Coverage Report

Created: 2025-06-19 04:27

/root/doris/be/src/util/bit_util.h
Line
Count
Source (jump to first uncovered line)
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/bit-util.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <type_traits>
24
25
#include "vec/core/wide_integer.h"
26
#ifndef __APPLE__
27
#include <endian.h>
28
#endif
29
30
#include "common/compiler_util.h" // IWYU pragma: keep
31
#include "gutil/endian.h"
32
#include "util/cpu_info.h"
33
#include "util/sse_util.hpp"
34
35
namespace doris {
36
37
// Utility class to do standard bit tricks
38
// TODO: is this in boost or something else like that?
39
class BitUtil {
40
public:
41
    // Returns the ceil of value/divisor
42
7
    static inline int64_t ceil(int64_t value, int64_t divisor) {
43
7
        return value / divisor + (value % divisor != 0);
44
7
    }
45
46
    // Returns 'value' rounded up to the nearest multiple of 'factor'
47
36
    static inline int64_t round_up(int64_t value, int64_t factor) {
48
36
        return (value + (factor - 1)) / factor * factor;
49
36
    }
50
51
    // Returns the smallest power of two that contains v. Taken from
52
    // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
53
    // TODO: Pick a better name, as it is not clear what happens when the input is
54
    // already a power of two.
55
108
    static inline int64_t next_power_of_two(int64_t v) {
56
108
        --v;
57
108
        v |= v >> 1;
58
108
        v |= v >> 2;
59
108
        v |= v >> 4;
60
108
        v |= v >> 8;
61
108
        v |= v >> 16;
62
108
        v |= v >> 32;
63
108
        ++v;
64
108
        return v;
65
108
    }
66
67
    // Non hw accelerated pop count.
68
    // TODO: we don't use this in any perf sensitive code paths currently.  There
69
    // might be a much faster way to implement this.
70
4
    static inline int popcount_no_hw(uint64_t x) {
71
4
        int count = 0;
72
73
22
        for (; x != 0; ++count) {
74
18
            x &= x - 1;
75
18
        }
76
77
4
        return count;
78
4
    }
79
80
    // Returns the number of set bits in x
81
4
    static inline int popcount(uint64_t x) {
82
4
        if (LIKELY(CpuInfo::is_supported(CpuInfo::POPCNT))) {
83
4
            return __builtin_popcountl(x);
84
4
        } else {
85
0
            return popcount_no_hw(x);
86
0
        }
87
4
    }
88
89
    // Returns the 'num_bits' least-significant bits of 'v'.
90
0
    static inline uint64_t trailing_bits(uint64_t v, int num_bits) {
91
0
        if (UNLIKELY(num_bits == 0)) {
92
0
            return 0;
93
0
        }
94
0
95
0
        if (UNLIKELY(num_bits >= 64)) {
96
0
            return v;
97
0
        }
98
0
99
0
        int n = 64 - num_bits;
100
0
        return (v << n) >> n;
101
0
    }
102
103
    template <typename T>
104
1
    static std::string IntToByteBuffer(T input) {
105
1
        std::string buffer;
106
1
        T value = input;
107
2
        for (int i = 0; i < sizeof(value); ++i) {
108
            // Applies a mask for a byte range on the input.
109
2
            signed char value_to_save = value & 0XFF;
110
2
            buffer.push_back(value_to_save);
111
            // Remove the just processed part from the input so that we can exit early if there
112
            // is nothing left to process.
113
2
            value >>= 8;
114
2
            if (value == 0 && value_to_save >= 0) {
115
1
                break;
116
1
            }
117
1
            if (value == -1 && value_to_save < 0) {
118
0
                break;
119
0
            }
120
1
        }
121
1
        std::reverse(buffer.begin(), buffer.end());
122
1
        return buffer;
123
1
    }
_ZN5doris7BitUtil15IntToByteBufferIiEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_
Line
Count
Source
104
1
    static std::string IntToByteBuffer(T input) {
105
1
        std::string buffer;
106
1
        T value = input;
107
2
        for (int i = 0; i < sizeof(value); ++i) {
108
            // Applies a mask for a byte range on the input.
109
2
            signed char value_to_save = value & 0XFF;
110
2
            buffer.push_back(value_to_save);
111
            // Remove the just processed part from the input so that we can exit early if there
112
            // is nothing left to process.
113
2
            value >>= 8;
114
2
            if (value == 0 && value_to_save >= 0) {
115
1
                break;
116
1
            }
117
1
            if (value == -1 && value_to_save < 0) {
118
0
                break;
119
0
            }
120
1
        }
121
1
        std::reverse(buffer.begin(), buffer.end());
122
1
        return buffer;
123
1
    }
Unexecuted instantiation: _ZN5doris7BitUtil15IntToByteBufferInEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_
Unexecuted instantiation: _ZN5doris7BitUtil15IntToByteBufferIlEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_
Unexecuted instantiation: _ZN5doris7BitUtil15IntToByteBufferIN4wide7integerILm256EiEEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_
124
125
    // Returns ceil(log2(x)).
126
    // TODO: this could be faster if we use __builtin_clz.  Fix this if this ever shows up
127
    // in a hot path.
128
117
    static inline int log2(uint64_t x) {
129
117
        DCHECK_GT(x, 0);
130
131
117
        if (x == 1) {
132
0
            return 0;
133
0
        }
134
135
        // Compute result = ceil(log2(x))
136
        //                = floor(log2(x - 1)) + 1, for x > 1
137
        // by finding the position of the most significant bit (1-indexed) of x - 1
138
        // (floor(log2(n)) = MSB(n) (0-indexed))
139
117
        --x;
140
117
        int result = 1;
141
142
124
        while (x >>= 1) {
143
7
            ++result;
144
7
        }
145
146
117
        return result;
147
117
    }
148
149
    // Swaps the byte order (i.e. endianess)
150
0
    static inline int64_t byte_swap(int64_t value) { return __builtin_bswap64(value); }
151
0
    static inline uint64_t byte_swap(uint64_t value) {
152
0
        return static_cast<uint64_t>(__builtin_bswap64(value));
153
0
    }
154
0
    static inline int32_t byte_swap(int32_t value) { return __builtin_bswap32(value); }
155
0
    static inline uint32_t byte_swap(uint32_t value) {
156
0
        return static_cast<uint32_t>(__builtin_bswap32(value));
157
0
    }
158
0
    static inline int16_t byte_swap(int16_t value) {
159
0
        return (((value >> 8) & 0xff) | ((value & 0xff) << 8));
160
0
    }
161
0
    static inline uint16_t byte_swap(uint16_t value) {
162
0
        return static_cast<uint16_t>(byte_swap(static_cast<int16_t>(value)));
163
0
    }
164
165
    // Write the swapped bytes into dst. len must be 1, 2, 4 or 8.
166
0
    static inline void byte_swap(void* dst, void* src, int len) {
167
0
        switch (len) {
168
0
        case 1:
169
0
            *reinterpret_cast<int8_t*>(dst) = *reinterpret_cast<int8_t*>(src);
170
0
            break;
171
0
172
0
        case 2:
173
0
            *reinterpret_cast<int16_t*>(dst) = byte_swap(*reinterpret_cast<int16_t*>(src));
174
0
            break;
175
0
176
0
        case 4:
177
0
            *reinterpret_cast<int32_t*>(dst) = byte_swap(*reinterpret_cast<int32_t*>(src));
178
0
            break;
179
0
180
0
        case 8:
181
0
            *reinterpret_cast<int64_t*>(dst) = byte_swap(*reinterpret_cast<int64_t*>(src));
182
0
            break;
183
0
184
0
        default:
185
0
            DCHECK(false);
186
0
        }
187
0
    }
188
189
    // Returns the rounded up to 64 multiple. Used for conversions of bits to i64.
190
0
    static inline uint32_t round_up_numi64(uint32_t bits) { return (bits + 63) >> 6; }
191
192
    // Returns the rounded up to 32 multiple. Used for conversions of bits to i32.
193
0
    constexpr static inline uint32_t round_up_numi32(uint32_t bits) { return (bits + 31) >> 5; }
194
195
#if __BYTE_ORDER == __LITTLE_ENDIAN
196
    // Converts to big endian format (if not already in big endian).
197
0
    static inline int64_t big_endian(int64_t value) { return byte_swap(value); }
198
0
    static inline uint64_t big_endian(uint64_t value) { return byte_swap(value); }
199
0
    static inline int32_t big_endian(int32_t value) { return byte_swap(value); }
200
0
    static inline uint32_t big_endian(uint32_t value) { return byte_swap(value); }
201
0
    static inline int16_t big_endian(int16_t value) { return byte_swap(value); }
202
0
    static inline uint16_t big_endian(uint16_t value) { return byte_swap(value); }
203
#else
204
    static inline int64_t big_endian(int64_t val) { return val; }
205
    static inline uint64_t big_endian(uint64_t val) { return val; }
206
    static inline int32_t big_endian(int32_t val) { return val; }
207
    static inline uint32_t big_endian(uint32_t val) { return val; }
208
    static inline int16_t big_endian(int16_t val) { return val; }
209
    static inline uint16_t big_endian(uint16_t val) { return val; }
210
#endif
211
212
    template <typename T>
213
5
    static T big_endian_to_host(T value) {
214
5
        if constexpr (std::is_same_v<T, wide::Int256>) {
215
5
            return BigEndian::ToHost256(value);
216
5
        } else if constexpr (std::is_same_v<T, wide::UInt256>) {
217
4
            return BigEndian::ToHost256(value);
218
4
        } else if constexpr (std::is_same_v<T, __int128>) {
219
4
            return BigEndian::ToHost128(value);
220
4
        } else if constexpr (std::is_same_v<T, unsigned __int128>) {
221
3
            return BigEndian::ToHost128(value);
222
3
        } else if constexpr (std::is_same_v<T, int64_t>) {
223
3
            return BigEndian::ToHost64(value);
224
3
        } else if constexpr (std::is_same_v<T, uint64_t>) {
225
2
            return BigEndian::ToHost64(value);
226
2
        } else if constexpr (std::is_same_v<T, int32_t>) {
227
2
            return BigEndian::ToHost32(value);
228
2
        } else if constexpr (std::is_same_v<T, uint32_t>) {
229
1
            return BigEndian::ToHost32(value);
230
1
        } else if constexpr (std::is_same_v<T, int16_t>) {
231
1
            return BigEndian::ToHost16(value);
232
1
        } else if constexpr (std::is_same_v<T, uint16_t>) {
233
1
            return BigEndian::ToHost16(value);
234
1
        } else if constexpr (std::is_same_v<T, int8_t>) {
235
5
            return value;
236
5
        } else if constexpr (std::is_same_v<T, uint8_t>) {
237
5
            return value;
238
5
        } else {
239
5
            throw Exception(Status::FatalError("__builtin_unreachable"));
240
5
        }
241
5
    }
_ZN5doris7BitUtil18big_endian_to_hostItEET_S2_
Line
Count
Source
213
1
    static T big_endian_to_host(T value) {
214
1
        if constexpr (std::is_same_v<T, wide::Int256>) {
215
1
            return BigEndian::ToHost256(value);
216
1
        } else if constexpr (std::is_same_v<T, wide::UInt256>) {
217
1
            return BigEndian::ToHost256(value);
218
1
        } else if constexpr (std::is_same_v<T, __int128>) {
219
1
            return BigEndian::ToHost128(value);
220
1
        } else if constexpr (std::is_same_v<T, unsigned __int128>) {
221
1
            return BigEndian::ToHost128(value);
222
1
        } else if constexpr (std::is_same_v<T, int64_t>) {
223
1
            return BigEndian::ToHost64(value);
224
1
        } else if constexpr (std::is_same_v<T, uint64_t>) {
225
1
            return BigEndian::ToHost64(value);
226
1
        } else if constexpr (std::is_same_v<T, int32_t>) {
227
1
            return BigEndian::ToHost32(value);
228
1
        } else if constexpr (std::is_same_v<T, uint32_t>) {
229
1
            return BigEndian::ToHost32(value);
230
1
        } else if constexpr (std::is_same_v<T, int16_t>) {
231
1
            return BigEndian::ToHost16(value);
232
1
        } else if constexpr (std::is_same_v<T, uint16_t>) {
233
1
            return BigEndian::ToHost16(value);
234
1
        } else if constexpr (std::is_same_v<T, int8_t>) {
235
1
            return value;
236
1
        } else if constexpr (std::is_same_v<T, uint8_t>) {
237
1
            return value;
238
1
        } else {
239
1
            throw Exception(Status::FatalError("__builtin_unreachable"));
240
1
        }
241
1
    }
_ZN5doris7BitUtil18big_endian_to_hostIjEET_S2_
Line
Count
Source
213
1
    static T big_endian_to_host(T value) {
214
1
        if constexpr (std::is_same_v<T, wide::Int256>) {
215
1
            return BigEndian::ToHost256(value);
216
1
        } else if constexpr (std::is_same_v<T, wide::UInt256>) {
217
1
            return BigEndian::ToHost256(value);
218
1
        } else if constexpr (std::is_same_v<T, __int128>) {
219
1
            return BigEndian::ToHost128(value);
220
1
        } else if constexpr (std::is_same_v<T, unsigned __int128>) {
221
1
            return BigEndian::ToHost128(value);
222
1
        } else if constexpr (std::is_same_v<T, int64_t>) {
223
1
            return BigEndian::ToHost64(value);
224
1
        } else if constexpr (std::is_same_v<T, uint64_t>) {
225
1
            return BigEndian::ToHost64(value);
226
1
        } else if constexpr (std::is_same_v<T, int32_t>) {
227
1
            return BigEndian::ToHost32(value);
228
1
        } else if constexpr (std::is_same_v<T, uint32_t>) {
229
1
            return BigEndian::ToHost32(value);
230
1
        } else if constexpr (std::is_same_v<T, int16_t>) {
231
1
            return BigEndian::ToHost16(value);
232
1
        } else if constexpr (std::is_same_v<T, uint16_t>) {
233
1
            return BigEndian::ToHost16(value);
234
1
        } else if constexpr (std::is_same_v<T, int8_t>) {
235
1
            return value;
236
1
        } else if constexpr (std::is_same_v<T, uint8_t>) {
237
1
            return value;
238
1
        } else {
239
1
            throw Exception(Status::FatalError("__builtin_unreachable"));
240
1
        }
241
1
    }
_ZN5doris7BitUtil18big_endian_to_hostImEET_S2_
Line
Count
Source
213
1
    static T big_endian_to_host(T value) {
214
1
        if constexpr (std::is_same_v<T, wide::Int256>) {
215
1
            return BigEndian::ToHost256(value);
216
1
        } else if constexpr (std::is_same_v<T, wide::UInt256>) {
217
1
            return BigEndian::ToHost256(value);
218
1
        } else if constexpr (std::is_same_v<T, __int128>) {
219
1
            return BigEndian::ToHost128(value);
220
1
        } else if constexpr (std::is_same_v<T, unsigned __int128>) {
221
1
            return BigEndian::ToHost128(value);
222
1
        } else if constexpr (std::is_same_v<T, int64_t>) {
223
1
            return BigEndian::ToHost64(value);
224
1
        } else if constexpr (std::is_same_v<T, uint64_t>) {
225
1
            return BigEndian::ToHost64(value);
226
1
        } else if constexpr (std::is_same_v<T, int32_t>) {
227
1
            return BigEndian::ToHost32(value);
228
1
        } else if constexpr (std::is_same_v<T, uint32_t>) {
229
1
            return BigEndian::ToHost32(value);
230
1
        } else if constexpr (std::is_same_v<T, int16_t>) {
231
1
            return BigEndian::ToHost16(value);
232
1
        } else if constexpr (std::is_same_v<T, uint16_t>) {
233
1
            return BigEndian::ToHost16(value);
234
1
        } else if constexpr (std::is_same_v<T, int8_t>) {
235
1
            return value;
236
1
        } else if constexpr (std::is_same_v<T, uint8_t>) {
237
1
            return value;
238
1
        } else {
239
1
            throw Exception(Status::FatalError("__builtin_unreachable"));
240
1
        }
241
1
    }
_ZN5doris7BitUtil18big_endian_to_hostIoEET_S2_
Line
Count
Source
213
1
    static T big_endian_to_host(T value) {
214
1
        if constexpr (std::is_same_v<T, wide::Int256>) {
215
1
            return BigEndian::ToHost256(value);
216
1
        } else if constexpr (std::is_same_v<T, wide::UInt256>) {
217
1
            return BigEndian::ToHost256(value);
218
1
        } else if constexpr (std::is_same_v<T, __int128>) {
219
1
            return BigEndian::ToHost128(value);
220
1
        } else if constexpr (std::is_same_v<T, unsigned __int128>) {
221
1
            return BigEndian::ToHost128(value);
222
1
        } else if constexpr (std::is_same_v<T, int64_t>) {
223
1
            return BigEndian::ToHost64(value);
224
1
        } else if constexpr (std::is_same_v<T, uint64_t>) {
225
1
            return BigEndian::ToHost64(value);
226
1
        } else if constexpr (std::is_same_v<T, int32_t>) {
227
1
            return BigEndian::ToHost32(value);
228
1
        } else if constexpr (std::is_same_v<T, uint32_t>) {
229
1
            return BigEndian::ToHost32(value);
230
1
        } else if constexpr (std::is_same_v<T, int16_t>) {
231
1
            return BigEndian::ToHost16(value);
232
1
        } else if constexpr (std::is_same_v<T, uint16_t>) {
233
1
            return BigEndian::ToHost16(value);
234
1
        } else if constexpr (std::is_same_v<T, int8_t>) {
235
1
            return value;
236
1
        } else if constexpr (std::is_same_v<T, uint8_t>) {
237
1
            return value;
238
1
        } else {
239
1
            throw Exception(Status::FatalError("__builtin_unreachable"));
240
1
        }
241
1
    }
_ZN5doris7BitUtil18big_endian_to_hostIN4wide7integerILm256EjEEEET_S5_
Line
Count
Source
213
1
    static T big_endian_to_host(T value) {
214
1
        if constexpr (std::is_same_v<T, wide::Int256>) {
215
1
            return BigEndian::ToHost256(value);
216
1
        } else if constexpr (std::is_same_v<T, wide::UInt256>) {
217
1
            return BigEndian::ToHost256(value);
218
1
        } else if constexpr (std::is_same_v<T, __int128>) {
219
1
            return BigEndian::ToHost128(value);
220
1
        } else if constexpr (std::is_same_v<T, unsigned __int128>) {
221
1
            return BigEndian::ToHost128(value);
222
1
        } else if constexpr (std::is_same_v<T, int64_t>) {
223
1
            return BigEndian::ToHost64(value);
224
1
        } else if constexpr (std::is_same_v<T, uint64_t>) {
225
1
            return BigEndian::ToHost64(value);
226
1
        } else if constexpr (std::is_same_v<T, int32_t>) {
227
1
            return BigEndian::ToHost32(value);
228
1
        } else if constexpr (std::is_same_v<T, uint32_t>) {
229
1
            return BigEndian::ToHost32(value);
230
1
        } else if constexpr (std::is_same_v<T, int16_t>) {
231
1
            return BigEndian::ToHost16(value);
232
1
        } else if constexpr (std::is_same_v<T, uint16_t>) {
233
1
            return BigEndian::ToHost16(value);
234
1
        } else if constexpr (std::is_same_v<T, int8_t>) {
235
1
            return value;
236
1
        } else if constexpr (std::is_same_v<T, uint8_t>) {
237
1
            return value;
238
1
        } else {
239
1
            throw Exception(Status::FatalError("__builtin_unreachable"));
240
1
        }
241
1
    }
Unexecuted instantiation: _ZN5doris7BitUtil18big_endian_to_hostIlEET_S2_
Unexecuted instantiation: _ZN5doris7BitUtil18big_endian_to_hostInEET_S2_
Unexecuted instantiation: _ZN5doris7BitUtil18big_endian_to_hostIN4wide7integerILm256EiEEEET_S5_
Unexecuted instantiation: _ZN5doris7BitUtil18big_endian_to_hostIiEET_S2_
242
243
    /// Returns the smallest power of two that contains v. If v is a power of two, v is
244
    /// returned. Taken from
245
    /// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
246
8
    static inline int64_t RoundUpToPowerOfTwo(int64_t v) {
247
8
        --v;
248
8
        v |= v >> 1;
249
8
        v |= v >> 2;
250
8
        v |= v >> 4;
251
8
        v |= v >> 8;
252
8
        v |= v >> 16;
253
8
        v |= v >> 32;
254
8
        ++v;
255
8
        return v;
256
8
    }
257
258
    // Wrap the gutil/ version for convenience.
259
0
    static inline int Log2FloorNonZero64(uint64_t n) { return 63 ^ __builtin_clzll(n); }
260
261
    // Wrap the gutil/ version for convenience.
262
0
    static inline int Log2Floor64(uint64_t n) { return n == 0 ? -1 : 63 ^ __builtin_clzll(n); }
263
264
0
    static inline int Log2Ceiling64(uint64_t n) {
265
0
        int floor = Log2Floor64(n);
266
0
        // Check if zero or a power of two. This pattern is recognised by gcc and optimised
267
0
        // into branch-free code.
268
0
        if (0 == (n & (n - 1))) {
269
0
            return floor;
270
0
        } else {
271
0
            return floor + 1;
272
0
        }
273
0
    }
274
275
0
    static inline int Log2CeilingNonZero64(uint64_t n) {
276
0
        int floor = Log2FloorNonZero64(n);
277
0
        // Check if zero or a power of two. This pattern is recognised by gcc and optimised
278
0
        // into branch-free code.
279
0
        if (0 == (n & (n - 1))) {
280
0
            return floor;
281
0
        } else {
282
0
            return floor + 1;
283
0
        }
284
0
    }
285
286
    // Returns the rounded up to 64 multiple. Used for conversions of bits to i64.
287
0
    static inline uint32_t round_up_numi_64(uint32_t bits) { return (bits + 63) >> 6; }
288
289
0
    constexpr static inline int64_t Ceil(int64_t value, int64_t divisor) {
290
0
        return value / divisor + (value % divisor != 0);
291
0
    }
292
293
0
    constexpr static inline bool IsPowerOf2(int64_t value) { return (value & (value - 1)) == 0; }
294
295
0
    constexpr static inline int64_t RoundDown(int64_t value, int64_t factor) {
296
0
        return (value / factor) * factor;
297
0
    }
298
299
    /// Specialized round up and down functions for frequently used factors,
300
    /// like 8 (bits->bytes), 32 (bits->i32), and 64 (bits->i64)
301
    /// Returns the rounded up number of bytes that fit the number of bits.
302
71
    constexpr static inline uint32_t RoundUpNumBytes(uint32_t bits) { return (bits + 7) >> 3; }
303
304
    /// Non hw accelerated pop count.
305
    /// TODO: we don't use this in any perf sensitive code paths currently.  There
306
    /// might be a much faster way to implement this.
307
0
    static inline int PopcountNoHw(uint64_t x) {
308
0
        int count = 0;
309
0
        for (; x != 0; ++count) x &= x - 1;
310
0
        return count;
311
0
    }
312
313
    /// Returns the number of set bits in x
314
0
    static inline int Popcount(uint64_t x) {
315
0
        //if (LIKELY(CpuInfo::is_supported(CpuInfo::POPCNT))) {
316
0
        //  return POPCNT_popcnt_u64(x);
317
0
        //} else {
318
0
        return PopcountNoHw(x);
319
0
        // }
320
0
    }
321
322
    // Compute correct population count for various-width signed integers
323
    template <typename T>
324
    static inline int PopcountSigned(T v) {
325
        // Converting to same-width unsigned then extending preserves the bit pattern.
326
        return BitUtil::Popcount(static_cast<typename std::make_unsigned<T>::type>(v));
327
    }
328
329
    /// Logical right shift for signed integer types
330
    /// This is needed because the C >> operator does arithmetic right shift
331
    /// Negative shift amounts lead to undefined behavior
332
    template <typename T>
333
    constexpr static T ShiftRightLogical(T v, int shift) {
334
        // Conversion to unsigned ensures most significant bits always filled with 0's
335
        return static_cast<typename std::make_unsigned<T>::type>(v) >> shift;
336
    }
337
338
    /// Get an specific bit of a numeric type
339
    template <typename T>
340
    static inline int8_t GetBit(T v, int bitpos) {
341
        T masked = v & (static_cast<T>(0x1) << bitpos);
342
        return static_cast<int8_t>(ShiftRightLogical(masked, bitpos));
343
    }
344
345
    /// Set a specific bit to 1
346
    /// Behavior when bitpos is negative is undefined
347
    template <typename T>
348
    constexpr static T SetBit(T v, int bitpos) {
349
        return v | (static_cast<T>(0x1) << bitpos);
350
    }
351
352
    /// Set a specific bit to 0
353
    /// Behavior when bitpos is negative is undefined
354
    template <typename T>
355
    constexpr static T UnsetBit(T v, int bitpos) {
356
        return v & ~(static_cast<T>(0x1) << bitpos);
357
    }
358
359
    /// Returns 'value' rounded up to the nearest multiple of 'factor' when factor is
360
    /// a power of two
361
0
    static inline int64_t RoundUpToPowerOf2(int64_t value, int64_t factor) {
362
0
        DCHECK((factor > 0) && ((factor & (factor - 1)) == 0));
363
0
        return (value + (factor - 1)) & ~(factor - 1);
364
0
    }
365
366
    // speed up function compute for SIMD
367
0
    static inline size_t RoundUpToPowerOf2Int32(size_t value, size_t factor) {
368
0
        DCHECK((factor > 0) && ((factor & (factor - 1)) == 0));
369
0
        return (value + (factor - 1)) & ~(factor - 1);
370
0
    }
371
372
    template <typename T>
373
28
    static inline T RoundDownToPowerOf2(T value, T factor) {
374
28
        static_assert(std::is_integral<T>::value, "T must be an integral type");
375
28
        DCHECK((factor > 0) && ((factor & (factor - 1)) == 0));
376
28
        return value & ~(factor - 1);
377
28
    }
378
379
    // Returns the ceil of value/divisor
380
157k
    static inline int Ceil(int value, int divisor) {
381
157k
        return value / divisor + (value % divisor != 0);
382
157k
    }
383
384
    // Returns the 'num_bits' least-significant bits of 'v'.
385
630k
    static inline uint64_t TrailingBits(uint64_t v, int num_bits) {
386
630k
        if (num_bits == 0) [[unlikely]] {
387
24.6k
            return 0;
388
24.6k
        }
389
606k
        if (num_bits >= 64) [[unlikely]] {
390
200k
            return v;
391
200k
        }
392
405k
        int n = 64 - num_bits;
393
405k
        return (v << n) >> n;
394
606k
    }
395
396
200k
    static inline uint64_t ShiftLeftZeroOnOverflow(uint64_t v, int num_bits) {
397
200k
        if (num_bits >= 64) [[unlikely]] {
398
6.42k
            return 0;
399
6.42k
        }
400
194k
        return v << num_bits;
401
200k
    }
402
403
200k
    static inline uint64_t ShiftRightZeroOnOverflow(uint64_t v, int num_bits) {
404
200k
        if (num_bits >= 64) [[unlikely]] {
405
6.42k
            return 0;
406
6.42k
        }
407
194k
        return v >> num_bits;
408
200k
    }
409
410
0
    static void ByteSwapScalar(void* dest, const void* source, int len) {
411
0
        uint8_t* dst = reinterpret_cast<uint8_t*>(dest);
412
0
        const uint8_t* src = reinterpret_cast<const uint8_t*>(source);
413
0
        switch (len) {
414
0
        case 1:
415
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src);
416
0
            return;
417
0
        case 2:
418
0
            *reinterpret_cast<uint16_t*>(dst) =
419
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src));
420
0
            return;
421
0
        case 3:
422
0
            *reinterpret_cast<uint16_t*>(dst + 1) =
423
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src));
424
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 2);
425
0
            return;
426
0
        case 4:
427
0
            *reinterpret_cast<uint32_t*>(dst) =
428
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src));
429
0
            return;
430
0
        case 5:
431
0
            *reinterpret_cast<uint32_t*>(dst + 1) =
432
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src));
433
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 4);
434
0
            return;
435
0
        case 6:
436
0
            *reinterpret_cast<uint32_t*>(dst + 2) =
437
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src));
438
0
            *reinterpret_cast<uint16_t*>(dst) =
439
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src + 4));
440
0
            return;
441
0
        case 7:
442
0
            *reinterpret_cast<uint32_t*>(dst + 3) =
443
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src));
444
0
            *reinterpret_cast<uint16_t*>(dst + 1) =
445
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src + 4));
446
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 6);
447
0
            return;
448
0
        case 8:
449
0
            *reinterpret_cast<uint64_t*>(dst) =
450
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
451
0
            return;
452
0
        case 9:
453
0
            *reinterpret_cast<uint64_t*>(dst + 1) =
454
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
455
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 8);
456
0
            return;
457
0
        case 10:
458
0
            *reinterpret_cast<uint64_t*>(dst + 2) =
459
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
460
0
            *reinterpret_cast<uint16_t*>(dst) =
461
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src + 8));
462
0
            return;
463
0
        case 11:
464
0
            *reinterpret_cast<uint64_t*>(dst + 3) =
465
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
466
0
            *reinterpret_cast<uint16_t*>(dst + 1) =
467
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src + 8));
468
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 10);
469
0
            return;
470
0
        case 12:
471
0
            *reinterpret_cast<uint64_t*>(dst + 4) =
472
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
473
0
            *reinterpret_cast<uint32_t*>(dst) =
474
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src + 8));
475
0
            return;
476
0
        case 13:
477
0
            *reinterpret_cast<uint64_t*>(dst + 5) =
478
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
479
0
            *reinterpret_cast<uint32_t*>(dst + 1) =
480
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src + 8));
481
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 12);
482
0
            return;
483
0
        case 14:
484
0
            *reinterpret_cast<uint64_t*>(dst + 6) =
485
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
486
0
            *reinterpret_cast<uint32_t*>(dst + 2) =
487
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src + 8));
488
0
            *reinterpret_cast<uint16_t*>(dst) =
489
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src + 12));
490
0
            return;
491
0
        case 15:
492
0
            *reinterpret_cast<uint64_t*>(dst + 7) =
493
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
494
0
            *reinterpret_cast<uint32_t*>(dst + 3) =
495
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint32_t*>(src + 8));
496
0
            *reinterpret_cast<uint16_t*>(dst + 1) =
497
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint16_t*>(src + 12));
498
0
            *reinterpret_cast<uint8_t*>(dst) = *reinterpret_cast<const uint8_t*>(src + 14);
499
0
            return;
500
0
        case 16:
501
0
            *reinterpret_cast<uint64_t*>(dst + 8) =
502
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src));
503
0
            *reinterpret_cast<uint64_t*>(dst) =
504
0
                    BitUtil::byte_swap(*reinterpret_cast<const uint64_t*>(src + 8));
505
0
            return;
506
0
        default:
507
0
            // Revert to slow loop-based swap.
508
0
            ByteSwapScalarLoop(source, len, dest);
509
0
            return;
510
0
        }
511
0
    }
512
513
0
    static void ByteSwapScalarLoop(const void* src, int len, void* dst) {
514
0
        //TODO: improve the performance of following code further using BSWAP intrinsic
515
0
        uint8_t* d = reinterpret_cast<uint8_t*>(dst);
516
0
        const uint8_t* s = reinterpret_cast<const uint8_t*>(src);
517
0
        for (int i = 0; i < len; ++i) d[i] = s[len - i - 1];
518
0
    }
519
};
520
521
} // namespace doris