/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2026 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Stockfish is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TT_H_INCLUDED #define TT_H_INCLUDED #include #include "misc.h" #include "memory.h" #include "types.h" namespace Stockfish { class ThreadPool; struct TTEntry; struct Cluster; // There is only one global hash table for the engine and all its threads. For chess in particular, we even allow racy // updates between threads to and from the TT, as taking the time to synchronize access would cost thinking time and // thus elo. As a hash table, collisions are possible and may cause chess playing issues (bizarre blunders, faulty mate // reports, etc). Fixing these also loses elo; however such risk decreases quickly with larger TT size. // // We clearly separate TTData, a local copy of an entry, from TTWriter, which writes to the global table. // A copy of the data already in an entry (possibly collided). Probes and reads are racy and non-atomic, // possibly resulting in inconsistent data. struct TTData { Move move; Value value, eval; Depth depth; Bound bound; bool is_pv; TTData() = delete; // clang-format off TTData(Move m, Value v, Value ev, Depth d, Bound b, bool pv) : move(m), value(v), eval(ev), depth(d), bound(b), is_pv(pv) {}; // clang-format on }; // This is used to make racy, non-atomic writes to the global TT. Writes are not "guaranteed": // for chess reasons, we may decide the new data is less important than the old. struct TTWriter { public: void write(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, u8 generation8); void penalize(int penalty); // decrement stored depth by the penalty private: friend class TranspositionTable; TTEntry* entry; TTWriter(TTEntry* tte); }; class TranspositionTable { public: ~TranspositionTable() { aligned_large_pages_free(table); } void resize(usize mbSize, ThreadPool& threads); // Set TT size in MiB void clear(ThreadPool& threads); // Re-initialize memory, multithreaded void new_search(); // This must be called at the beginning of each root search to track entry aging u8 generation() const; // The current age, used when writing new data to the TT // Approximate what fraction of entries (permille) have been written to during this root search int hashfull(int maxAge = 0) const; // `probe` is the primary method: given a board position, we lookup its entry in the table, and return a tuple of: // 1) whether the entry already had data on this position // 2) a copy of the prior data, if any (may be self-inconsistent due to read races) // 3) a writer object to the entry std::tuple probe(const Key key) const; // The hash function; its only external use is memory prefetching TTEntry* first_entry(const Key key) const; private: friend struct TTEntry; usize clusterCount; Cluster* table = nullptr; u8 generation8 = 0; }; } // namespace Stockfish #endif // #ifndef TT_H_INCLUDED