LCOV - code coverage report
Current view: top level - src - indexentry.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 290 299 97.0 %
Date: 2019-01-29 11:06:41 Functions: 84 84 100.0 %

          Line data    Source code
       1             : /*
       2             : * Copyright (c) 1999-2002  Shane Hudson
       3             : * Copyright (c) 2006-2009  Pascal Georges
       4             : * Copyright (C) 2014-2017  Fulvio Benini
       5             : 
       6             : * This file is part of Scid (Shane's Chess Information Database).
       7             : *
       8             : * Scid is free software: you can redistribute it and/or modify
       9             : * it under the terms of the GNU General Public License as published by
      10             : * the Free Software Foundation.
      11             : *
      12             : * Scid is distributed in the hope that it will be useful,
      13             : * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             : * GNU General Public License for more details.
      16             : *
      17             : * You should have received a copy of the GNU General Public License
      18             : * along with Scid.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #ifndef SCID_INDEXENTRY_H
      22             : #define SCID_INDEXENTRY_H
      23             : 
      24             : #include "common.h"
      25             : #include "date.h"
      26             : #include "matsig.h"
      27             : #include "namebase.h"
      28             : 
      29             : // Length is encoded as 17bits uint
      30             : #define MAX_GAME_LENGTH 131072
      31             : 
      32             : // HPSIG_SIZE = size of HomePawnData array in an IndexEntry.
      33             : // It is nine bytes: the first byte contains the number of valid entries
      34             : // in the array, and the next 8 bytes contain up to 16 half-byte entries.
      35             : const uint HPSIG_SIZE = 9;
      36             : 
      37             : const eloT MAX_ELO = 4000; // Since we store Elo Ratings in 12 bits
      38             : 
      39             : const byte CUSTOM_FLAG_MASK[] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5 };
      40             : 
      41             : // Total on-disk size per index entry: currently 47 bytes.
      42             : const uint  INDEX_ENTRY_SIZE = 47;
      43             : const uint  OLD_INDEX_ENTRY_SIZE = 46;
      44             : 
      45             : 
      46             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      47             : // Class IndexEntry: one of these per game in the index file.
      48             : //
      49             : //    It contains more than just the location of the game data in the main
      50             : //    data file.  For fast searching, it also store some other important
      51             : //    values: players, event, site, date, result, eco, gamelength.
      52             : //
      53             : //    It takes 56 bytes.
      54             : class IndexEntry {
      55             :     uint64_t offset_         : 46; // Start of gamefile record for this game.
      56             :     uint64_t gameDataSize_   : 18; // Length of gamefile record for this game.
      57             : 
      58             :     uint64_t storedLineCode_ :  8;
      59             :     uint64_t whiteID_        : 28;
      60             :     uint64_t blackID_        : 28;
      61             : 
      62             :     uint32_t eventID_        : 28;
      63             :     uint32_t whiteEloType_   :  4;
      64             : 
      65             :     uint32_t siteID_         : 28;
      66             :     uint32_t blackEloType_   :  4;
      67             : 
      68             :     uint32_t roundID_        : 28;
      69             :     uint32_t result_         :  4;
      70             : 
      71             :     uint32_t whiteElo_       : 12;
      72             :     uint32_t date_           : 20;
      73             : 
      74             :     uint32_t blackElo_       : 12;
      75             :     uint32_t eventDate_      : 20;
      76             : 
      77             :     uint32_t numHalfMoves_   : 10;
      78             :     uint32_t flags_          : 22;
      79             : 
      80             :     uint32_t finalMatSig_    : 24; // material of the final position in the game
      81             :     uint32_t nVariations_    :  4;
      82             :     uint32_t nComments_      :  4;
      83             : 
      84             :     uint16_t ECOcode_;
      85             : 
      86             :     uint8_t  nNags_          :  4;
      87             : 
      88             :     byte     HomePawnData [HPSIG_SIZE];  // homePawnSig data.
      89             : 
      90             : public:
      91        9015 :     void Init() { std::memset(this, 0, sizeof(IndexEntry)); }
      92             : 
      93             :     template <class T> errorT Write (T* file, versionT version) const;
      94             : 
      95             :     // get functions
      96      837378 :     uint64_t  GetOffset() const { return offset_; }
      97      967378 :     uint32_t  GetLength() const { return gameDataSize_; }
      98      964114 :     idNumberT GetWhite() const { return whiteID_; }
      99      838301 :     eloT      GetWhiteElo() const { return whiteElo_; }
     100      718354 :     byte      GetWhiteRatingType() const { return whiteEloType_; }
     101     1068099 :     idNumberT GetBlack() const { return blackID_; }
     102      913741 :     eloT      GetBlackElo() const { return blackElo_; }
     103      718354 :     byte      GetBlackRatingType() const { return blackEloType_; }
     104      924929 :     idNumberT GetEvent() const { return eventID_; }
     105     1141795 :     idNumberT GetSite() const { return siteID_; }
     106     1071901 :     idNumberT GetRound() const { return roundID_; }
     107      848872 :     dateT     GetDate() const { return date_; }
     108      827822 :     dateT     GetEventDate() const { return eventDate_; }
     109     1577122 :     resultT   GetResult() const { return result_; }
     110      542771 :     uint      GetVariationCount() const { return DecodeCount(nVariations_); }
     111      564566 :     uint      GetCommentCount() const { return DecodeCount(nComments_); }
     112      526713 :     uint      GetNagCount() const { return DecodeCount(nNags_); }
     113      899862 :     uint16_t  GetNumHalfMoves() const { return numHalfMoves_; }
     114      821354 :     matSigT   GetFinalMatSig() const { return finalMatSig_; }
     115      821354 :     byte      GetStoredLineCode() const { return storedLineCode_; }
     116      821416 :     ecoT      GetEcoCode() const { return ECOcode_; }
     117     3185066 :     bool      GetFlag(uint32_t mask) const { return (flags_ & mask) == mask; }
     118      104000 :     const byte* GetHomePawnData() const { return HomePawnData; }
     119     3813354 :     byte* GetHomePawnData() { return HomePawnData; }
     120             : 
     121             :     // set functions, assert that the value is not truncated.
     122      316357 :     void SetOffset(uint64_t offset) {
     123      316357 :         offset_ = offset;
     124      316357 :         ASSERT(GetOffset() == offset);
     125      316357 :     }
     126      316357 :     void SetLength(size_t length) {
     127      316357 :         gameDataSize_ = length;
     128      316357 :         ASSERT(GetLength() == length);
     129      316357 :     }
     130      319357 :     void SetWhite(idNumberT id) {
     131      319357 :         whiteID_ = id;
     132      319357 :         ASSERT(GetWhite() == id);
     133      319357 :     }
     134      313354 :     void SetWhiteElo(eloT elo) {
     135      313354 :         whiteElo_ = elo;
     136      313354 :         ASSERT(GetWhiteElo() == elo);
     137      313354 :     }
     138      313354 :     void SetWhiteRatingType(byte b) {
     139      313354 :         whiteEloType_ = b;
     140      313354 :         ASSERT(GetWhiteRatingType() == b);
     141      313354 :     }
     142      319357 :     void SetBlack(idNumberT id) {
     143      319357 :         blackID_ = id;
     144      319357 :         ASSERT(GetBlack() == id);
     145      319357 :     }
     146      313354 :     void SetBlackElo(eloT elo) {
     147      313354 :         blackElo_ = elo;
     148      313354 :         ASSERT(GetBlackElo() == elo);
     149      313354 :     }
     150      313354 :     void SetBlackRatingType(byte b) {
     151      313354 :         blackEloType_ = b;
     152      313354 :         ASSERT(GetBlackRatingType() == b);
     153      313354 :     }
     154      319357 :     void SetEvent(idNumberT id) {
     155      319357 :         eventID_ = id;
     156      319357 :         ASSERT(GetEvent() == id);
     157      319357 :     }
     158      319357 :     void SetSite(idNumberT id) {
     159      319357 :         siteID_ = id;
     160      319357 :         ASSERT(GetSite() == id);
     161      319357 :     }
     162      319357 :     void SetRound(idNumberT id) {
     163      319357 :         roundID_ = id;
     164      319357 :         ASSERT(GetRound() == id);
     165      319357 :     }
     166      313354 :     void SetDate(dateT date) {
     167      313354 :         date_ = date;
     168      313354 :         ASSERT(GetDate() == date);
     169      313354 :     }
     170      313354 :     void SetEventDate(dateT edate) {
     171      313354 :         eventDate_ = edate;
     172      313354 :         ASSERT(GetEventDate() == edate);
     173      313354 :     }
     174      313354 :     void SetResult(resultT res) {
     175      313354 :         result_ = res;
     176      313354 :         ASSERT(GetResult() == res);
     177      313354 :     }
     178      209015 :     void SetVariationCount(unsigned x) { nVariations_ = EncodeCount(x); }
     179      209015 :     void SetCommentCount(unsigned x) { nComments_ = EncodeCount(x); }
     180      209015 :     void SetNagCount(unsigned x) { nNags_ = EncodeCount(x); }
     181      204339 :     void SetRawVariationCount(unsigned x) {
     182      204339 :         nVariations_ = x;
     183      204339 :         ASSERT(x == nVariations_);
     184      204339 :     }
     185      204339 :     void SetRawCommentCount(unsigned x) {
     186      204339 :         nComments_ = x;
     187      204339 :         ASSERT(x == nComments_);
     188      204339 :     }
     189      204339 :     void SetRawNagCount(unsigned x) {
     190      204339 :         nNags_ = x;
     191      204339 :         ASSERT(x == nNags_);
     192      204339 :     }
     193      313354 :     void SetNumHalfMoves(ushort b) {
     194      313354 :         numHalfMoves_ = b;
     195      313354 :         ASSERT(GetNumHalfMoves() == b);
     196      313354 :     }
     197      313354 :     void SetFinalMatSig(matSigT ms) {
     198      313354 :         finalMatSig_ = ms;
     199      313354 :         ASSERT(GetFinalMatSig() == ms);
     200      313354 :     }
     201      313354 :     void SetStoredLineCode(byte b) {
     202      313354 :         storedLineCode_ = b;
     203      313354 :         ASSERT(GetStoredLineCode() == b);
     204      313354 :     }
     205      313354 :     void SetEcoCode(ecoT eco) {
     206      313354 :         ECOcode_ = eco;
     207      313354 :         ASSERT(GetEcoCode() == eco);
     208      313354 :     }
     209     1303754 :     void SetFlag(uint32_t flagMask, bool set) {
     210     1303754 :         if (set)
     211      625887 :             flags_ |= flagMask;
     212             :         else
     213      677867 :             flags_ &= ~flagMask;
     214     1303754 :     }
     215             : 
     216             :     // Handy functions that do not directly access member vars.
     217       67762 :     uint  GetYear () const { return date_GetYear (GetDate()); }
     218             :     uint  GetMonth() const { return date_GetMonth (GetDate()); }
     219             :     uint  GetDay ()  const { return date_GetDay (GetDate()); }
     220             : 
     221             :     void SetPlayer(colorT col, idNumberT id) {
     222             :         return (col == BLACK) ? SetBlack(id) : SetWhite(id);
     223             :     }
     224             : 
     225        6356 :     const char* GetWhiteName (const NameBase* nb) const {
     226        6356 :         return nb->GetName (NAME_PLAYER, GetWhite()); 
     227             :     }
     228        5017 :     const char* GetBlackName (const NameBase* nb) const {
     229        5017 :         return nb->GetName (NAME_PLAYER, GetBlack());
     230             :     }
     231        7695 :     const char* GetEventName (const NameBase* nb) const {
     232        7695 :         return nb->GetName (NAME_EVENT, GetEvent());
     233             :     }
     234      197200 :     const char* GetSiteName (const NameBase* nb) const {
     235      197200 :         return nb->GetName (NAME_SITE, GetSite());
     236             :     }
     237        5017 :     const char* GetRoundName (const NameBase* nb) const {
     238        5017 :         return nb->GetName (NAME_ROUND, GetRound());
     239             :     }
     240       70461 :     eloT GetWhiteElo (const NameBase* nb)  const {
     241       70461 :         eloT r = GetWhiteElo();
     242       70461 :         if (r == 0 && nb != 0) return nb->GetElo (GetWhite());
     243       60467 :         return r;
     244             :     }
     245      145901 :     eloT GetBlackElo (const NameBase* nb) const {
     246      145901 :         eloT r = GetBlackElo();
     247      145901 :         if (r == 0 && nb != 0) return nb->GetElo (GetBlack());
     248      112817 :         return r;
     249             :     }
     250             :     byte   GetRating(const NameBase* nb) const;
     251             : 
     252      100000 :     bool GetStartFlag () const      { return GetFlag(1 << IDX_FLAG_START); }
     253      100000 :     bool GetPromotionsFlag () const { return GetFlag(1 << IDX_FLAG_PROMO); }
     254      100000 :     bool GetUnderPromoFlag() const  { return GetFlag(1 << IDX_FLAG_UPROMO); }
     255      100000 :     bool GetCommentsFlag () const   { return (GetCommentCount() > 0); }
     256      100000 :     bool GetVariationsFlag () const { return (GetVariationCount() > 0); }
     257      100000 :     bool GetNagsFlag () const       { return (GetNagCount() > 0); }
     258      166066 :     bool GetDeleteFlag () const     { return GetFlag(1 << IDX_FLAG_DELETE); }
     259             : 
     260             :     static uint CharToFlag (char ch);
     261             :     static uint32_t CharToFlagMask (char flag);
     262             :     static uint32_t StrToFlagMask (const char* flags);
     263             :     uint GetFlagStr(char* dest, const char* flags) const;
     264             : 
     265      109015 :     void SetStartFlag (bool b)      { SetFlag(1 << IDX_FLAG_START, b); }
     266      109015 :     void SetPromotionsFlag (bool b) { SetFlag(1 << IDX_FLAG_PROMO, b); }
     267      109015 :     void SetUnderPromoFlag (bool b) { SetFlag(1 << IDX_FLAG_UPROMO, b); }
     268      100000 :     void SetDeleteFlag (bool b)     { SetFlag(1 << IDX_FLAG_DELETE, b); }
     269      463355 :     void clearFlags() { return SetFlag(IDX_MASK_ALLFLAGS, false); }
     270             : 
     271             :     enum {
     272             :         // IndexEntry Flag types:
     273             :         IDX_FLAG_START      =  0,   // Game has own start position.
     274             :         IDX_FLAG_PROMO      =  1,   // Game contains promotion(s).
     275             :         IDX_FLAG_UPROMO     =  2,   // Game contains promotion(s).
     276             :         IDX_FLAG_DELETE     =  3,   // Game marked for deletion.
     277             :         IDX_FLAG_WHITE_OP   =  4,   // White openings flag.
     278             :         IDX_FLAG_BLACK_OP   =  5,   // Black openings flag.
     279             :         IDX_FLAG_MIDDLEGAME =  6,   // Middlegames flag.
     280             :         IDX_FLAG_ENDGAME    =  7,   // Endgames flag.
     281             :         IDX_FLAG_NOVELTY    =  8,   // Novelty flag.
     282             :         IDX_FLAG_PAWN       =  9,   // Pawn structure flag.
     283             :         IDX_FLAG_TACTICS    = 10,   // Tactics flag.
     284             :         IDX_FLAG_KSIDE      = 11,   // Kingside play flag.
     285             :         IDX_FLAG_QSIDE      = 12,   // Queenside play flag.
     286             :         IDX_FLAG_BRILLIANCY = 13,   // Brilliancy or good play.
     287             :         IDX_FLAG_BLUNDER    = 14,   // Blunder or bad play.
     288             :         IDX_FLAG_USER       = 15,   // User-defined flag.
     289             :         IDX_FLAG_CUSTOM1    = 16,   // Custom flag.
     290             :         IDX_FLAG_CUSTOM2    = 17,   // Custom flag.
     291             :         IDX_FLAG_CUSTOM3    = 18,   // Custom flag.
     292             :         IDX_FLAG_CUSTOM4    = 19,   // Custom flag.
     293             :         IDX_FLAG_CUSTOM5    = 20,   // Custom flag.
     294             :         IDX_FLAG_CUSTOM6    = 21,   // Custom flag.
     295             :         IDX_NUM_FLAGS       = 22,
     296             :     };
     297             :     static const uint32_t IDX_MASK_ALLFLAGS = 0xFFFFFFFF;
     298             : 
     299             : private:
     300      627045 :     static uint EncodeCount (uint x) {
     301      627045 :         if (x <= 10) { return x; }
     302      251081 :         if (x <= 12) { return 10; }
     303      238999 :         if (x <= 17) { return 11; }  // 11 indicates 15 (13-17)
     304      208776 :         if (x <= 24) { return 12; }  // 12 indicates 20 (18-24)
     305      166242 :         if (x <= 34) { return 13; }  // 13 indicates 30 (25-34)
     306      105448 :         if (x <= 44) { return 14; }  // 14 indicates 40 (35-44)
     307       45165 :         return 15;                   // 15 indicates 50 or more
     308             :     }
     309     1634050 :     static uint DecodeCount (uint x) {
     310             :         static uint countCodes[16] = {0,1,2,3,4,5,6,7,8,9,10,15,20,30,40,50};
     311     1634050 :         return countCodes[x & 15];
     312             :     }
     313             : };
     314             : 
     315             : 
     316             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     317             : // IndexEntry::Write():
     318             : //      Writes a single index entry to an open index file.
     319             : //      INDEX_ENTRY_SIZE must be updated
     320      104000 : template <class T> errorT IndexEntry::Write(T* file, versionT version) const {
     321      104000 :         if (version < 400) // Cannot write old-version index files:
     322           0 :                 return ERROR_FileVersion;
     323             : 
     324             :         char buf[INDEX_ENTRY_SIZE];
     325      104000 :         char* buf_it = buf;
     326     4160000 :         auto WriteOneByte = [&buf_it](uint8_t v) { *buf_it++ = v; };
     327     3640000 :         auto WriteTwoBytes = [&WriteOneByte](uint16_t v) {
     328     1768000 :                 WriteOneByte(static_cast<uint8_t>(v >> 8));
     329     1768000 :                 WriteOneByte(static_cast<uint8_t>(v));
     330     1768000 :         };
     331      728000 :         auto WriteFourBytes = [&WriteTwoBytes](uint32_t v) {
     332      312000 :                 WriteTwoBytes(static_cast<uint16_t>(v >> 16));
     333      312000 :                 WriteTwoBytes(static_cast<uint16_t>(v));
     334      312000 :         };
     335             : 
     336      104000 :         const IndexEntry* ie = this;
     337             : 
     338      104000 :         ASSERT(ie->GetOffset() < (1ULL << 32));
     339      104000 :         WriteFourBytes(static_cast<uint32_t>(ie->GetOffset()));
     340             : 
     341      104000 :         ASSERT(ie->GetLength() < (1ULL << 17));
     342      104000 :         WriteTwoBytes(static_cast<uint16_t>(ie->GetLength()));
     343      104000 :         uint8_t len_flags = static_cast<uint8_t>(ie->GetLength() >> 9) & 0x80;
     344      104000 :         len_flags |= static_cast<uint8_t>(ie->flags_ >> 16) & 0x3F;
     345      104000 :         WriteOneByte(len_flags);
     346      104000 :         WriteTwoBytes(static_cast<uint16_t>(ie->flags_));
     347             : 
     348             :         // WhiteID and BlackID are 20-bit values, EventID and SiteID are
     349             :         // 19-bit values, and RoundID is an 18-bit value.
     350             :         // WhiteID high 4 bits = bits 4-7 of WhiteBlack_High.
     351             :         // BlackID high 4 bits = bits 0-3 of WhiteBlack_High.
     352             :         // EventID high 3 bits = bits 5-7 of EventSiteRnd_high.
     353             :         // SiteID  high 3 bits = bits 2-4 of EventSiteRnd_high.
     354             :         // RoundID high 2 bits = bits 0-1 of EventSiteRnd_high.
     355      104000 :         ASSERT(std::max(ie->GetWhite(), ie->GetBlack()) < (1ULL << 20));
     356      104000 :         uint32_t WhiteID_Low = ie->GetWhite();
     357      104000 :         uint32_t BlackID_Low = ie->GetBlack();
     358      104000 :         uint32_t WhiteBlack_High = (WhiteID_Low & 0x0F0000) >> 12;
     359      104000 :         WhiteBlack_High |= (BlackID_Low & 0x0F0000) >> 16;
     360      104000 :         WriteOneByte(static_cast<uint8_t>(WhiteBlack_High));
     361      104000 :         WriteTwoBytes(static_cast<uint16_t>(WhiteID_Low));
     362      104000 :         WriteTwoBytes(static_cast<uint16_t>(BlackID_Low));
     363             : 
     364      104000 :         ASSERT(std::max(ie->GetEvent(), ie->GetSite()) < (1ULL << 19));
     365      104000 :         ASSERT(ie->GetRound() < (1ULL << 18));
     366      104000 :         uint32_t EventID_Low = ie->GetEvent();
     367      104000 :         uint32_t SiteID_Low = ie->GetSite();
     368      104000 :         uint32_t RoundID_Low = ie->GetRound();
     369      104000 :         uint32_t EventSiteRnd_High = (EventID_Low & 0x070000) >> 11;
     370      104000 :         EventSiteRnd_High |= (SiteID_Low & 0x070000) >> 14;
     371      104000 :         EventSiteRnd_High |= (RoundID_Low & 0x030000) >> 16;
     372      104000 :         WriteOneByte(static_cast<uint8_t>(EventSiteRnd_High));
     373      104000 :         WriteTwoBytes(static_cast<uint16_t>(EventID_Low));
     374      104000 :         WriteTwoBytes(static_cast<uint16_t>(SiteID_Low));
     375      104000 :         WriteTwoBytes(static_cast<uint16_t>(RoundID_Low));
     376             : 
     377      104000 :         uint16_t varCounts = ie->nVariations_ & 0x0F;
     378      104000 :         varCounts |= static_cast<uint16_t>(ie->nComments_ & 0x0F) << 4;
     379      104000 :         varCounts |= static_cast<uint16_t>(ie->nNags_ & 0x0F) << 8;
     380      104000 :         varCounts |= static_cast<uint16_t>(ie->GetResult() & 0x0F) << 12;
     381      104000 :         WriteTwoBytes(varCounts);
     382             : 
     383      104000 :         WriteTwoBytes(ie->GetEcoCode());
     384             : 
     385             :         // Due to a compact encoding format, the EventDate
     386             :         // must be within a few years of the Date.
     387      104000 :         uint32_t date = ie->GetDate() & 0xFFFFF;
     388      104000 :         uint32_t edate = ie->GetEventDate();
     389      104000 :         uint32_t eyear = date_GetYear(edate);
     390      104000 :         uint32_t dyear = date_GetYear(date);
     391      104000 :         if ((eyear + 3) < dyear || eyear > (dyear + 3)) {
     392       99656 :                 edate = ZERO_DATE;
     393             :         } else {
     394        4344 :                 eyear = (eyear + 4 - dyear) & 7;
     395        4344 :                 edate = (eyear << 9) | (date_GetMonth(edate) << 5) | date_GetDay(edate);
     396             :         }
     397      104000 :         WriteFourBytes((edate << 20) | date);
     398             : 
     399             :         // Elo ratings and rating types: 2 bytes each.
     400      104000 :         uint16_t wElo = std::min(MAX_ELO, ie->GetWhiteElo());
     401      104000 :         wElo |= static_cast<uint16_t>(ie->GetWhiteRatingType()) << 12;
     402      104000 :         uint16_t bElo = std::min(MAX_ELO, ie->GetBlackElo());
     403      104000 :         bElo |= static_cast<uint16_t>(ie->GetBlackRatingType()) << 12;
     404      104000 :         WriteTwoBytes(wElo);
     405      104000 :         WriteTwoBytes(bElo);
     406             : 
     407      104000 :         ASSERT(ie->GetFinalMatSig() < (1ULL << 24));
     408      104000 :         ASSERT(ie->GetStoredLineCode() < (1ULL << 8));
     409      104000 :         uint32_t FinalMatSig = ie->GetFinalMatSig();
     410      104000 :         FinalMatSig |= static_cast<uint32_t>(ie->GetStoredLineCode()) << 24;
     411      104000 :         WriteFourBytes(FinalMatSig);
     412             : 
     413             :         // The first byte of HomePawnData has high bits of the NumHalfMoves
     414             :         // counter in its top two bits:
     415      104000 :         uint16_t nMoves = ie->GetNumHalfMoves();
     416      104000 :         ASSERT(nMoves < (1ULL << 10));
     417      104000 :         WriteOneByte(static_cast<uint8_t>(nMoves));
     418      104000 :         uint8_t pawnData0 = static_cast<uint8_t>(nMoves >> 8) << 6;
     419             : 
     420             :         // Write the 9-byte homePawnData array:
     421      104000 :         const byte* pb = ie->GetHomePawnData();
     422      104000 :         pawnData0 |= *pb & 0x3F;
     423      104000 :         WriteOneByte(pawnData0);
     424      104000 :         std::copy(pb + 1, pb + HPSIG_SIZE, buf_it);
     425             : 
     426      104000 :         return file->sputn(buf, INDEX_ENTRY_SIZE) == INDEX_ENTRY_SIZE
     427      104000 :                    ? OK
     428      104000 :                    : ERROR_FileWrite;
     429             : }
     430             : 
     431       33129 : inline byte IndexEntry::GetRating(const NameBase* nb) const {
     432       33129 :     eloT welo = GetWhiteElo();
     433       33129 :     eloT belo = GetBlackElo();
     434       33129 :     if (welo == 0) { welo = nb->GetElo (GetWhite()); }
     435       33129 :     if (belo == 0) { belo = nb->GetElo (GetBlack()); }
     436       33129 :     int rating = static_cast<int>(welo + belo) / 140;
     437             : 
     438             :     // Bonus for comments or Nags
     439       33129 :     if (GetCommentCount() > 2 || GetNagCount() > 2) {
     440          47 :         if (rating < 21) { // Missing elo
     441           0 :             rating = 40;
     442             :         } else {
     443          47 :             rating += 6;
     444             :         }
     445             :     }
     446             : 
     447             :     // Early draw penalty
     448       33129 :     if (GetResult() == RESULT_Draw) {
     449       13204 :         uint moves = GetNumHalfMoves();
     450       13204 :         if (moves < 80) {
     451        7471 :             rating -= 3;
     452        7471 :             if (moves < 60) {
     453        5088 :                 rating -= 2;
     454        5088 :                 if (moves < 40) rating -= 2;
     455             :             }
     456             :         }
     457             :     }
     458             : 
     459       33129 :     if (rating < 0) return 0;
     460       33074 :     else return static_cast<byte> (rating);
     461             : }
     462             : 
     463             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     464             : // IndexEntry::CharToFlag():
     465             : //    Returns the flag number corresponding to the given character.
     466             : inline uint
     467             : IndexEntry::CharToFlag (char ch)
     468             : {
     469             :     uint flag = 0;
     470             :     switch (toupper(ch)) {
     471             :         case 'D': flag = IDX_FLAG_DELETE;     break;
     472             :         case 'W': flag = IDX_FLAG_WHITE_OP;   break;
     473             :         case 'B': flag = IDX_FLAG_BLACK_OP;   break;
     474             :         case 'M': flag = IDX_FLAG_MIDDLEGAME; break;
     475             :         case 'E': flag = IDX_FLAG_ENDGAME;    break;
     476             :         case 'N': flag = IDX_FLAG_NOVELTY;    break;
     477             :         case 'P': flag = IDX_FLAG_PAWN;       break;
     478             :         case 'T': flag = IDX_FLAG_TACTICS;    break;
     479             :         case 'K': flag = IDX_FLAG_KSIDE;      break;
     480             :         case 'Q': flag = IDX_FLAG_QSIDE;      break;
     481             :         case '!': flag = IDX_FLAG_BRILLIANCY; break;
     482             :         case '?': flag = IDX_FLAG_BLUNDER;    break;
     483             :         case 'U': flag = IDX_FLAG_USER;       break;
     484             :         case '1': flag = IDX_FLAG_CUSTOM1;    break;
     485             :         case '2': flag = IDX_FLAG_CUSTOM2;    break;
     486             :         case '3': flag = IDX_FLAG_CUSTOM3;    break;
     487             :         case '4': flag = IDX_FLAG_CUSTOM4;    break;
     488             :         case '5': flag = IDX_FLAG_CUSTOM5;    break;
     489             :         case '6': flag = IDX_FLAG_CUSTOM6;    break;
     490             :     }
     491             :     return flag;
     492             : }
     493             : 
     494             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     495             : // IndexEntry::CharToFlagMask():
     496             : //    Transform a char in a mask that can be used with GetFlag() and SetFlag()
     497       19000 : inline uint32_t IndexEntry::CharToFlagMask(char flag)
     498             : {
     499       19000 :     switch (toupper(flag)) {
     500           0 :         case 'S': return 1 << IDX_FLAG_START;
     501           0 :         case 'X': return 1 << IDX_FLAG_PROMO;
     502           0 :         case 'Y': return 1 << IDX_FLAG_UPROMO;
     503        1000 :         case 'D': return 1 << IDX_FLAG_DELETE;
     504        1000 :         case 'W': return 1 << IDX_FLAG_WHITE_OP;
     505        1000 :         case 'B': return 1 << IDX_FLAG_BLACK_OP;
     506        1000 :         case 'M': return 1 << IDX_FLAG_MIDDLEGAME;
     507        1000 :         case 'E': return 1 << IDX_FLAG_ENDGAME;
     508        1000 :         case 'N': return 1 << IDX_FLAG_NOVELTY;
     509        1000 :         case 'P': return 1 << IDX_FLAG_PAWN;
     510        1000 :         case 'T': return 1 << IDX_FLAG_TACTICS;
     511        1000 :         case 'K': return 1 << IDX_FLAG_KSIDE;
     512        1000 :         case 'Q': return 1 << IDX_FLAG_QSIDE;
     513        1000 :         case '!': return 1 << IDX_FLAG_BRILLIANCY;
     514        1000 :         case '?': return 1 << IDX_FLAG_BLUNDER;
     515        1000 :         case 'U': return 1 << IDX_FLAG_USER;
     516        1000 :         case '1': return 1 << IDX_FLAG_CUSTOM1;
     517        1000 :         case '2': return 1 << IDX_FLAG_CUSTOM2;
     518        1000 :         case '3': return 1 << IDX_FLAG_CUSTOM3;
     519        1000 :         case '4': return 1 << IDX_FLAG_CUSTOM4;
     520        1000 :         case '5': return 1 << IDX_FLAG_CUSTOM5;
     521        1000 :         case '6': return 1 << IDX_FLAG_CUSTOM6;
     522             :     }
     523             : 
     524           0 :     ASSERT(0);
     525             :     return 0;
     526             : }
     527             : 
     528             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     529             : // IndexEntry::StrToFlagMask():
     530             : //    Transform a string in a mask that can be used with GetFlag() and SetFlag()
     531        9015 : inline uint32_t IndexEntry::StrToFlagMask(const char* flags)
     532             : {
     533        9015 :     if (flags == 0) return 0;
     534             : 
     535        9015 :     uint32_t res = 0;
     536        9015 :     while (*flags != 0) {
     537           0 :         res |= IndexEntry::CharToFlagMask(*(flags++));
     538             :     }
     539        9015 :     return res;
     540             : }
     541             : 
     542             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     543             : // IndexEntry::GetFlagStr():
     544             : //    Fills in the provided flag string with information on the
     545             : //    user-settable flags set for this game.
     546             : //    Returns the number of specified flags that are turned on.
     547             : inline uint
     548        1000 : IndexEntry::GetFlagStr(char* dest, const char* flags) const
     549             : {
     550        1000 :     if (flags == NULL) { flags = "DWBMENPTKQ!?U123456"; }
     551        1000 :     uint count = 0;
     552       39000 :     while (*flags != 0) {
     553       19000 :         uint32_t mask = CharToFlagMask(*flags);
     554       19000 :         ASSERT(mask != 0);
     555       19000 :         if (GetFlag(mask)) {
     556           0 :             *dest++ = *flags;
     557           0 :             count++;
     558             :         }
     559       19000 :         flags++;
     560             :     }
     561        1000 :     *dest = 0;
     562        1000 :     return count;
     563             : }
     564             : 
     565             : #endif

Generated by: LCOV version 1.13