Coverage Report

Created: 2026-10-27 17:29

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