+template<>
+TBTable<DTZ>::TBTable(const TBTable<WDL>& wdl) :
+ TBTable() {
+
+ // Use the corresponding WDL table to avoid recalculating all from scratch
+ key = wdl.key;
+ key2 = wdl.key2;
+ pieceCount = wdl.pieceCount;
+ hasPawns = wdl.hasPawns;
+ hasUniquePieces = wdl.hasUniquePieces;
+ pawnCount[0] = wdl.pawnCount[0];
+ pawnCount[1] = wdl.pawnCount[1];
+}
+
+// class TBTables creates and keeps ownership of the TBTable objects, one for
+// each TB file found. It supports a fast, hash-based, table lookup. Populated
+// at init time, accessed at probe time.
+class TBTables {
+
+ struct Entry {
+ Key key;
+ TBTable<WDL>* wdl;
+ TBTable<DTZ>* dtz;
+
+ template<TBType Type>
+ TBTable<Type>* get() const {
+ return (TBTable<Type>*) (Type == WDL ? (void*) wdl : (void*) dtz);
+ }
+ };
+
+ static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb
+ static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket
+
+ Entry hashTable[Size + Overflow];
+
+ std::deque<TBTable<WDL>> wdlTable;
+ std::deque<TBTable<DTZ>> dtzTable;
+
+ void insert(Key key, TBTable<WDL>* wdl, TBTable<DTZ>* dtz) {
+ uint32_t homeBucket = uint32_t(key) & (Size - 1);
+ Entry entry{key, wdl, dtz};
+
+ // Ensure last element is empty to avoid overflow when looking up
+ for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket)
+ {
+ Key otherKey = hashTable[bucket].key;
+ if (otherKey == key || !hashTable[bucket].get<WDL>())
+ {
+ hashTable[bucket] = entry;
+ return;
+ }
+
+ // Robin Hood hashing: If we've probed for longer than this element,
+ // insert here and search for a new spot for the other element instead.
+ uint32_t otherHomeBucket = uint32_t(otherKey) & (Size - 1);
+ if (otherHomeBucket > homeBucket)
+ {
+ std::swap(entry, hashTable[bucket]);
+ key = otherKey;
+ homeBucket = otherHomeBucket;
+ }
+ }
+ std::cerr << "TB hash table size too low!" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ public:
+ template<TBType Type>
+ TBTable<Type>* get(Key key) {
+ for (const Entry* entry = &hashTable[uint32_t(key) & (Size - 1)];; ++entry)
+ {
+ if (entry->key == key || !entry->get<Type>())
+ return entry->get<Type>();
+ }
+ }
+
+ void clear() {
+ memset(hashTable, 0, sizeof(hashTable));
+ wdlTable.clear();
+ dtzTable.clear();
+ }
+ size_t size() const { return wdlTable.size(); }
+ void add(const std::vector<PieceType>& pieces);
+};
+
+TBTables TBTables;
+
+// If the corresponding file exists two new objects TBTable<WDL> and TBTable<DTZ>
+// are created and added to the lists and hash table. Called at init time.
+void TBTables::add(const std::vector<PieceType>& pieces) {