HooverChessUtils_PgnReader 0.9.0
Loading...
Searching...
No Matches
bittricks.h
Go to the documentation of this file.
1// Hoover Chess Utilities / PGN reader
2// Copyright (C) 2025-2026 Sami Kiminki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17#ifndef HOOVER_CHESS_UTILS__PGN_READER__BITTRICKS_H_INCLUDED
18#define HOOVER_CHESS_UTILS__PGN_READER__BITTRICKS_H_INCLUDED
19
20#include "pgnreader-config.h"
21
22#include <bit>
23#include <cassert>
24#include <cinttypes>
25
26#if (HAVE_X86_BMI2)
27#include <immintrin.h>
28#endif
29
30#if (HAVE_AARCH64_SVE2_BITPERM)
31#include <arm_sve.h>
32#endif
33
35{
36
40{
41
46 static constexpr inline std::uint64_t bits0ToN(std::uint8_t n) noexcept
47 {
48 assert(n <= 63U);
49
50 return (std::uint64_t { 2 } << n) - 1U;
51 }
52
68 static constexpr inline std::uint64_t rangeHalfOpen(std::uint8_t a, std::uint8_t b) noexcept
69 {
70 assert(a <= 63U);
71 assert(b <= 63U);
72
73 return bits0ToN(a) ^ bits0ToN(b);
74 }
75
80 static constexpr inline std::uint64_t isolateLowestSetBit(std::uint64_t mask) noexcept
81 {
82 return mask & (-mask);
83 }
84
89 static constexpr inline std::uint64_t isolateHighestSetBit(std::uint64_t mask) noexcept
90 {
91 // Note: we need to 'and' to ensure that the isolated bit actually exists (when n == 0)
92 if (mask != 0U) [[likely]]
93 {
94 std::uint64_t topBit { UINT64_C(0x80'00'00'00'00'00'00'00) };
95 return (topBit >> std::countl_zero(mask));
96 }
97 else [[unlikely]]
98 {
99 return 0U;
100 }
101 }
102
103private:
104 static std::uint64_t parallelExtractPortable(std::uint64_t data, std::uint64_t mask) noexcept;
105 static std::uint64_t parallelDepositPortable(std::uint64_t data, std::uint64_t mask) noexcept;
106
107public:
108
136 static inline std::uint64_t parallelExtract(std::uint64_t data, std::uint64_t mask) noexcept
137 {
138#if (HAVE_X86_BMI2)
139 return _pext_u64(data, mask);
140#elif (HAVE_AARCH64_SVE2_BITPERM)
141 return svbext_n_u64(svdup_u64(data), mask)[0U];
142#elif 1
143 return parallelExtractPortable(data, mask);
144#else
145 std::uint64_t mk { (~mask) << 1U };
146 data = data & mask;
147
148 for (unsigned i { }; i < 6U; ++i)
149 {
150 std::uint64_t mp { mk ^ (mk << 1U) };
151 mp = mp ^ (mp << 2U);
152 mp = mp ^ (mp << 4U);
153 mp = mp ^ (mp << 8U);
154 mp = mp ^ (mp << 16U);
155 mp = mp ^ (mp << 32U);
156
157 const std::uint64_t mv { mp & mask };
158 mask = (mask ^ mv) | (mv >> (UINT64_C(1) << i));
159 const std::uint64_t t { data & mv };
160 data = (data ^ t) | (t >> (UINT64_C(1) << i));
161 mk = mk & ~mp;
162 }
163
164 return data;
165#endif
166 }
167
195 static inline std::uint64_t parallelDeposit(std::uint64_t data, std::uint64_t mask) noexcept
196 {
197#if (HAVE_X86_BMI2)
198 return _pdep_u64(data, mask);
199#elif (HAVE_AARCH64_SVE2_BITPERM)
200 return svbdep_n_u64(svdup_u64(data), mask)[0U];
201#elif 1
202 return parallelDepositPortable(data, mask);
203#else
204 std::uint64_t mk { (~mask) << 1U };
205 const std::uint64_t m0 { mask };
206
207 std::uint64_t arr[6];
208
209 for (unsigned i { }; i < 6U; ++i)
210 {
211 std::uint64_t mp { mk ^ (mk << 1U) };
212 mp = mp ^ (mp << 2U);
213 mp = mp ^ (mp << 4U);
214 mp = mp ^ (mp << 8U);
215 mp = mp ^ (mp << 16U);
216 mp = mp ^ (mp << 32U);
217
218 const std::uint64_t mv { mp & mask };
219 arr[i] = mv;
220 mask = (mask ^ mv) | (mv >> (UINT64_C(1) << i));
221 mk = mk & ~mp;
222 }
223
224 for (unsigned i { 5U }; i <= 5U; --i)
225 {
226 std::uint64_t mv { arr[i] };
227 const std::uint64_t t { data << (1U << i) };
228 data = (data & ~mv) | (t & mv);
229 }
230
231 return data & m0;
232#endif
233 }
234
235};
236
237}
238
239#endif
Definition chessboard-types-squareset.h:30
Collection of bit tricks for 64-bit words.
Definition bittricks.h:40
static constexpr std::uint64_t isolateHighestSetBit(std::uint64_t mask) noexcept
Isolates (extracts) the highest bit set in bit mask.
Definition bittricks.h:89
static constexpr std::uint64_t isolateLowestSetBit(std::uint64_t mask) noexcept
Isolates (extracts) the lowest bit set in bit mask.
Definition bittricks.h:80
static std::uint64_t parallelDepositPortable(std::uint64_t data, std::uint64_t mask) noexcept
static constexpr std::uint64_t rangeHalfOpen(std::uint8_t a, std::uint8_t b) noexcept
Generates a half-open bit mask (min(a,b), max(a,b)].
Definition bittricks.h:68
static constexpr std::uint64_t bits0ToN(std::uint8_t n) noexcept
Generates a bit mask with bits 0 to N set.
Definition bittricks.h:46
static std::uint64_t parallelExtractPortable(std::uint64_t data, std::uint64_t mask) noexcept
static std::uint64_t parallelDeposit(std::uint64_t data, std::uint64_t mask) noexcept
Deposits bits of data to bit locations specified by mask.
Definition bittricks.h:195
static std::uint64_t parallelExtract(std::uint64_t data, std::uint64_t mask) noexcept
Extracts bits of data from bit locations specified by mask.
Definition bittricks.h:136