Coverage Report

Created: 2026-09-02 20:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/hash_util.hpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
// This file is copied from
18
// https://github.com/apache/impala/blob/branch-2.9.0/be/src/util/hash-util.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <crc32c/crc32c.h>
24
#include <xxh3.h>
25
#include <xxhash.h>
26
#include <zlib.h>
27
28
#include <bit>
29
#include <functional>
30
31
#include "common/compiler_util.h" // IWYU pragma: keep
32
#include "exec/common/endian.h"
33
#include "util/cpu_info.h"
34
#include "util/hash/city.h"
35
#include "util/hash/murmur_hash3.h"
36
#include "util/sse_util.hpp"
37
38
namespace doris {
39
namespace detail {
40
// Slicing-by-4 table: t[0] is the standard byte-at-a-time table,
41
// t[1..3] are extended tables for parallel 4-byte processing.
42
struct CRC32SliceBy4Table {
43
    uint32_t t[4][256] {};
44
0
    constexpr CRC32SliceBy4Table() {
45
0
        // t[0]: standard CRC32 lookup table
46
0
        for (uint32_t i = 0; i < 256; i++) {
47
0
            uint32_t c = i;
48
0
            for (int j = 0; j < 8; j++) {
49
0
                c = (c & 1) ? ((c >> 1) ^ 0xEDB88320U) : (c >> 1);
50
0
            }
51
0
            t[0][i] = c;
52
0
        }
53
0
        // t[1..3]: each entry is one additional CRC byte-step applied to t[k-1]
54
0
        for (uint32_t i = 0; i < 256; i++) {
55
0
            uint32_t c = t[0][i];
56
0
            for (int k = 1; k < 4; k++) {
57
0
                c = t[0][c & 0xFF] ^ (c >> 8);
58
0
                t[k][i] = c;
59
0
            }
60
0
        }
61
0
    }
62
};
63
} // namespace detail
64
65
// Utility class to compute hash values.
66
class HashUtil {
67
private:
68
    static inline constexpr detail::CRC32SliceBy4Table CRC32_TABLE {};
69
70
public:
71
738k
    static uint32_t zlib_crc_hash(const void* data, uint32_t bytes, uint32_t hash) {
72
738k
        return (uint32_t)crc32(hash, (const unsigned char*)data, bytes);
73
738k
    }
74
75
    // Inline CRC32 (zlib-compatible, standard CRC32 polynomial) for fixed-size types.
76
    // Uses Slicing-by-4 technique for 4/8-byte types: processes 4 bytes at a time using
77
    // 4 precomputed lookup tables, reducing serial table lookups from 4 to 1 per 4-byte chunk.
78
    // Polynomial: 0xEDB88320 (reflected form of 0x04C11DB7).
79
    // Endian note: CRC32 reflected algorithm processes bytes in address order (byte[0] first).
80
    // Slicing-by-4 requires byte[0] at LSB of the loaded uint32_t, which is little-endian layout.
81
    // LittleEndian::Load32 provides this on ALL platforms: noop on LE, bswap on BE.
82
    template <typename T>
83
4.23M
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
4.23M
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
4.23M
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
4.23M
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
202
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
207
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
207
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
207
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
4.22M
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
4.22M
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
4.22M
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
4.22M
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
4.22M
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
1.34k
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
1.34k
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
1.34k
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
1.34k
            word = LittleEndian::Load32(p + 4) ^ crc;
109
1.34k
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
1.34k
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
2.88k
        } else {
112
            // Fallback to zlib for larger/unusual types
113
2.88k
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
2.88k
        }
115
0
        return crc ^ 0xFFFFFFFFU;
116
4.23M
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIiEEjRKT_j
Line
Count
Source
83
4.22M
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
4.22M
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
4.22M
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
4.22M
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
4.22M
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
4.22M
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
4.22M
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
4.22M
        return crc ^ 0xFFFFFFFFU;
116
4.22M
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIhEEjRKT_j
Line
Count
Source
83
41
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
41
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
41
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
41
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
41
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
41
        return crc ^ 0xFFFFFFFFU;
116
41
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIsEEjRKT_j
Line
Count
Source
83
186
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
186
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
186
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
186
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
186
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
186
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
186
        return crc ^ 0xFFFFFFFFU;
116
186
    }
_ZN5doris8HashUtil16zlib_crc32_fixedItEEjRKT_j
Line
Count
Source
83
21
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
21
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
21
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
21
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
21
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
21
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
21
        return crc ^ 0xFFFFFFFFU;
116
21
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIjEEjRKT_j
Line
Count
Source
83
51
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
51
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
51
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
51
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
51
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
51
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
51
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
51
        return crc ^ 0xFFFFFFFFU;
116
51
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIlEEjRKT_j
Line
Count
Source
83
206
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
206
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
206
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
206
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
206
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
206
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
206
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
206
            word = LittleEndian::Load32(p + 4) ^ crc;
109
206
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
206
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
206
        return crc ^ 0xFFFFFFFFU;
116
206
    }
_ZN5doris8HashUtil16zlib_crc32_fixedImEEjRKT_j
Line
Count
Source
83
18
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
18
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
18
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
18
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
18
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
18
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
18
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
18
            word = LittleEndian::Load32(p + 4) ^ crc;
109
18
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
18
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
18
        return crc ^ 0xFFFFFFFFU;
116
18
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIfEEjRKT_j
Line
Count
Source
83
20
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
20
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
20
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
20
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
20
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
20
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
20
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
20
        return crc ^ 0xFFFFFFFFU;
116
20
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIdEEjRKT_j
Line
Count
Source
83
42
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
42
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
42
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
42
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
42
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
42
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
42
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
42
            word = LittleEndian::Load32(p + 4) ^ crc;
109
42
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
42
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
42
        return crc ^ 0xFFFFFFFFU;
116
42
    }
_ZN5doris8HashUtil16zlib_crc32_fixedInEEjRKT_j
Line
Count
Source
83
158
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
158
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
158
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
158
        } else {
112
            // Fallback to zlib for larger/unusual types
113
158
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
158
        }
115
0
        return crc ^ 0xFFFFFFFFU;
116
158
    }
_ZN5doris8HashUtil16zlib_crc32_fixedINS_7DecimalIiEEEEjRKT_j
Line
Count
Source
83
519
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
519
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
519
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
519
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
519
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
519
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
519
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
519
        return crc ^ 0xFFFFFFFFU;
116
519
    }
_ZN5doris8HashUtil16zlib_crc32_fixedINS_7DecimalIlEEEEjRKT_j
Line
Count
Source
83
966
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
966
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
966
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
966
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
966
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
966
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
966
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
966
            word = LittleEndian::Load32(p + 4) ^ crc;
109
966
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
966
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
966
        return crc ^ 0xFFFFFFFFU;
116
966
    }
_ZN5doris8HashUtil16zlib_crc32_fixedINS_12Decimal128V3EEEjRKT_j
Line
Count
Source
83
1.05k
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
1.05k
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
1.05k
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
1.05k
        } else {
112
            // Fallback to zlib for larger/unusual types
113
1.05k
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
1.05k
        }
115
0
        return crc ^ 0xFFFFFFFFU;
116
1.05k
    }
_ZN5doris8HashUtil16zlib_crc32_fixedINS_7DecimalIN4wide7integerILm256EiEEEEEEjRKT_j
Line
Count
Source
83
1.65k
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
1.65k
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
1.65k
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
1.65k
        } else {
112
            // Fallback to zlib for larger/unusual types
113
1.65k
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
1.65k
        }
115
0
        return crc ^ 0xFFFFFFFFU;
116
1.65k
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIaEEjRKT_j
Line
Count
Source
83
161
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
161
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
161
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
161
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
161
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
161
        return crc ^ 0xFFFFFFFFU;
116
161
    }
_ZN5doris8HashUtil16zlib_crc32_fixedIoEEjRKT_j
Line
Count
Source
83
12
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
12
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
12
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
12
        } else {
112
            // Fallback to zlib for larger/unusual types
113
12
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
12
        }
115
0
        return crc ^ 0xFFFFFFFFU;
116
12
    }
_ZN5doris8HashUtil16zlib_crc32_fixedINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEjRKT_j
Line
Count
Source
83
37
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
37
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
37
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
37
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
37
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
37
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
37
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
            word = LittleEndian::Load32(p + 4) ^ crc;
109
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
37
        return crc ^ 0xFFFFFFFFU;
116
37
    }
_ZN5doris8HashUtil16zlib_crc32_fixedINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEjRKT_j
Line
Count
Source
83
111
    static uint32_t zlib_crc32_fixed(const T& value, uint32_t hash) {
84
111
        const auto* p = reinterpret_cast<const uint8_t*>(&value);
85
        // zlib convention: pre/post XOR with 0xFFFFFFFF
86
111
        uint32_t crc = hash ^ 0xFFFFFFFFU;
87
88
        if constexpr (sizeof(T) == 1) {
89
            // 1 byte: single table lookup
90
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
91
        } else if constexpr (sizeof(T) == 2) {
92
            // 2 bytes: two sequential table lookups (slicing doesn't help below 4 bytes)
93
            crc = CRC32_TABLE.t[0][(crc ^ p[0]) & 0xFF] ^ (crc >> 8);
94
            crc = CRC32_TABLE.t[0][(crc ^ p[1]) & 0xFF] ^ (crc >> 8);
95
        } else if constexpr (sizeof(T) == 4) {
96
            // 4 bytes: one Slicing-by-4 step — 4 independent lookups in parallel
97
            // LittleEndian::Load32 handles unaligned load + byte-swap on big-endian,
98
            // ensuring byte[0] is always at LSB for correct CRC byte processing order.
99
            uint32_t word = LittleEndian::Load32(p) ^ crc;
100
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
101
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
102
111
        } else if constexpr (sizeof(T) == 8) {
103
            // 8 bytes: two Slicing-by-4 steps
104
111
            uint32_t word = LittleEndian::Load32(p) ^ crc;
105
111
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
106
111
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
107
108
111
            word = LittleEndian::Load32(p + 4) ^ crc;
109
111
            crc = CRC32_TABLE.t[3][(word)&0xFF] ^ CRC32_TABLE.t[2][(word >> 8) & 0xFF] ^
110
111
                  CRC32_TABLE.t[1][(word >> 16) & 0xFF] ^ CRC32_TABLE.t[0][(word >> 24) & 0xFF];
111
        } else {
112
            // Fallback to zlib for larger/unusual types
113
            return (uint32_t)crc32(hash, (const unsigned char*)&value, sizeof(T));
114
        }
115
111
        return crc ^ 0xFFFFFFFFU;
116
111
    }
Unexecuted instantiation: _ZN5doris8HashUtil16zlib_crc32_fixedINS_16TimestampTzValueEEEjRKT_j
117
118
1.08M
    static uint32_t zlib_crc_hash_null(uint32_t hash) {
119
        // null is treat as 0 when hash
120
1.08M
        static const int INT_VALUE = 0;
121
1.08M
        return zlib_crc32_fixed(INT_VALUE, hash);
122
1.08M
    }
123
124
    template <typename T>
125
17.5M
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
17.5M
        if constexpr (sizeof(T) == 1) {
127
5.90k
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
5.90k
        } else if constexpr (sizeof(T) == 2) {
129
4.93k
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
17.4M
        } else if constexpr (sizeof(T) == 4) {
131
17.4M
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
17.4M
        } else if constexpr (sizeof(T) == 8) {
133
26.2k
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
26.2k
        } else {
135
19.6k
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
19.6k
        }
137
17.5M
    }
_ZN5doris8HashUtil12crc32c_fixedIiEEjRKT_j
Line
Count
Source
125
17.4M
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
17.4M
        } else if constexpr (sizeof(T) == 4) {
131
17.4M
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
17.4M
    }
_ZN5doris8HashUtil12crc32c_fixedINS_7DecimalIiEEEEjRKT_j
Line
Count
Source
125
2.16k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
2.16k
        } else if constexpr (sizeof(T) == 4) {
131
2.16k
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
2.16k
    }
_ZN5doris8HashUtil12crc32c_fixedINS_7DecimalIlEEEEjRKT_j
Line
Count
Source
125
3.49k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
3.49k
        } else if constexpr (sizeof(T) == 8) {
133
3.49k
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
3.49k
    }
Unexecuted instantiation: _ZN5doris8HashUtil12crc32c_fixedINS_14DecimalV2ValueEEEjRKT_j
_ZN5doris8HashUtil12crc32c_fixedINS_12Decimal128V3EEEjRKT_j
Line
Count
Source
125
3.91k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
3.91k
        } else {
135
3.91k
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
3.91k
        }
137
3.91k
    }
_ZN5doris8HashUtil12crc32c_fixedINS_7DecimalIN4wide7integerILm256EiEEEEEEjRKT_j
Line
Count
Source
125
7.44k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
7.44k
        } else {
135
7.44k
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
7.44k
        }
137
7.44k
    }
_ZN5doris8HashUtil12crc32c_fixedIhEEjRKT_j
Line
Count
Source
125
804
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
804
        if constexpr (sizeof(T) == 1) {
127
804
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
804
    }
_ZN5doris8HashUtil12crc32c_fixedIaEEjRKT_j
Line
Count
Source
125
5.09k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
5.09k
        if constexpr (sizeof(T) == 1) {
127
5.09k
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
5.09k
    }
_ZN5doris8HashUtil12crc32c_fixedIsEEjRKT_j
Line
Count
Source
125
4.93k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
4.93k
        } else if constexpr (sizeof(T) == 2) {
129
4.93k
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
4.93k
    }
_ZN5doris8HashUtil12crc32c_fixedIlEEjRKT_j
Line
Count
Source
125
6.90k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
6.90k
        } else if constexpr (sizeof(T) == 8) {
133
6.90k
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
6.90k
    }
_ZN5doris8HashUtil12crc32c_fixedInEEjRKT_j
Line
Count
Source
125
3.77k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
3.77k
        } else {
135
3.77k
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
3.77k
        }
137
3.77k
    }
_ZN5doris8HashUtil12crc32c_fixedIfEEjRKT_j
Line
Count
Source
125
4.32k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
4.32k
        } else if constexpr (sizeof(T) == 4) {
131
4.32k
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
4.32k
    }
_ZN5doris8HashUtil12crc32c_fixedIdEEjRKT_j
Line
Count
Source
125
4.85k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
4.85k
        } else if constexpr (sizeof(T) == 8) {
133
4.85k
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
4.85k
    }
_ZN5doris8HashUtil12crc32c_fixedIjEEjRKT_j
Line
Count
Source
125
6.79k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
6.79k
        } else if constexpr (sizeof(T) == 4) {
131
6.79k
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
6.79k
    }
_ZN5doris8HashUtil12crc32c_fixedIoEEjRKT_j
Line
Count
Source
125
4.53k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
4.53k
        } else {
135
4.53k
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
4.53k
        }
137
4.53k
    }
_ZN5doris8HashUtil12crc32c_fixedINS_11DateV2ValueINS_15DateV2ValueTypeEEEEEjRKT_j
Line
Count
Source
125
1.57k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
1.57k
        } else if constexpr (sizeof(T) == 4) {
131
1.57k
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
        } else if constexpr (sizeof(T) == 8) {
133
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
1.57k
    }
_ZN5doris8HashUtil12crc32c_fixedINS_11DateV2ValueINS_19DateTimeV2ValueTypeEEEEEjRKT_j
Line
Count
Source
125
11.0k
    static uint32_t crc32c_fixed(const T& value, uint32_t hash) {
126
        if constexpr (sizeof(T) == 1) {
127
            return _mm_crc32_u8(hash, *reinterpret_cast<const uint8_t*>(&value));
128
        } else if constexpr (sizeof(T) == 2) {
129
            return _mm_crc32_u16(hash, *reinterpret_cast<const uint16_t*>(&value));
130
        } else if constexpr (sizeof(T) == 4) {
131
            return _mm_crc32_u32(hash, *reinterpret_cast<const uint32_t*>(&value));
132
11.0k
        } else if constexpr (sizeof(T) == 8) {
133
11.0k
            return (uint32_t)_mm_crc32_u64(hash, *reinterpret_cast<const uint64_t*>(&value));
134
        } else {
135
            return crc32c_extend(hash, (const uint8_t*)&value, sizeof(T));
136
        }
137
11.0k
    }
Unexecuted instantiation: _ZN5doris8HashUtil12crc32c_fixedINS_16TimestampTzValueEEEjRKT_j
Unexecuted instantiation: _ZN5doris8HashUtil12crc32c_fixedImEEjRKT_j
138
139
464
    static uint32_t crc32c_null(uint32_t hash) {
140
        // null is treat as 0 when hash
141
464
        static const int INT_VALUE = 0;
142
464
        return crc32c_fixed(INT_VALUE, hash);
143
464
    }
144
145
    // Compute the Crc32 hash for data using SSE4 instructions.  The input hash parameter is
146
    // the current hash/seed value.
147
    // This should only be called if SSE is supported.
148
    // This is ~4x faster than Fnv/Boost Hash.
149
    // NOTE: DO NOT use this method for checksum! This does not generate the standard CRC32 checksum!
150
    //       For checksum, use CRC-32C algorithm from crc32c.h
151
    // NOTE: Any changes made to this function need to be reflected in Codegen::GetHashFn.
152
    // TODO: crc32 hashes with different seeds do not result in different hash functions.
153
    // The resulting hashes are correlated.
154
    // ATTN: prefer do not use this function anymore, use crc32c::Extend instead
155
    // This function is retained because it is not certain whether there are compatibility issues with historical data.
156
0
    static uint32_t crc_hash(const void* data, uint32_t bytes, uint32_t hash) {
157
0
        if (!CpuInfo::is_supported(CpuInfo::SSE4_2)) {
158
0
            return zlib_crc_hash(data, bytes, hash);
159
0
        }
160
0
        uint32_t words = bytes / sizeof(uint32_t);
161
0
        bytes = bytes % sizeof(uint32_t);
162
163
0
        const uint32_t* p = reinterpret_cast<const uint32_t*>(data);
164
165
0
        while (words--) {
166
0
            hash = _mm_crc32_u32(hash, *p);
167
0
            ++p;
168
0
        }
169
170
0
        const uint8_t* s = reinterpret_cast<const uint8_t*>(p);
171
172
0
        while (bytes--) {
173
0
            hash = _mm_crc32_u8(hash, *s);
174
0
            ++s;
175
0
        }
176
177
        // The lower half of the CRC hash has has poor uniformity, so swap the halves
178
        // for anyone who only uses the first several bits of the hash.
179
0
        hash = (hash << 16) | (hash >> 16);
180
0
        return hash;
181
0
    }
182
183
20
    static uint64_t crc_hash64(const void* data, uint32_t bytes, uint64_t hash) {
184
20
        uint32_t words = bytes / sizeof(uint32_t);
185
20
        bytes = bytes % sizeof(uint32_t);
186
187
20
        uint32_t h1 = hash >> 32;
188
20
        uint32_t h2 = (hash << 32) >> 32;
189
190
20
        const uint32_t* p = reinterpret_cast<const uint32_t*>(data);
191
28
        while (words--) {
192
8
            (words & 1) ? (h1 = _mm_crc32_u32(h1, *p)) : (h2 = _mm_crc32_u32(h2, *p));
193
8
            ++p;
194
8
        }
195
196
20
        const uint8_t* s = reinterpret_cast<const uint8_t*>(p);
197
36
        while (bytes--) {
198
16
            (bytes & 1) ? (h1 = _mm_crc32_u8(h1, *s)) : (h2 = _mm_crc32_u8(h2, *s));
199
16
            ++s;
200
16
        }
201
20
        union {
202
20
            uint64_t u64;
203
20
            uint32_t u32[2];
204
20
        } converter;
205
20
        converter.u64 = hash;
206
207
20
        h1 = (h1 << 16) | (h1 >> 16);
208
20
        h2 = (h2 << 16) | (h2 >> 16);
209
20
        converter.u32[0] = h1;
210
20
        converter.u32[1] = h2;
211
212
20
        return converter.u64;
213
20
    }
214
215
    // refer to https://github.com/apache/commons-codec/blob/master/src/main/java/org/apache/commons/codec/digest/MurmurHash3.java
216
    static const uint32_t MURMUR3_32_SEED = 104729;
217
218
    // modify from https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
219
20
    static uint32_t murmur_hash3_32(const void* key, int64_t len, uint32_t seed) {
220
20
        uint32_t out = 0;
221
20
        murmur_hash3_x86_32(key, len, seed, &out);
222
20
        return out;
223
20
    }
224
225
    template <bool is_mmh64_v2>
226
15
    static uint64_t murmur_hash3_64(const void* key, int64_t len, uint64_t seed) {
227
15
        uint64_t out = 0;
228
15
        if constexpr (is_mmh64_v2) {
229
3
            murmur_hash3_x64_64_shared(key, len, seed, &out);
230
12
        } else {
231
12
            murmur_hash3_x64_64(key, len, seed, &out);
232
12
        }
233
15
        return out;
234
15
    }
_ZN5doris8HashUtil15murmur_hash3_64ILb0EEEmPKvlm
Line
Count
Source
226
12
    static uint64_t murmur_hash3_64(const void* key, int64_t len, uint64_t seed) {
227
12
        uint64_t out = 0;
228
        if constexpr (is_mmh64_v2) {
229
            murmur_hash3_x64_64_shared(key, len, seed, &out);
230
12
        } else {
231
12
            murmur_hash3_x64_64(key, len, seed, &out);
232
12
        }
233
12
        return out;
234
12
    }
_ZN5doris8HashUtil15murmur_hash3_64ILb1EEEmPKvlm
Line
Count
Source
226
3
    static uint64_t murmur_hash3_64(const void* key, int64_t len, uint64_t seed) {
227
3
        uint64_t out = 0;
228
3
        if constexpr (is_mmh64_v2) {
229
3
            murmur_hash3_x64_64_shared(key, len, seed, &out);
230
        } else {
231
            murmur_hash3_x64_64(key, len, seed, &out);
232
        }
233
3
        return out;
234
3
    }
235
236
    static const int MURMUR_R = 47;
237
238
    // Murmur2 hash implementation returning 64-bit hashes.
239
0
    static uint64_t murmur_hash2_64(const void* input, int len, uint64_t seed) {
240
0
        uint64_t h = seed ^ (len * MURMUR_PRIME);
241
0
242
0
        const uint64_t* data = reinterpret_cast<const uint64_t*>(input);
243
0
        const uint64_t* end = data + (len / sizeof(uint64_t));
244
0
245
0
        while (data != end) {
246
0
            uint64_t k = *data++;
247
0
            k *= MURMUR_PRIME;
248
0
            k ^= k >> MURMUR_R;
249
0
            k *= MURMUR_PRIME;
250
0
            h ^= k;
251
0
            h *= MURMUR_PRIME;
252
0
        }
253
0
254
0
        const uint8_t* data2 = reinterpret_cast<const uint8_t*>(data);
255
0
        switch (len & 7) {
256
0
        case 7:
257
0
            h ^= uint64_t(data2[6]) << 48;
258
0
            [[fallthrough]];
259
0
        case 6:
260
0
            h ^= uint64_t(data2[5]) << 40;
261
0
            [[fallthrough]];
262
0
        case 5:
263
0
            h ^= uint64_t(data2[4]) << 32;
264
0
            [[fallthrough]];
265
0
        case 4:
266
0
            h ^= uint64_t(data2[3]) << 24;
267
0
            [[fallthrough]];
268
0
        case 3:
269
0
            h ^= uint64_t(data2[2]) << 16;
270
0
            [[fallthrough]];
271
0
        case 2:
272
0
            h ^= uint64_t(data2[1]) << 8;
273
0
            [[fallthrough]];
274
0
        case 1:
275
0
            h ^= uint64_t(data2[0]);
276
0
            h *= MURMUR_PRIME;
277
0
        }
278
0
279
0
        h ^= h >> MURMUR_R;
280
0
        h *= MURMUR_PRIME;
281
0
        h ^= h >> MURMUR_R;
282
0
        return h;
283
0
    }
284
285
    // default values recommended by http://isthe.com/chongo/tech/comp/fnv/
286
    static const uint32_t FNV_PRIME = 0x01000193; //   16777619
287
    static const uint32_t FNV_SEED = 0x811C9DC5;  // 2166136261
288
    static const uint64_t FNV64_PRIME = 1099511628211UL;
289
    static const uint64_t FNV64_SEED = 14695981039346656037UL;
290
    static const uint64_t MURMUR_PRIME = 0xc6a4a7935bd1e995ULL;
291
    static const uint32_t MURMUR_SEED = 0xadc83b19ULL;
292
    // Implementation of the Fowler–Noll–Vo hash function.  This is not as performant
293
    // as boost's hash on int types (2x slower) but has bit entropy.
294
    // For ints, boost just returns the value of the int which can be pathological.
295
    // For example, if the data is <1000, 2000, 3000, 4000, ..> and then the mod of 1000
296
    // is taken on the hash, all values will collide to the same bucket.
297
    // For string values, Fnv is slightly faster than boost.
298
197k
    static uint32_t fnv_hash(const void* data, uint32_t bytes, uint32_t hash) {
299
197k
        const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
300
301
802k
        while (bytes--) {
302
604k
            hash = (*ptr ^ hash) * FNV_PRIME;
303
604k
            ++ptr;
304
604k
        }
305
306
197k
        return hash;
307
197k
    }
308
309
0
    static uint64_t fnv_hash64(const void* data, uint32_t bytes, uint64_t hash) {
310
0
        const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
311
0
312
0
        while (bytes--) {
313
0
            hash = (*ptr ^ hash) * FNV64_PRIME;
314
0
            ++ptr;
315
0
        }
316
0
317
0
        return hash;
318
0
    }
319
320
    // Our hash function is MurmurHash2, 64 bit version.
321
    // It was modified in order to provide the same result in
322
    // big and little endian archs (endian neutral).
323
67.8k
    static uint64_t murmur_hash64A(const void* key, int64_t len, unsigned int seed) {
324
67.8k
        const uint64_t m = MURMUR_PRIME;
325
67.8k
        const int r = 47;
326
67.8k
        uint64_t h = seed ^ (len * m);
327
67.8k
        const uint8_t* data = (const uint8_t*)key;
328
67.8k
        const uint8_t* end = data + (len - (len & 7));
329
330
135k
        while (data != end) {
331
67.8k
            uint64_t k;
332
            if constexpr (std::endian::native == std::endian::big) {
333
                k = (uint64_t)data[0];
334
                k |= (uint64_t)data[1] << 8;
335
                k |= (uint64_t)data[2] << 16;
336
                k |= (uint64_t)data[3] << 24;
337
                k |= (uint64_t)data[4] << 32;
338
                k |= (uint64_t)data[5] << 40;
339
                k |= (uint64_t)data[6] << 48;
340
                k |= (uint64_t)data[7] << 56;
341
67.8k
            } else if constexpr (std::endian::native == std::endian::little) {
342
67.8k
                memcpy(&k, data, sizeof(k));
343
            } else {
344
                static_assert(std::endian::native == std::endian::big ||
345
                                      std::endian::native == std::endian::little,
346
                              "Unsupported endianness");
347
            }
348
349
67.8k
            k *= m;
350
67.8k
            k ^= k >> r;
351
67.8k
            k *= m;
352
67.8k
            h ^= k;
353
67.8k
            h *= m;
354
67.8k
            data += 8;
355
67.8k
        }
356
357
67.8k
        switch (len & 7) {
358
0
        case 7:
359
0
            h ^= (uint64_t)data[6] << 48;
360
0
            [[fallthrough]];
361
0
        case 6:
362
0
            h ^= (uint64_t)data[5] << 40;
363
0
            [[fallthrough]];
364
0
        case 5:
365
0
            h ^= (uint64_t)data[4] << 32;
366
0
            [[fallthrough]];
367
3
        case 4:
368
3
            h ^= (uint64_t)data[3] << 24;
369
3
            [[fallthrough]];
370
3
        case 3:
371
3
            h ^= (uint64_t)data[2] << 16;
372
3
            [[fallthrough]];
373
3
        case 2:
374
3
            h ^= (uint64_t)data[1] << 8;
375
3
            [[fallthrough]];
376
6
        case 1:
377
6
            h ^= (uint64_t)data[0];
378
6
            h *= m;
379
67.8k
        }
380
381
67.8k
        h ^= h >> r;
382
67.8k
        h *= m;
383
67.8k
        h ^= h >> r;
384
67.8k
        return h;
385
67.8k
    }
386
387
    // Computes the hash value for data.  Will call either CrcHash or FnvHash
388
    // depending on hardware capabilities.
389
    // Seed values for different steps of the query execution should use different seeds
390
    // to prevent accidental key collisions. (See IMPALA-219 for more details).
391
197k
    static uint32_t hash(const void* data, uint32_t bytes, uint32_t seed) {
392
197k
#ifdef __SSE4_2__
393
394
197k
        if (LIKELY(CpuInfo::is_supported(CpuInfo::SSE4_2))) {
395
0
            return crc_hash(data, bytes, seed);
396
197k
        } else {
397
197k
            return fnv_hash(data, bytes, seed);
398
197k
        }
399
400
#else
401
        return fnv_hash(data, bytes, seed);
402
#endif
403
197k
    }
404
405
61.8k
    static uint64_t hash64(const void* data, uint64_t bytes, uint64_t seed) {
406
#ifdef _SSE4_2_
407
        if (LIKELY(CpuInfo::is_supported(CpuInfo::SSE4_2))) {
408
            return crc_hash64(data, bytes, seed);
409
410
        } else {
411
            uint64_t hash = 0;
412
            murmur_hash3_x64_64(data, bytes, seed, &hash);
413
            return hash;
414
        }
415
#else
416
61.8k
        uint64_t hash = 0;
417
61.8k
        murmur_hash3_x64_64(data, bytes, seed, &hash);
418
61.8k
        return hash;
419
61.8k
#endif
420
61.8k
    }
421
    // hash_combine is the same with boost hash_combine,
422
    // except replace boost::hash with std::hash
423
    template <class T>
424
1.87k
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
1.87k
        std::hash<T> hasher;
426
1.87k
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
1.87k
    }
_ZN5doris8HashUtil12hash_combineINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRmRKT_
Line
Count
Source
424
1.26k
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
1.26k
        std::hash<T> hasher;
426
1.26k
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
1.26k
    }
_ZN5doris8HashUtil12hash_combineIlEEvRmRKT_
Line
Count
Source
424
91
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
91
        std::hash<T> hasher;
426
91
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
91
    }
_ZN5doris8HashUtil12hash_combineImEEvRmRKT_
Line
Count
Source
424
211
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
211
        std::hash<T> hasher;
426
211
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
211
    }
_ZN5doris8HashUtil12hash_combineIfEEvRmRKT_
Line
Count
Source
424
153
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
153
        std::hash<T> hasher;
426
153
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
153
    }
_ZN5doris8HashUtil12hash_combineIiEEvRmRKT_
Line
Count
Source
424
74
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
74
        std::hash<T> hasher;
426
74
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
74
    }
_ZN5doris8HashUtil12hash_combineIbEEvRmRKT_
Line
Count
Source
424
85
    static inline void hash_combine(std::size_t& seed, const T& v) {
425
85
        std::hash<T> hasher;
426
85
        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
427
85
    }
428
429
#if defined(__clang__)
430
#pragma clang diagnostic push
431
#pragma clang diagnostic ignored "-Wused-but-marked-unused"
432
#endif
433
    // xxHash function for a byte array.  For convenience, a 64-bit seed is also
434
    // hashed into the result.  The mapping may change from time to time.
435
24
    static xxh_u32 xxHash32WithSeed(const char* s, size_t len, xxh_u32 seed) {
436
24
        return XXH32(s, len, seed);
437
24
    }
438
439
    // same to the up function, just for null value
440
0
    static xxh_u32 xxHash32NullWithSeed(xxh_u32 seed) {
441
0
        static const int INT_VALUE = 0;
442
0
        return XXH32(reinterpret_cast<const char*>(&INT_VALUE), sizeof(int), seed);
443
0
    }
444
445
255k
    static xxh_u64 xxHash64WithSeed(const char* s, size_t len, xxh_u64 seed) {
446
255k
        return XXH3_64bits_withSeed(s, len, seed);
447
255k
    }
448
449
    // same to the up function, just for null value
450
1.08M
    static xxh_u64 xxHash64NullWithSeed(xxh_u64 seed) {
451
1.08M
        static const int INT_VALUE = 0;
452
1.08M
        return XXH3_64bits_withSeed(reinterpret_cast<const char*>(&INT_VALUE), sizeof(int), seed);
453
1.08M
    }
454
455
112
    static xxh_u64 xxhash64_compat_with_seed(const char* s, size_t len, xxh_u64 seed) {
456
112
        return XXH64(reinterpret_cast<const void*>(s), len, seed);
457
112
    }
458
459
0
    static xxh_u64 xxhash64_compat_null_with_seed(xxh_u64 seed) {
460
0
        static const int INT_VALUE = 0;
461
0
        return XXH64(reinterpret_cast<const void*>(&INT_VALUE), sizeof(int), seed);
462
0
    }
463
464
#if defined(__clang__)
465
#pragma clang diagnostic pop
466
#endif
467
};
468
469
} // namespace doris
470
471
namespace doris {
472
// Forward declarations only: a std::hash specialization can be DECLARED for
473
// an incomplete type, which keeps gen_cpp/Types_types.h out of this header.
474
// This header stays the earliest carrier of these specializations (it rides
475
// in through string_ref.h and storage/olap_common.h), so they are visible
476
// before any implicit instantiation. Bodies live in util/uid_util.cpp and
477
// util/network_util.cpp, where the types are complete.
478
class TUniqueId;
479
class TNetworkAddress;
480
} // namespace doris
481
482
template <>
483
struct std::hash<doris::TUniqueId> {
484
    size_t operator()(const doris::TUniqueId& id) const;
485
};
486
487
template <>
488
struct std::hash<doris::TNetworkAddress> {
489
    size_t operator()(const doris::TNetworkAddress& address) const;
490
};
491
492
template <>
493
struct std::hash<std::pair<doris::TUniqueId, int64_t>> {
494
    size_t operator()(const std::pair<doris::TUniqueId, int64_t>& pair) const;
495
};
496
497
template <class First, class Second>
498
struct std::hash<std::pair<First, Second>> {
499
31.2k
    size_t operator()(const pair<First, Second>& p) const {
500
31.2k
        size_t h1 = std::hash<First>()(p.first);
501
31.2k
        size_t h2 = std::hash<Second>()(p.second);
502
31.2k
        return doris::util_hash::HashLen16(h1, h2);
503
31.2k
    }
Unexecuted instantiation: _ZNKSt4hashISt4pairIlN5doris8RowsetIdEEEclERKS3_
Unexecuted instantiation: _ZNKSt4hashISt4pairIP13hdfs_internalS0_INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEElEEEclERKSA_
_ZNKSt4hashISt4pairINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEElEEclERKS7_
Line
Count
Source
499
48
    size_t operator()(const pair<First, Second>& p) const {
500
48
        size_t h1 = std::hash<First>()(p.first);
501
48
        size_t h2 = std::hash<Second>()(p.second);
502
48
        return doris::util_hash::HashLen16(h1, h2);
503
48
    }
_ZNKSt4hashISt4pairIllEEclERKS1_
Line
Count
Source
499
68
    size_t operator()(const pair<First, Second>& p) const {
500
68
        size_t h1 = std::hash<First>()(p.first);
501
68
        size_t h2 = std::hash<Second>()(p.second);
502
68
        return doris::util_hash::HashLen16(h1, h2);
503
68
    }
_ZNKSt4hashISt4pairIiN5doris10PathInDataEEEclERKS3_
Line
Count
Source
499
31.1k
    size_t operator()(const pair<First, Second>& p) const {
500
31.1k
        size_t h1 = std::hash<First>()(p.first);
501
31.1k
        size_t h2 = std::hash<Second>()(p.second);
502
31.1k
        return doris::util_hash::HashLen16(h1, h2);
503
31.1k
    }
Unexecuted instantiation: _ZNKSt4hashISt4pairIN5doris9TUniqueIdEiEEclERKS3_
504
};