Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/misc.h
632 views
1
/*
2
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
Copyright (C) 2004-2026 The Stockfish developers (see AUTHORS file)
4
5
Stockfish is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Stockfish is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#ifndef MISC_H_INCLUDED
20
#define MISC_H_INCLUDED
21
22
#include <algorithm>
23
#include <array>
24
#include <cassert>
25
#include <chrono>
26
#include <cstdint>
27
#include <cstdio>
28
#include <exception> // IWYU pragma: keep
29
// IWYU pragma: no_include <__exception/terminate.h>
30
#include <functional>
31
#include <iosfwd>
32
#include <optional>
33
#include <cstring>
34
#include <memory>
35
#include <string>
36
#include <string_view>
37
#include <type_traits>
38
#include <vector>
39
40
#define stringify2(x) #x
41
#define stringify(x) stringify2(x)
42
43
namespace Stockfish {
44
45
std::string engine_version_info();
46
std::string engine_info(bool to_uci = false);
47
std::string compiler_info();
48
49
// Preloads the given address in L1/L2 cache. This is a non-blocking
50
// function that doesn't stall the CPU waiting for data to be loaded from memory,
51
// which can be quite slow.
52
void prefetch(const void* addr);
53
54
void start_logger(const std::string& fname);
55
56
size_t str_to_size_t(const std::string& s);
57
58
#if defined(__linux__)
59
60
struct PipeDeleter {
61
void operator()(FILE* file) const {
62
if (file != nullptr)
63
{
64
pclose(file);
65
}
66
}
67
};
68
69
#endif
70
71
// Reads the file as bytes.
72
// Returns std::nullopt if the file does not exist.
73
std::optional<std::string> read_file_to_string(const std::string& path);
74
75
void dbg_hit_on(bool cond, int slot = 0);
76
void dbg_mean_of(int64_t value, int slot = 0);
77
void dbg_stdev_of(int64_t value, int slot = 0);
78
void dbg_extremes_of(int64_t value, int slot = 0);
79
void dbg_correl_of(int64_t value1, int64_t value2, int slot = 0);
80
void dbg_print();
81
void dbg_clear();
82
83
using TimePoint = std::chrono::milliseconds::rep; // A value in milliseconds
84
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
85
inline TimePoint now() {
86
return std::chrono::duration_cast<std::chrono::milliseconds>(
87
std::chrono::steady_clock::now().time_since_epoch())
88
.count();
89
}
90
91
inline std::vector<std::string_view> split(std::string_view s, std::string_view delimiter) {
92
std::vector<std::string_view> res;
93
94
if (s.empty())
95
return res;
96
97
size_t begin = 0;
98
for (;;)
99
{
100
const size_t end = s.find(delimiter, begin);
101
if (end == std::string::npos)
102
break;
103
104
res.emplace_back(s.substr(begin, end - begin));
105
begin = end + delimiter.size();
106
}
107
108
res.emplace_back(s.substr(begin));
109
110
return res;
111
}
112
113
void remove_whitespace(std::string& s);
114
bool is_whitespace(std::string_view s);
115
116
enum SyncCout {
117
IO_LOCK,
118
IO_UNLOCK
119
};
120
std::ostream& operator<<(std::ostream&, SyncCout);
121
122
#define sync_cout std::cout << IO_LOCK
123
#define sync_endl std::endl << IO_UNLOCK
124
125
void sync_cout_start();
126
void sync_cout_end();
127
128
// True if and only if the binary is compiled on a little-endian machine
129
static inline const std::uint16_t Le = 1;
130
static inline const bool IsLittleEndian = *reinterpret_cast<const char*>(&Le) == 1;
131
132
133
template<typename T, std::size_t MaxSize>
134
class ValueList {
135
136
public:
137
std::size_t size() const { return size_; }
138
int ssize() const { return int(size_); }
139
void push_back(const T& value) {
140
assert(size_ < MaxSize);
141
values_[size_++] = value;
142
}
143
const T* begin() const { return values_; }
144
const T* end() const { return values_ + size_; }
145
const T& operator[](int index) const { return values_[index]; }
146
147
T* make_space(size_t count) {
148
T* result = &values_[size_];
149
size_ += count;
150
assert(size_ <= MaxSize);
151
return result;
152
}
153
154
private:
155
T values_[MaxSize];
156
std::size_t size_ = 0;
157
};
158
159
160
template<typename T, std::size_t Size, std::size_t... Sizes>
161
class MultiArray;
162
163
namespace Detail {
164
165
template<typename T, std::size_t Size, std::size_t... Sizes>
166
struct MultiArrayHelper {
167
using ChildType = MultiArray<T, Sizes...>;
168
};
169
170
template<typename T, std::size_t Size>
171
struct MultiArrayHelper<T, Size> {
172
using ChildType = T;
173
};
174
175
template<typename To, typename From>
176
constexpr bool is_strictly_assignable_v =
177
std::is_assignable_v<To&, From> && (std::is_same_v<To, From> || !std::is_convertible_v<From, To>);
178
179
}
180
181
// MultiArray is a generic N-dimensional array.
182
// The template parameters (Size and Sizes) encode the dimensions of the array.
183
template<typename T, std::size_t Size, std::size_t... Sizes>
184
class MultiArray {
185
using ChildType = typename Detail::MultiArrayHelper<T, Size, Sizes...>::ChildType;
186
using ArrayType = std::array<ChildType, Size>;
187
ArrayType data_;
188
189
public:
190
using value_type = typename ArrayType::value_type;
191
using size_type = typename ArrayType::size_type;
192
using difference_type = typename ArrayType::difference_type;
193
using reference = typename ArrayType::reference;
194
using const_reference = typename ArrayType::const_reference;
195
using pointer = typename ArrayType::pointer;
196
using const_pointer = typename ArrayType::const_pointer;
197
using iterator = typename ArrayType::iterator;
198
using const_iterator = typename ArrayType::const_iterator;
199
using reverse_iterator = typename ArrayType::reverse_iterator;
200
using const_reverse_iterator = typename ArrayType::const_reverse_iterator;
201
202
constexpr auto& at(size_type index) noexcept { return data_.at(index); }
203
constexpr const auto& at(size_type index) const noexcept { return data_.at(index); }
204
205
constexpr auto& operator[](size_type index) noexcept { return data_[index]; }
206
constexpr const auto& operator[](size_type index) const noexcept { return data_[index]; }
207
208
constexpr auto& front() noexcept { return data_.front(); }
209
constexpr const auto& front() const noexcept { return data_.front(); }
210
constexpr auto& back() noexcept { return data_.back(); }
211
constexpr const auto& back() const noexcept { return data_.back(); }
212
213
auto* data() { return data_.data(); }
214
const auto* data() const { return data_.data(); }
215
216
constexpr auto begin() noexcept { return data_.begin(); }
217
constexpr auto end() noexcept { return data_.end(); }
218
constexpr auto begin() const noexcept { return data_.begin(); }
219
constexpr auto end() const noexcept { return data_.end(); }
220
constexpr auto cbegin() const noexcept { return data_.cbegin(); }
221
constexpr auto cend() const noexcept { return data_.cend(); }
222
223
constexpr auto rbegin() noexcept { return data_.rbegin(); }
224
constexpr auto rend() noexcept { return data_.rend(); }
225
constexpr auto rbegin() const noexcept { return data_.rbegin(); }
226
constexpr auto rend() const noexcept { return data_.rend(); }
227
constexpr auto crbegin() const noexcept { return data_.crbegin(); }
228
constexpr auto crend() const noexcept { return data_.crend(); }
229
230
constexpr bool empty() const noexcept { return data_.empty(); }
231
constexpr size_type size() const noexcept { return data_.size(); }
232
constexpr size_type max_size() const noexcept { return data_.max_size(); }
233
234
template<typename U>
235
void fill(const U& v) {
236
static_assert(Detail::is_strictly_assignable_v<T, U>,
237
"Cannot assign fill value to entry type");
238
for (auto& ele : data_)
239
{
240
if constexpr (sizeof...(Sizes) == 0)
241
ele = v;
242
else
243
ele.fill(v);
244
}
245
}
246
247
constexpr void swap(MultiArray<T, Size, Sizes...>& other) noexcept { data_.swap(other.data_); }
248
};
249
250
251
// xorshift64star Pseudo-Random Number Generator
252
// This class is based on original code written and dedicated
253
// to the public domain by Sebastiano Vigna (2014).
254
// It has the following characteristics:
255
//
256
// - Outputs 64-bit numbers
257
// - Passes Dieharder and SmallCrush test batteries
258
// - Does not require warm-up, no zeroland to escape
259
// - Internal state is a single 64-bit integer
260
// - Period is 2^64 - 1
261
// - Speed: 1.60 ns/call (Core i7 @3.40GHz)
262
//
263
// For further analysis see
264
// <http://vigna.di.unimi.it/ftp/papers/xorshift.pdf>
265
266
class PRNG {
267
268
uint64_t s;
269
270
uint64_t rand64() {
271
272
s ^= s >> 12, s ^= s << 25, s ^= s >> 27;
273
return s * 2685821657736338717LL;
274
}
275
276
public:
277
PRNG(uint64_t seed) :
278
s(seed) {
279
assert(seed);
280
}
281
282
template<typename T>
283
T rand() {
284
return T(rand64());
285
}
286
287
// Special generator used to fast init magic numbers.
288
// Output values only have 1/8th of their bits set on average.
289
template<typename T>
290
T sparse_rand() {
291
return T(rand64() & rand64() & rand64());
292
}
293
};
294
295
inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
296
#if defined(__GNUC__) && defined(IS_64BIT)
297
__extension__ using uint128 = unsigned __int128;
298
return (uint128(a) * uint128(b)) >> 64;
299
#else
300
uint64_t aL = uint32_t(a), aH = a >> 32;
301
uint64_t bL = uint32_t(b), bH = b >> 32;
302
uint64_t c1 = (aL * bL) >> 32;
303
uint64_t c2 = aH * bL + c1;
304
uint64_t c3 = aL * bH + uint32_t(c2);
305
return aH * bH + (c2 >> 32) + (c3 >> 32);
306
#endif
307
}
308
309
uint64_t hash_bytes(const char*, size_t);
310
311
template<typename T>
312
inline std::size_t get_raw_data_hash(const T& value) {
313
// We must have no padding bytes because we're reinterpreting as char
314
static_assert(std::has_unique_object_representations<T>());
315
316
return static_cast<std::size_t>(
317
hash_bytes(reinterpret_cast<const char*>(&value), sizeof(value)));
318
}
319
320
template<typename T>
321
inline void hash_combine(std::size_t& seed, const T& v) {
322
std::size_t x;
323
// For primitive types we avoid using the default hasher, which may be
324
// nondeterministic across program invocations
325
if constexpr (std::is_integral<T>())
326
x = v;
327
else
328
x = std::hash<T>{}(v);
329
seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2);
330
}
331
332
inline std::uint64_t hash_string(const std::string& sv) { return hash_bytes(sv.data(), sv.size()); }
333
334
template<std::size_t Capacity>
335
class FixedString {
336
public:
337
FixedString() :
338
length_(0) {
339
data_[0] = '\0';
340
}
341
342
FixedString(const char* str) {
343
size_t len = std::strlen(str);
344
if (len > Capacity)
345
std::terminate();
346
std::memcpy(data_, str, len);
347
length_ = len;
348
data_[length_] = '\0';
349
}
350
351
FixedString(const std::string& str) {
352
if (str.size() > Capacity)
353
std::terminate();
354
std::memcpy(data_, str.data(), str.size());
355
length_ = str.size();
356
data_[length_] = '\0';
357
}
358
359
std::size_t size() const { return length_; }
360
std::size_t capacity() const { return Capacity; }
361
362
const char* c_str() const { return data_; }
363
const char* data() const { return data_; }
364
365
char& operator[](std::size_t i) { return data_[i]; }
366
367
const char& operator[](std::size_t i) const { return data_[i]; }
368
369
FixedString& operator+=(const char* str) {
370
size_t len = std::strlen(str);
371
if (length_ + len > Capacity)
372
std::terminate();
373
std::memcpy(data_ + length_, str, len);
374
length_ += len;
375
data_[length_] = '\0';
376
return *this;
377
}
378
379
FixedString& operator+=(const FixedString& other) { return (*this += other.c_str()); }
380
381
operator std::string() const { return std::string(data_, length_); }
382
383
operator std::string_view() const { return std::string_view(data_, length_); }
384
385
template<typename T>
386
bool operator==(const T& other) const noexcept {
387
return (std::string_view) (*this) == other;
388
}
389
390
template<typename T>
391
bool operator!=(const T& other) const noexcept {
392
return (std::string_view) (*this) != other;
393
}
394
395
void clear() {
396
length_ = 0;
397
data_[0] = '\0';
398
}
399
400
private:
401
char data_[Capacity + 1]; // +1 for null terminator
402
std::size_t length_;
403
};
404
405
struct CommandLine {
406
public:
407
CommandLine(int _argc, char** _argv) :
408
argc(_argc),
409
argv(_argv) {}
410
411
static std::string get_binary_directory(std::string argv0);
412
static std::string get_working_directory();
413
414
int argc;
415
char** argv;
416
};
417
418
namespace Utility {
419
420
template<typename T, typename Predicate>
421
void move_to_front(std::vector<T>& vec, Predicate pred) {
422
auto it = std::find_if(vec.begin(), vec.end(), pred);
423
424
if (it != vec.end())
425
{
426
std::rotate(vec.begin(), it, it + 1);
427
}
428
}
429
}
430
431
#if defined(__GNUC__)
432
#define sf_always_inline __attribute__((always_inline))
433
#elif defined(_MSC_VER)
434
#define sf_always_inline __forceinline
435
#else
436
// do nothing for other compilers
437
#define sf_always_inline
438
#endif
439
440
#if defined(__clang__)
441
#define sf_assume(cond) __builtin_assume(cond)
442
#elif defined(__GNUC__)
443
#if __GNUC__ >= 13
444
#define sf_assume(cond) __attribute__((assume(cond)))
445
#else
446
#define sf_assume(cond) \
447
do \
448
{ \
449
if (!(cond)) \
450
__builtin_unreachable(); \
451
} while (0)
452
#endif
453
#elif defined(_MSC_VER)
454
#define sf_assume(cond) __assume(cond)
455
#else
456
// do nothing for other compilers
457
#define sf_assume(cond)
458
#endif
459
460
#ifdef __GNUC__
461
#define sf_unreachable() __builtin_unreachable()
462
#elif defined(_MSC_VER)
463
#define sf_unreachable() __assume(0)
464
#else
465
#define sf_unreachable()
466
#endif
467
468
} // namespace Stockfish
469
470
template<std::size_t N>
471
struct std::hash<Stockfish::FixedString<N>> {
472
std::size_t operator()(const Stockfish::FixedString<N>& fstr) const noexcept {
473
return Stockfish::hash_bytes(fstr.data(), fstr.size());
474
}
475
};
476
477
#endif // #ifndef MISC_H_INCLUDED
478
479