LCOV - code coverage report
Current view: top level - src - indexentry.h (source / functions) Hit Total Coverage
Test: test_coverage.info Lines: 297 305 97.4 %
Date: 2017-06-21 14:32:49 Functions: 13 13 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  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 "matsig.h"
      26             : #include "namebase.h"
      27             : 
      28             : // Length is encoded as 17bits uint
      29             : #define MAX_GAME_LENGTH 131072
      30             : 
      31             : // HPSIG_SIZE = size of HomePawnData array in an IndexEntry.
      32             : // It is nine bytes: the first byte contains the number of valid entries
      33             : // in the array, and the next 8 bytes contain up to 16 half-byte entries.
      34             : const uint HPSIG_SIZE = 9;
      35             : 
      36             : const uint MAX_ELO = 4000; // Since we store Elo Ratings in 12 bits
      37             : 
      38             : const byte CUSTOM_FLAG_MASK[] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5 };
      39             : 
      40             : // Total on-disk size per index entry: currently 47 bytes.
      41             : const uint  INDEX_ENTRY_SIZE = 47;
      42             : const uint  OLD_INDEX_ENTRY_SIZE = 46;
      43             : 
      44             : 
      45             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      46             : // Class IndexEntry: one of these per game in the index file.
      47             : //
      48             : //    It contains more than just the location of the game data in the main
      49             : //    data file.  For fast searching, it also store some other important
      50             : //    values: players, event, site, date, result, eco, gamelength.
      51             : //
      52             : //    It takes 48 bytes, assuming sizeof(uint) == 4 and sizeof(ushort) == 2.
      53             : 
      54             : class IndexEntry
      55             : {
      56             :     uint32_t  Offset;            // Start of gamefile record for this game.
      57             :     uint16_t  Length_Low;        // Length of gamefile record for this game. 17 bits are used so the max
      58             :                                  // length is 128 ko (131071). So 7 bits are usable for custom flags or other.
      59             :     byte      Length_High;       // LxFFFFFF ( L = length for long games, x = spare, F = custom flags)
      60             :     // Name ID values are packed into 12 bytes, saving 8 bytes over the
      61             :     // simpler method of just storing each as a 4-byte idNumberT.
      62             :     byte      WhiteBlack_High;   // High bits of White, Black.
      63             :     uint16_t  WhiteID_Low;       // Lower 16 bits of White ID.
      64             :     uint16_t  BlackID_Low;       // Lower 16 bits of Black ID.
      65             :     uint16_t  EventID_Low;       // Lower 16 bits of Site.
      66             :     uint16_t  SiteID_Low;        // Lower 16 bits of Site ID.
      67             :     uint16_t  RoundID_Low;       // Lower 16 bits of Round ID.
      68             :     uint16_t  Flags;
      69             :     uint16_t  VarCounts;         // Counters for comments, variations, etc.
      70             :                                  // VarCounts also stores the result.
      71             :     ecoT      EcoCode;           // ECO code
      72             :     dateT     Dates;             // Date and EventDate fields.
      73             :     eloT      WhiteElo;
      74             :     eloT      BlackElo;
      75             :     matSigT   FinalMatSig;       // material of the final position in the game,
      76             :                                  // and the StoredLineCode in the top 8 bits.
      77             :     uint16_t  NumHalfMoves;
      78             :     byte      HomePawnData [HPSIG_SIZE];  // homePawnSig data.
      79             :     byte      EventSiteRnd_High; // High bits of Event, Site, Round.
      80             :     
      81             : public:
      82             :     void Init();
      83             :     template <class T> errorT Read (T* file, versionT version);
      84             :     template <class T> errorT Write (T* file, versionT version) const;
      85             : 
      86             : 
      87             :     uint32_t GetOffset () const { return Offset; }
      88       16012 :     void SetOffset (uint32_t offset) { Offset = offset; }
      89             :     uint32_t GetLength() const {
      90       48062 :         return Length_Low + (uint32_t(Length_High & 0x80) << 9);
      91             :     }
      92       16012 :     void SetLength (size_t length) {
      93       16012 :         ASSERT(length < MAX_GAME_LENGTH);
      94       16012 :         Length_Low = static_cast<uint16_t>(length & 0xFFFF);
      95             :         // preserve the last 7 bits
      96       16012 :         Length_High = ( Length_High & 0x7F ) | static_cast<byte>( (length >> 16) << 7 );
      97       16012 :     }
      98             : 
      99             : 
     100             :     // Name Get and Set routines:
     101             :     //   WhiteID and BlackID are 20-bit values, EventID and SiteID are
     102             :     //   19-bit values, and RoundID is an 18-bit value.
     103             :     //
     104             :     //   WhiteID high 4 bits = bits 4-7 of WhiteBlack_High.
     105             :     //   BlackID high 4 bits = bits 0-3 of WhiteBlack_High.
     106             :     //   EventID high 3 bits = bits 5-7 of EventSiteRnd_high.
     107             :     //   SiteID  high 3 bits = bits 2-4 of EventSiteRnd_high.
     108             :     //   RoundID high 2 bits = bits 0-1 of EventSiteRnd_high.
     109             :     idNumberT GetWhite () const {
     110      223617 :         idNumberT id = (idNumberT) WhiteBlack_High;
     111      223617 :         id = id >> 4;  // High 4 bits = bits 4-7 of WhiteBlack_High.
     112      223617 :         id <<= 16;
     113      223617 :         id |= (idNumberT) WhiteID_Low;
     114             :         return id;
     115             :     }
     116             :     idNumberT GetBlack () const {
     117      307188 :         idNumberT id = (idNumberT) WhiteBlack_High;
     118      307188 :         id = id & 0xF;   // High 4 bits = bits 0-3 of WhiteBlack_High.
     119      307188 :         id <<= 16;
     120      307188 :         id |= (idNumberT) BlackID_Low;
     121             :         return id;
     122             :     }
     123             :     idNumberT GetPlayer(colorT col) const {
     124             :         if (col == BLACK) return GetBlack();
     125             :         return GetWhite();
     126             :     }
     127             :     idNumberT GetEvent () const {
     128      118301 :         uint id = (idNumberT) EventSiteRnd_High;
     129      118301 :         id >>= 5;  // High 3 bits = bits 5-7 of EventSiteRnd_High.
     130      118301 :         id <<= 16;
     131      118301 :         id |= (idNumberT) EventID_Low;
     132             :         return id;
     133             :     }
     134             :     idNumberT GetSite () const {
     135      339841 :         uint id = (idNumberT) EventSiteRnd_High;
     136      339841 :         id = (id >> 2) & 7;  // High 3 bits = bits 2-5 of EventSiteRnd_High.
     137      339841 :         id <<= 16;
     138      339841 :         id |= (idNumberT) SiteID_Low;
     139             :         return id;
     140             :     }
     141             :     idNumberT GetRound () const {
     142      213407 :         uint id = (idNumberT) EventSiteRnd_High;
     143      213407 :         id &= 3;   // High 2 bits = bits 0-1 of EventSiteRnd_High.
     144      213407 :         id <<= 16;
     145      213407 :         id |= (idNumberT) RoundID_Low;
     146             :         return id;
     147             :     }
     148             : 
     149             :     void SetWhite (idNumberT id) {
     150       16022 :         WhiteID_Low = id & 0xFFFF;
     151       16019 :         WhiteBlack_High = WhiteBlack_High & 0x0F;   // Clear bits 4-7.
     152       16021 :         WhiteBlack_High |= ((id >> 16) << 4);       // Set bits 4-7.
     153             :     }
     154             :     void SetBlack (idNumberT id) {
     155       16022 :         BlackID_Low = id & 0xFFFF;
     156       16019 :         WhiteBlack_High = WhiteBlack_High & 0xF0;   // Clear bits 0-3.
     157       16022 :         WhiteBlack_High |= (id >> 16);              // Set bits 0-3.
     158             :     }
     159             :     void SetPlayer (colorT col, idNumberT id) {
     160             :         if (col == BLACK) return SetBlack(id);
     161             :         return SetWhite(id);
     162             :     }
     163             :     void SetEvent (idNumberT id) {
     164       16023 :         EventID_Low = id & 0xFFFF;
     165             :         // Clear bits 2-4 of EventSiteRnd_high: 31 = 00011111 binary.
     166       16020 :         EventSiteRnd_High = EventSiteRnd_High & 31;
     167       16022 :         EventSiteRnd_High |= ((id >> 16) << 5);
     168             :     }
     169             :     void SetSite (idNumberT id) {
     170       16022 :         SiteID_Low = id & 0xFFFF;
     171             :         // Clear bits 2-4 of EventSiteRnd_high: 227 = 11100011 binary.
     172       16019 :         EventSiteRnd_High = EventSiteRnd_High & 227;
     173       16021 :         EventSiteRnd_High |= ((id >> 16) << 2);
     174             :     }
     175             :     void SetRound (idNumberT id) {
     176       16022 :         RoundID_Low = id & 0xFFFF;
     177             :         // Clear bits 0-1 of EventSiteRnd_high: 252 = 11111100 binary.
     178       16021 :         EventSiteRnd_High = EventSiteRnd_High & 252;
     179       16022 :         EventSiteRnd_High |= (id >> 16);
     180             :     }
     181             : 
     182             : 
     183             :     const char* GetWhiteName (const NameBase* nb) const {
     184       19077 :         return nb->GetName (NAME_PLAYER, GetWhite()); 
     185             :     }
     186             :     const char* GetBlackName (const NameBase* nb) const {
     187       15060 :         return nb->GetName (NAME_PLAYER, GetBlack());
     188             :     }
     189             :     const char* GetEventName (const NameBase* nb) const {
     190       23094 :         return nb->GetName (NAME_EVENT, GetEvent());
     191             :     }
     192             :     const char* GetSiteName (const NameBase* nb) const {
     193      624027 :         return nb->GetName (NAME_SITE, GetSite());
     194             :     }
     195             :     const char* GetRoundName (const NameBase* nb) const {
     196       15060 :         return nb->GetName (NAME_ROUND, GetRound());
     197             :     }
     198             : 
     199       16019 :     errorT SetWhiteName(NameBase* nb, const char* s) {
     200       16019 :         idNumberT id = 0;
     201       16019 :         errorT res = nb->AddName (NAME_PLAYER, s ? s : "?", &id);
     202       16019 :         if (res == OK) SetWhite (id);
     203       16019 :         return res;
     204             :     }
     205       16019 :     errorT SetBlackName(NameBase* nb, const char* s) {
     206       16019 :         idNumberT id = 0;
     207       16019 :         errorT res = nb->AddName (NAME_PLAYER, s ? s : "?", &id);
     208       16019 :         if (res == OK) SetBlack (id);
     209       16019 :         return res;
     210             :     }
     211       16019 :     errorT SetEventName(NameBase* nb, const char* s) {
     212       16019 :         idNumberT id = 0;
     213       16019 :         errorT res = nb->AddName (NAME_EVENT, s ? s : "?", &id);
     214       16019 :         if (res == OK) SetEvent (id);
     215       16019 :         return res;
     216             :     }
     217       16019 :     errorT SetSiteName(NameBase* nb, const char* s) {
     218       16019 :         idNumberT id = 0;
     219       16019 :         errorT res = nb->AddName (NAME_SITE, s ? s : "?", &id);
     220       16019 :         if (res == OK) SetSite (id);
     221       16019 :         return res;
     222             :     }
     223       16019 :     errorT SetRoundName(NameBase* nb, const char* s) {
     224       16019 :         idNumberT id = 0;
     225       16019 :         errorT res = nb->AddName (NAME_ROUND, s ? s : "?", &id);
     226       16019 :         if (res == OK) SetRound (id);
     227       16019 :         return res;
     228             :     }
     229             : 
     230             : 
     231      300872 :     dateT GetDate () const { return u32_low_20(Dates); }
     232      217704 :     uint  GetYear () const { return date_GetYear (GetDate()); }
     233             :     uint  GetMonth() const { return date_GetMonth (GetDate()); }
     234             :     uint  GetDay ()  const { return date_GetDay (GetDate()); }
     235             :     dateT GetEventDate () const {
     236      255215 :         uint dyear = date_GetYear (GetDate());
     237      171036 :         dateT edate = u32_high_12 (Dates);
     238       85518 :         uint month = date_GetMonth (edate);
     239       85518 :         uint day = date_GetDay (edate);
     240       85518 :         uint year = date_GetYear(edate) & 7;
     241       85518 :         if (year == 0) { return ZERO_DATE; }
     242       20958 :         year = dyear + year - 4;
     243       20958 :         return DATE_MAKE (year, month, day);
     244             :     }
     245      684025 :     resultT GetResult () const { return (VarCounts >> 12); }
     246      153675 :     eloT GetWhiteElo () const { return u16_low_12(WhiteElo); }
     247             :     eloT GetWhiteElo (const NameBase* nb)  const {
     248      165866 :         eloT r = GetWhiteElo();
     249      109293 :         if (r == 0 && nb != 0) return nb->GetElo (GetWhite());
     250             :         return r;
     251             :     }
     252      256645 :     eloT GetBlackElo () const { return u16_low_12(BlackElo); }
     253             :     eloT GetBlackElo (const NameBase* nb) const {
     254      371806 :         eloT r = GetBlackElo();
     255      272369 :         if (r == 0 && nb != 0) return nb->GetElo (GetBlack());
     256             :         return r;
     257             :     }
     258             :     eloT GetElo(colorT col) const {
     259             :         if (col == BLACK) return GetBlackElo();
     260             :         return GetWhiteElo();
     261             :     }
     262        1008 :     byte   GetWhiteRatingType () const { return u16_high_4 (WhiteElo); }
     263        1008 :     byte   GetBlackRatingType () const { return u16_high_4 (BlackElo); }
     264             :     ecoT   GetEcoCode () const { return EcoCode; }
     265             :     ushort GetNumHalfMoves () const { return NumHalfMoves; }
     266             :     byte   GetRating(const NameBase* nb) const;
     267             : 
     268             :     void SetDate  (dateT date)   {
     269       38038 :         Dates = u32_set_low_20 (Dates, date);
     270             :     }
     271       11012 :     void SetEventDate (dateT edate) {
     272       27026 :         uint codedDate = date_GetMonth(edate) << 5;
     273       27026 :         codedDate |= date_GetDay (edate);
     274       27026 :         uint eyear = date_GetYear (edate);
     275       65064 :         uint dyear = date_GetYear (GetDate());
     276             :         // Due to a compact encoding format, the EventDate
     277             :         // must be within a few years of the Date.
     278       11012 :         if ((eyear + 3) < dyear  ||  eyear > (dyear + 3)) {
     279             :             codedDate = 0; 
     280             :         } else {
     281       27026 :             codedDate |= (((eyear + 4 - dyear) & 7) << 9);
     282             :         }
     283       54052 :         Dates = u32_set_high_12 (Dates, codedDate);
     284       11012 :     }
     285             :     void SetResult (resultT res) {
     286       11012 :         VarCounts = (VarCounts & 0x0FFF) | (((ushort)res) << 12);
     287             :     }
     288             :     void SetWhiteElo (eloT elo)  {
     289       22025 :         WhiteElo = u16_set_low_12(WhiteElo, elo);
     290             :     }
     291             :     void SetBlackElo (eloT elo)  {
     292       22025 :         BlackElo = u16_set_low_12 (BlackElo, elo);
     293             :     }
     294             :     void SetWhiteRatingType (byte b) {
     295       11012 :         WhiteElo = u16_set_high_4 (WhiteElo, b);
     296             :     }
     297             :     void SetBlackRatingType (byte b) {
     298       11012 :         BlackElo = u16_set_high_4 (BlackElo, b);
     299             :     }
     300       11012 :     void SetEcoCode (ecoT eco)   { EcoCode = eco; }
     301       11012 :     void SetNumHalfMoves (ushort b)  { NumHalfMoves = b; }
     302             : 
     303             : 
     304             :     bool GetFlag (uint32_t mask) const {
     305       20080 :         uint32_t tmp = Flags;
     306       20080 :         if ((mask & 0xFFFF0000) != 0) {
     307             :             // The if is not necessary but should be faster
     308        6294 :             tmp |= (Length_High & 0x3F) << 16;
     309             :         }
     310       20080 :         return (tmp & mask) == mask;
     311             :     }
     312             :     bool GetStartFlag () const      { return (Flags & (1 << IDX_FLAG_START)) != 0; }
     313             :     bool GetPromotionsFlag () const { return (Flags & (1 << IDX_FLAG_PROMO)) != 0; }
     314             :     bool GetUnderPromoFlag() const  { return (Flags & (1 << IDX_FLAG_UPROMO)) != 0; }
     315             :     bool GetCommentsFlag () const   { return (GetCommentCount() > 0); }
     316             :     bool GetVariationsFlag () const { return (GetVariationCount() > 0); }
     317             :     bool GetNagsFlag () const       { return (GetNagCount() > 0); }
     318      107790 :     bool GetDeleteFlag () const     { return (Flags & (1 << IDX_FLAG_DELETE)) != 0; }
     319             : 
     320             :     static uint CharToFlag (char ch);
     321             :     static uint32_t CharToFlagMask (char flag);
     322             :     static uint32_t StrToFlagMask (const char* flags);
     323             :     uint GetFlagStr(char* dest, const char* flags) const;
     324             : 
     325      512142 :     uint GetVariationCount () const { return DecodeCount(VarCounts & 15); }
     326      347878 :     uint GetCommentCount () const   { return DecodeCount((VarCounts >> 4) & 15); }
     327      203000 :     uint GetNagCount () const       { return DecodeCount((VarCounts >> 8) & 15); }
     328             : 
     329           8 :     matSigT GetFinalMatSig () const { return u32_low_24 (FinalMatSig); }
     330           8 :     byte GetStoredLineCode () const { return u32_high_8 (FinalMatSig); }
     331             :     const byte* GetHomePawnData () const { return HomePawnData; }
     332       11009 :     byte* GetHomePawnData () { return HomePawnData; }
     333             : 
     334          44 :     void SetFlag (uint32_t flagMask, bool b) {
     335       55093 :         uint16_t flagLow = flagMask & 0xFFFF;
     336       11055 :         if (flagLow != 0) {
     337       33059 :             if (b) { 
     338       16181 :                 Flags |= flagLow;
     339             :             } else {
     340       16882 :                 Flags &= ~flagLow;
     341             :             }
     342             :         }
     343             : 
     344       55093 :         byte flagHigh = (flagMask >> 16) & 0x3F;
     345       11055 :         if (flagHigh != 0) {
     346          12 :             if (b) {
     347           7 :                 Length_High |= flagHigh;
     348             :             } else {
     349       11016 :                 Length_High &= ~flagHigh;
     350             :             }
     351             :         }
     352          44 :     }
     353       22018 :     void SetStartFlag (bool b)      { SetFlag(1 << IDX_FLAG_START, b); }
     354       22018 :     void SetPromotionsFlag (bool b) { SetFlag(1 << IDX_FLAG_PROMO, b); }
     355       22018 :     void SetUnderPromoFlag (bool b) { SetFlag(1 << IDX_FLAG_UPROMO, b); }
     356             :     void SetDeleteFlag (bool b)     { SetFlag(1 << IDX_FLAG_DELETE, b); }
     357       11010 :     void clearFlags() { return SetFlag(IDX_MASK_ALLFLAGS, false); }
     358             : 
     359             :     void SetVariationCount (uint x) {
     360       22023 :         VarCounts = (VarCounts & 0xFFF0U) | EncodeCount(x);
     361             :     }
     362             :     void SetCommentCount (uint x) {
     363       22023 :         VarCounts = (VarCounts & 0xFF0FU) | (EncodeCount(x) << 4);
     364             :     }
     365             :     void SetNagCount (uint x) {
     366       22023 :         VarCounts = (VarCounts & 0xF0FFU) | (EncodeCount(x) << 8);
     367             :     }
     368             : 
     369             :     void SetFinalMatSig (matSigT ms) {
     370       38038 :         FinalMatSig = u32_set_low_24 (FinalMatSig, ms);
     371             :     }
     372             :     void SetStoredLineCode (byte b)    {
     373       22024 :         FinalMatSig = u32_set_high_8 (FinalMatSig, b);
     374             :     }
     375             : 
     376             :     enum {
     377             :         // IndexEntry Flag types:
     378             :         IDX_FLAG_START      =  0,   // Game has own start position.
     379             :         IDX_FLAG_PROMO      =  1,   // Game contains promotion(s).
     380             :         IDX_FLAG_UPROMO     =  2,   // Game contains promotion(s).
     381             :         IDX_FLAG_DELETE     =  3,   // Game marked for deletion.
     382             :         IDX_FLAG_WHITE_OP   =  4,   // White openings flag.
     383             :         IDX_FLAG_BLACK_OP   =  5,   // Black openings flag.
     384             :         IDX_FLAG_MIDDLEGAME =  6,   // Middlegames flag.
     385             :         IDX_FLAG_ENDGAME    =  7,   // Endgames flag.
     386             :         IDX_FLAG_NOVELTY    =  8,   // Novelty flag.
     387             :         IDX_FLAG_PAWN       =  9,   // Pawn structure flag.
     388             :         IDX_FLAG_TACTICS    = 10,   // Tactics flag.
     389             :         IDX_FLAG_KSIDE      = 11,   // Kingside play flag.
     390             :         IDX_FLAG_QSIDE      = 12,   // Queenside play flag.
     391             :         IDX_FLAG_BRILLIANCY = 13,   // Brilliancy or good play.
     392             :         IDX_FLAG_BLUNDER    = 14,   // Blunder or bad play.
     393             :         IDX_FLAG_USER       = 15,   // User-defined flag.
     394             :         IDX_FLAG_CUSTOM1    = 16,   // Custom flag.
     395             :         IDX_FLAG_CUSTOM2    = 17,   // Custom flag.
     396             :         IDX_FLAG_CUSTOM3    = 18,   // Custom flag.
     397             :         IDX_FLAG_CUSTOM4    = 19,   // Custom flag.
     398             :         IDX_FLAG_CUSTOM5    = 20,   // Custom flag.
     399             :         IDX_FLAG_CUSTOM6    = 21,   // Custom flag.
     400             :         IDX_NUM_FLAGS       = 22,
     401             :     };
     402             :     static const uint32_t IDX_MASK_ALLFLAGS = 0xFFFFFFFF;
     403             : 
     404             : private:
     405             :     static uint EncodeCount (uint x) {
     406       33033 :         if (x <= 10) { return x; }
     407       21336 :         if (x <= 12) { return 10; }
     408       21224 :         if (x <= 17) { return 11; }  // 11 indicates 15 (13-17)
     409       20855 :         if (x <= 24) { return 12; }  // 12 indicates 20 (18-24)
     410       20374 :         if (x <= 34) { return 13; }  // 13 indicates 30 (25-34)
     411       19753 :         if (x <= 44) { return 14; }  // 14 indicates 40 (35-44)
     412             :         return 15;                   // 15 indicates 50 or more
     413             :     }
     414             :     static uint DecodeCount (uint x) {
     415             :         static uint countCodes[16] = {0,1,2,3,4,5,6,7,8,9,10,15,20,30,40,50};
     416      531510 :         return countCodes[x & 15];
     417             :     }
     418             : 
     419             : // Bitmask functions for index entry decoding:
     420             :     static byte u32_high_8( uint x )
     421             :     {
     422           4 :         return (byte)(x >> 24);
     423             :     }
     424             : 
     425             :     static uint u32_low_24( uint x )
     426             :     {
     427       11015 :         return x & 0x00FFFFFF;
     428             :     }
     429             : 
     430             :     static uint u32_high_12( uint x )
     431             :     {
     432       85518 :         return x >> 20;
     433             :     }
     434             : 
     435             :     static uint u32_low_20( uint x )
     436             :     {
     437       63386 :         return x & 0x000FFFFF;
     438             :     }
     439             : 
     440             :     static byte u16_high_4( ushort x )
     441             :     {
     442           8 :         return (byte)(x >> 12);
     443             :     }
     444             : 
     445             :     static ushort u16_low_12( ushort x )
     446             :     {
     447      429664 :         return x & 0x0FFF;
     448             :     }
     449             : 
     450             :     static uint u32_set_high_8( uint u, byte x )
     451             :     {
     452       11012 :         return u32_low_24(u) | ((uint)x << 24);
     453             :     }
     454             : 
     455             :     static uint u32_set_low_24( uint u, uint x )
     456             :     {
     457       11012 :         return (u & 0xFF000000) | (x & 0x00FFFFFF);
     458             :     }
     459             : 
     460             :     static uint u32_set_high_12( uint u, uint x )
     461             :     {
     462       27026 :         return u32_low_20(u) | (x << 20);
     463             :     }
     464             : 
     465             :     static uint u32_set_low_20( uint u, uint x )
     466             :     {
     467       11012 :         return (u & 0xFFF00000) | (x & 0x000FFFFF);
     468             :     }
     469             : 
     470             :     static ushort u16_set_high_4( ushort u, byte x )
     471             :     {
     472       22024 :         return u16_low_12(u) | ((ushort)x << 12);
     473             :     }
     474             : 
     475             :     static ushort u16_set_low_12( ushort u, ushort x )
     476             :     {
     477       22026 :         return (u & 0xF000) | (x & 0x0FFF);
     478             :     }
     479             : };
     480             : 
     481             : 
     482             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     483             : // IndexEntry::Init():
     484             : //        Initialise a single index entry.
     485             : //
     486             : inline void
     487             : IndexEntry::Init ()
     488             : {
     489       16014 :     NumHalfMoves = 0;
     490       16014 :     WhiteID_Low = 0;
     491       16014 :     BlackID_Low = 0;
     492       16014 :     EventID_Low = 0;
     493       16014 :     SiteID_Low = 0;
     494       16014 :     RoundID_Low = 0;
     495       16014 :     WhiteBlack_High = 0;
     496       16014 :     EventSiteRnd_High = 0;
     497       16014 :     EcoCode = 0;
     498             :     Dates = 0;
     499       16014 :     WhiteElo = 0;
     500       16014 :     BlackElo = 0;
     501       16014 :     FinalMatSig = 0;
     502       16014 :     Flags = 0;
     503       16014 :     VarCounts = 0;
     504       16014 :     Offset = 0;
     505       16014 :     Length_Low = 0;
     506       16014 :     Length_High = 0;
     507       32028 :     SetDate (ZERO_DATE);
     508       16014 :     SetEventDate (ZERO_DATE);
     509       16014 :     SetResult (RESULT_None);
     510       16014 :     SetEcoCode (ECO_None);
     511       32028 :     SetFinalMatSig (MATSIG_Empty);
     512      160140 :     for (uint i=0; i < HPSIG_SIZE; i++) {
     513      144126 :         HomePawnData[i] = 0;
     514             :     }
     515             : }
     516             : 
     517             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     518             : // IndexEntry::Read():
     519             : //      Reads a single entry's values from an open index file.
     520             : //
     521             : template <class T> errorT
     522        5343 : IndexEntry::Read (T* file, versionT version)
     523             : {
     524             :     // Length of each gamefile record and its offset.
     525        5343 :     Offset = file->ReadFourBytes ();
     526        5343 :     Length_Low = file->ReadTwoBytes ();
     527       10686 :     Length_High = (version < 400) ? 0 : file->ReadOneByte();
     528        5343 :     Flags = file->ReadTwoBytes (); 
     529             : 
     530             :     // White and Black player names:
     531        5343 :     WhiteBlack_High = file->ReadOneByte ();
     532        5343 :     WhiteID_Low = file->ReadTwoBytes ();
     533        5343 :     BlackID_Low = file->ReadTwoBytes ();
     534             : 
     535             :     // Event, Site and Round names:
     536        5343 :     EventSiteRnd_High = file->ReadOneByte ();
     537        5343 :     EventID_Low = file->ReadTwoBytes ();
     538        5343 :     SiteID_Low = file->ReadTwoBytes ();
     539        5343 :     RoundID_Low = file->ReadTwoBytes ();
     540             : 
     541        5343 :     VarCounts = file->ReadTwoBytes();
     542        5343 :     EcoCode = file->ReadTwoBytes ();
     543             : 
     544             :     // Date and EventDate are stored in four bytes.
     545        5343 :     Dates = file->ReadFourBytes();
     546             : 
     547             :     // The two ELO ratings and rating types take 2 bytes each.
     548        5343 :     WhiteElo = file->ReadTwoBytes ();
     549        5343 :     BlackElo = file->ReadTwoBytes ();
     550       10686 :     if (GetWhiteElo() > MAX_ELO) { SetWhiteElo(MAX_ELO); }
     551       10686 :     if (GetBlackElo() > MAX_ELO) { SetBlackElo(MAX_ELO); }
     552             : 
     553        5343 :     FinalMatSig = file->ReadFourBytes ();
     554        5343 :     NumHalfMoves = file->ReadOneByte ();
     555             : 
     556             :     // Read the 9-byte homePawnData array:
     557        5343 :     byte * pb = HomePawnData;
     558             :     // The first byte of HomePawnData has high bits of the NumHalfMoves
     559             :     // counter in its top two bits:
     560        5343 :     uint pb0 = file->ReadOneByte();
     561        5343 :     *pb = (pb0 & 63);
     562        5343 :     pb++;
     563        5343 :     NumHalfMoves = NumHalfMoves | ((pb0 >> 6) << 8);
     564       48087 :     for (uint i2 = 1; i2 < HPSIG_SIZE; i2++) {
     565       42744 :         *pb = file->ReadOneByte ();
     566       42744 :         pb++;
     567             :     }
     568             : 
     569             :     // Top 2 bits of HomePawnData[0] are for NumHalfMoves:
     570        5343 :     uint numMoves_High = HomePawnData[0];
     571        5343 :     HomePawnData[0] = HomePawnData[0] & 63;
     572        5343 :     numMoves_High >>= 6;
     573        5343 :     numMoves_High <<= 8;
     574        5343 :     NumHalfMoves = NumHalfMoves | numMoves_High;
     575             : 
     576        5343 :     return OK;
     577             : }
     578             : 
     579             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     580             : // IndexEntry::Write():
     581             : //      Writes a single index entry to an open index file.
     582             : //      INDEX_ENTRY_SIZE must be updated
     583             : template <class T> errorT
     584        6004 : IndexEntry::Write (T* file, versionT version) const
     585             : {
     586             :     // Cannot write old-version index files:
     587        6004 :     if (version < 400) { return ERROR_FileVersion; }
     588             : 
     589        6004 :     version = 0;  // We don't have any version-specific code.
     590             :     
     591        6004 :     file->WriteFourBytes (Offset);
     592             :     
     593        6004 :     file->WriteTwoBytes (Length_Low);
     594       12008 :     file->WriteOneByte (Length_High);
     595        6004 :     file->WriteTwoBytes (Flags);
     596             : 
     597       12008 :     file->WriteOneByte (WhiteBlack_High);
     598        6004 :     file->WriteTwoBytes (WhiteID_Low);
     599        6004 :     file->WriteTwoBytes (BlackID_Low);
     600             : 
     601       12008 :     file->WriteOneByte (EventSiteRnd_High);
     602        6004 :     file->WriteTwoBytes (EventID_Low);
     603        6004 :     file->WriteTwoBytes (SiteID_Low);
     604        6004 :     file->WriteTwoBytes (RoundID_Low);
     605             : 
     606        6004 :     file->WriteTwoBytes (VarCounts);
     607        6004 :     file->WriteTwoBytes (EcoCode);
     608        6004 :     file->WriteFourBytes (Dates);
     609             : 
     610             :     // Elo ratings and rating types: 2 bytes each.
     611        6004 :     file->WriteTwoBytes (WhiteElo);
     612        6004 :     file->WriteTwoBytes (BlackElo);
     613             : 
     614        6004 :     file->WriteFourBytes (FinalMatSig);
     615       12008 :     file->WriteOneByte (NumHalfMoves & 255); 
     616             : 
     617             :     // Write the 9-byte homePawnData array:
     618        6004 :     const byte* pb = HomePawnData;
     619             :     // The first byte of HomePawnData has high bits of the NumHalfMoves
     620             :     // counter in its top two bits:
     621        6004 :     byte pb0 = *pb;
     622        6004 :     pb0 = pb0 | ((NumHalfMoves >> 8) << 6);
     623       12008 :     file->WriteOneByte (pb0);
     624        6004 :     pb++;
     625             :     // write 8 bytes
     626       54036 :     for (uint i2 = 1; i2 < HPSIG_SIZE; i2++) {
     627       96064 :         file->WriteOneByte (*pb);
     628       48032 :         pb++;
     629             :     }
     630             : 
     631             :     return OK;
     632             : }
     633             : 
     634       48040 : inline byte IndexEntry::GetRating(const NameBase* nb) const {
     635       96080 :     eloT welo = GetWhiteElo();
     636       96080 :     eloT belo = GetBlackElo();
     637       55728 :     if (welo == 0) { welo = nb->GetElo (GetWhite()); }
     638       69276 :     if (belo == 0) { belo = nb->GetElo (GetBlack()); }
     639       48040 :     int rating = static_cast<int>(welo + belo) / 140;
     640             : 
     641             :     // Bonus for comments or Nags
     642      144057 :     if (GetCommentCount() > 2 || GetNagCount() > 2) {
     643          64 :         if (rating < 21) { // Missing elo
     644             :             rating = 40;
     645             :         } else {
     646          64 :             rating += 6;
     647             :         }
     648             :     }
     649             : 
     650             :     // Early draw penalty
     651       96080 :     if (GetResult() == RESULT_Draw) {
     652       18480 :         uint moves = GetNumHalfMoves();
     653       18480 :         if (moves < 80) {
     654       10291 :             rating -= 3;
     655       10291 :             if (moves < 60) {
     656        6938 :                 rating -= 2;
     657        6938 :                 if (moves < 40) rating -= 2;
     658             :             }
     659             :         }
     660             :     }
     661             : 
     662       48040 :     if (rating < 0) return 0;
     663       47983 :     else return static_cast<byte> (rating);
     664             : }
     665             : 
     666             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     667             : // IndexEntry::CharToFlag():
     668             : //    Returns the flag number corresponding to the given character.
     669             : inline uint
     670             : IndexEntry::CharToFlag (char ch)
     671             : {
     672           0 :     uint flag = 0;
     673           0 :     switch (toupper(ch)) {
     674             :         case 'D': flag = IDX_FLAG_DELETE;     break;
     675             :         case 'W': flag = IDX_FLAG_WHITE_OP;   break;
     676             :         case 'B': flag = IDX_FLAG_BLACK_OP;   break;
     677             :         case 'M': flag = IDX_FLAG_MIDDLEGAME; break;
     678             :         case 'E': flag = IDX_FLAG_ENDGAME;    break;
     679             :         case 'N': flag = IDX_FLAG_NOVELTY;    break;
     680             :         case 'P': flag = IDX_FLAG_PAWN;       break;
     681             :         case 'T': flag = IDX_FLAG_TACTICS;    break;
     682             :         case 'K': flag = IDX_FLAG_KSIDE;      break;
     683             :         case 'Q': flag = IDX_FLAG_QSIDE;      break;
     684             :         case '!': flag = IDX_FLAG_BRILLIANCY; break;
     685             :         case '?': flag = IDX_FLAG_BLUNDER;    break;
     686             :         case 'U': flag = IDX_FLAG_USER;       break;
     687             :         case '1': flag = IDX_FLAG_CUSTOM1;    break;
     688             :         case '2': flag = IDX_FLAG_CUSTOM2;    break;
     689             :         case '3': flag = IDX_FLAG_CUSTOM3;    break;
     690             :         case '4': flag = IDX_FLAG_CUSTOM4;    break;
     691             :         case '5': flag = IDX_FLAG_CUSTOM5;    break;
     692             :         case '6': flag = IDX_FLAG_CUSTOM6;    break;
     693             :     }
     694             :     return flag;
     695             : }
     696             : 
     697             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     698             : // IndexEntry::CharToFlagMask():
     699             : //    Transform a char in a mask that can be used with GetFlag() and SetFlag()
     700       19000 : inline uint32_t IndexEntry::CharToFlagMask(char flag)
     701             : {
     702       19000 :     switch (toupper(flag)) {
     703             :         case 'S': return 1 << IDX_FLAG_START;
     704           0 :         case 'X': return 1 << IDX_FLAG_PROMO;
     705           0 :         case 'Y': return 1 << IDX_FLAG_UPROMO;
     706        1000 :         case 'D': return 1 << IDX_FLAG_DELETE;
     707        1000 :         case 'W': return 1 << IDX_FLAG_WHITE_OP;
     708        1000 :         case 'B': return 1 << IDX_FLAG_BLACK_OP;
     709        1000 :         case 'M': return 1 << IDX_FLAG_MIDDLEGAME;
     710        1000 :         case 'E': return 1 << IDX_FLAG_ENDGAME;
     711        1000 :         case 'N': return 1 << IDX_FLAG_NOVELTY;
     712        1000 :         case 'P': return 1 << IDX_FLAG_PAWN;
     713        1000 :         case 'T': return 1 << IDX_FLAG_TACTICS;
     714        1000 :         case 'K': return 1 << IDX_FLAG_KSIDE;
     715        1000 :         case 'Q': return 1 << IDX_FLAG_QSIDE;
     716        1000 :         case '!': return 1 << IDX_FLAG_BRILLIANCY;
     717        1000 :         case '?': return 1 << IDX_FLAG_BLUNDER;
     718        1000 :         case 'U': return 1 << IDX_FLAG_USER;
     719        1000 :         case '1': return 1 << IDX_FLAG_CUSTOM1;
     720        1000 :         case '2': return 1 << IDX_FLAG_CUSTOM2;
     721        1000 :         case '3': return 1 << IDX_FLAG_CUSTOM3;
     722        1000 :         case '4': return 1 << IDX_FLAG_CUSTOM4;
     723        1000 :         case '5': return 1 << IDX_FLAG_CUSTOM5;
     724        1000 :         case '6': return 1 << IDX_FLAG_CUSTOM6;
     725             :     }
     726             : 
     727           0 :     ASSERT(0);
     728             :     return 0;
     729             : }
     730             : 
     731             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     732             : // IndexEntry::StrToFlagMask():
     733             : //    Transform a string in a mask that can be used with GetFlag() and SetFlag()
     734             : inline uint32_t IndexEntry::StrToFlagMask(const char* flags)
     735             : {
     736       11009 :     if (flags == 0) return 0;
     737             : 
     738             :     uint32_t res = 0;
     739       11009 :     while (*flags != 0) {
     740           0 :         res |= IndexEntry::CharToFlagMask(*(flags++));
     741             :     }
     742             :     return res;
     743             : }
     744             : 
     745             : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     746             : // IndexEntry::GetFlagStr():
     747             : //    Fills in the provided flag string with information on the
     748             : //    user-settable flags set for this game.
     749             : //    Returns the number of specified flags that are turned on.
     750             : inline uint
     751        1000 : IndexEntry::GetFlagStr(char* dest, const char* flags) const
     752             : {
     753        1000 :     if (flags == NULL) { flags = "DWBMENPTKQ!?U123456"; }
     754             :     uint count = 0;
     755       39000 :     while (*flags != 0) {
     756       19000 :         uint32_t mask = CharToFlagMask(*flags);
     757       19000 :         ASSERT(mask != 0);
     758       38000 :         if (GetFlag(mask)) {
     759           0 :             *dest++ = *flags;
     760           0 :             count++;
     761             :         }
     762       19000 :         flags++;
     763             :     }
     764        1000 :     *dest = 0;
     765        1000 :     return count;
     766             : }
     767             : 
     768             : #endif

Generated by: LCOV version 1.12