LCOV - code coverage report
Current view: top level - src - index.h (source / functions) Hit Total Coverage
Test: test_coverage.info Lines: 55 64 85.9 %
Date: 2017-06-21 14:32:49 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*
       2             : * Copyright (c) 1999-2002  Shane Hudson
       3             : * Copyright (c) 2006-2009  Pascal Georges
       4             : * Copyright (C) 2014-2016  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_INDEX_H
      22             : #define SCID_INDEX_H
      23             : 
      24             : #include "common.h"
      25             : #include "date.h"
      26             : #include "indexentry.h"
      27             : #include "filebuf.h"
      28             : #include "hfilter.h"
      29             : #include <string>
      30             : #include <vector>
      31             : #include <cstring>
      32             : 
      33             : class NameBase;
      34             : 
      35             : //////////////////////////////////////////////////////////////////////
      36             : //  Index:  Constants
      37             : 
      38             : const char         INDEX_SUFFIX[]     = ".si4";
      39             : const char         OLD_INDEX_SUFFIX[] = ".si3";
      40             : const char         INDEX_MAGIC[8]     = "Scid.si";
      41             : // max. number of games is 2^(3*8)-1-1,
      42             : // The "2^(3*8)-1" as si4 only uses three bytes to store this integer,
      43             : // The second "-1" because GetAutoLoad uses 0 to mean "no autoload"
      44             : const gamenumT     MAX_GAMES          = 16777214;
      45             : 
      46             : // Descriptions can be up to 107 bytes long.
      47             : const uint  SCID_DESC_LENGTH = 107;
      48             : const uint  CUSTOM_FLAG_DESC_LENGTH = 8;
      49             : const uint  CUSTOM_FLAG_MAX = 6;
      50             : 
      51             : // Header on-disk size: magic=8, version=2, numGames=3, baseType=4, autoLoad=3
      52             : // Description length = 111 bytes including trailing '\0'.
      53             : // Custom flag desc length = 9 bytes including trailing '\0'.
      54             : // So total is 128 bytes + 9*6 = 182 bytes for the whole header.
      55             : const uint  INDEX_HEADER_SIZE = 8 + 2 + 3 + 4 + 3 + SCID_DESC_LENGTH + 1 + (CUSTOM_FLAG_DESC_LENGTH+1) * CUSTOM_FLAG_MAX;
      56             : const uint  OLD_INDEX_HEADER_SIZE = INDEX_HEADER_SIZE - (CUSTOM_FLAG_DESC_LENGTH+1) * CUSTOM_FLAG_MAX;
      57             : 
      58             : //////////////////////////////////////////////////////////////////////
      59             : //  Index:  Class Definition
      60             : 
      61             : class Index
      62             : {
      63             : private:
      64             :     // The complete index will be loaded in memory and can be pretty huge.
      65             :     // To avoid the slow reallocation when adding games we split the data in chunks.
      66             :     // CHUNKSHIFT is the base-2 logarithm of the number of index entries allocated as one chunk.
      67             :     // i.e 16 = 2^16 = 65536 (total size of one chunk: 65536*48 = 3MB)
      68             :     VectorBig<IndexEntry, 16> entries_; // A two-level array of the entire index.
      69             :     Filebuf*     FilePtr;       // filehandle for opened index file.
      70             :     fileModeT    fileMode_;     // Mode: e.g. FILE_WRITEONLY
      71             :     int nInvalidNameId_;
      72             :     gamenumT seqWrite_;
      73             : 
      74             :     struct { // one at the start of the index file.
      75             :         char        magic[9];    // 8-byte identifier for Scid index files.
      76             :         versionT    version;     // version number. 2 bytes.
      77             :         uint        baseType;    // Type, e.g. tournament, theory, etc.
      78             :         gamenumT    numGames;    // number of games in file.
      79             :         gamenumT    autoLoad;    // game number to autoload: 0=none, 1=1st, >numGames=last
      80             :         // description is a fixed-length string describing the database.
      81             :         char        description [SCID_DESC_LENGTH + 1];
      82             :         // short description (8 chars) for the CUSTOM_FLAG_MAX bits for CUSTOM flags
      83             :         char        customFlagDesc [CUSTOM_FLAG_MAX][CUSTOM_FLAG_DESC_LENGTH+1] ;
      84             :         bool        dirty_;      // If true, Header needs rewriting to disk.
      85             :     } Header;
      86             : 
      87             : public:
      88         159 :     Index()  { entries_.reserve(MAX_GAMES); Init(); }
      89             :     Index(const Index&);
      90             :     Index& operator=(const Index&);
      91          53 :     ~Index() { Clear(); }
      92             : 
      93             :     errorT Open(const char* filename, fileModeT fmode);
      94             :     errorT ReadEntireFile (NameBase* nb, const Progress& progress);
      95             :     errorT Create(const char* filename);
      96           8 :     errorT Close() { return Clear(); }
      97             : 
      98     1152493 :     const IndexEntry* GetEntry (gamenumT g) const {
      99     1152494 :         ASSERT(g < GetNumGames());
     100     2304988 :         return &(entries_[g]);
     101             :     }
     102             : 
     103             :     /**
     104             :      * GetBadNameIdCount() - return the number of invalid name handles.
     105             :      *
     106             :      * To save space, avoiding duplicates, the index keep handles
     107             :      * to strings stored in the namebase file.
     108             :      * If one of the two files is corrupted, the index may have
     109             :      * handles to strings that do not exists.
     110             :      * This functions returns the number of invalid name handles.
     111             :      */
     112             :     int GetBadNameIdCount() const { return nInvalidNameId_; }
     113             : 
     114             :     /**
     115             :      * calcNameFreq() - calculate the usage of NameBase's names
     116             :      * @nb: the NameBase linked to this Index
     117             :      * @resVec: an array of std::vectors where the stats will be stored.
     118             :      *
     119             :      * This functions counts how many times every names contained in @nb
     120             :      * is used and store the result into a corresponding record in @resVec
     121             :      */
     122          33 :     void calcNameFreq(const NameBase& nb, std::vector<int>(&resVec)[NUM_NAME_TYPES]) const {
     123         165 :         for (nameT n = NAME_PLAYER; n < NUM_NAME_TYPES; n++) {
     124         264 :             resVec[n].clear();
     125         264 :             resVec[n].resize(nb.GetNumNames(n), 0);
     126             :         }
     127             : 
     128        7696 :         for (gamenumT i = 0, n = GetNumGames(); i < n; i++) {
     129        7663 :             const IndexEntry* ie = GetEntry(i);
     130       22989 :             resVec[NAME_PLAYER][ie->GetWhite()] += 1;
     131       22989 :             resVec[NAME_PLAYER][ie->GetBlack()] += 1;
     132       22989 :             resVec[NAME_EVENT][ie->GetEvent()] += 1;
     133       22989 :             resVec[NAME_SITE][ie->GetSite()] += 1;
     134       22989 :             resVec[NAME_ROUND][ie->GetRound()] += 1;
     135             :         }
     136          33 :     }
     137             : 
     138             :     /**
     139             :      * Header getter functions
     140             :      */
     141             :     gamenumT    GetNumGames ()    const { return Header.numGames; }
     142             :     uint        GetType ()        const { return Header.baseType; }
     143             :     versionT    GetVersion ()     const { return Header.version; }
     144           0 :     const char* GetDescription () const { return Header.description; }
     145             :     const char* GetCustomFlagDesc (byte c) const {
     146           6 :         if (c < IndexEntry::IDX_FLAG_CUSTOM1 || c > IndexEntry::IDX_FLAG_CUSTOM6) return 0;
     147           6 :         return Header.customFlagDesc[c - IndexEntry::IDX_FLAG_CUSTOM1];
     148             :     }
     149             :     gamenumT GetAutoLoad () const {
     150           1 :         return (Header.autoLoad <= Header.numGames) ? Header.autoLoad : Header.numGames;
     151             :     }
     152             : 
     153             :     /**
     154             :      * Header setter functions
     155             :      */
     156           0 :     errorT copyHeaderInfo(const Index& src) {
     157           0 :         if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
     158           0 :         Header.baseType = src.Header.baseType;
     159           0 :         Header.autoLoad = src.Header.autoLoad;
     160           0 :         std::memcpy(Header.description, src.Header.description, sizeof Header.description);
     161           0 :         std::memcpy(Header.customFlagDesc, src.Header.customFlagDesc, sizeof Header.customFlagDesc);
     162           0 :         Header.dirty_ = true;
     163           0 :         return flush();
     164             :     }
     165             :     errorT SetType (uint t) {
     166           1 :         if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
     167           1 :         Header.baseType = t;
     168           1 :         Header.dirty_ = true;
     169           1 :         return flush();
     170             :     }
     171           1 :     errorT SetDescription (const char* str) {
     172           1 :         if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
     173           2 :         strncpy(Header.description, str, SCID_DESC_LENGTH);
     174           1 :         Header.description[SCID_DESC_LENGTH] = 0;
     175           1 :         Header.dirty_ = true;
     176           1 :         return flush();
     177             :     }
     178           6 :     errorT SetCustomFlagDesc (byte c, const char* str) {
     179           6 :         if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
     180           6 :         if (c < IndexEntry::IDX_FLAG_CUSTOM1 || c > IndexEntry::IDX_FLAG_CUSTOM6) return ERROR_BadArg;
     181           6 :         char* flagDesc = Header.customFlagDesc[c - IndexEntry::IDX_FLAG_CUSTOM1];
     182           6 :         strncpy(flagDesc, str, CUSTOM_FLAG_DESC_LENGTH);
     183           6 :         flagDesc[CUSTOM_FLAG_DESC_LENGTH] = 0;
     184           6 :         Header.dirty_ = true;
     185           6 :         return flush();
     186             :     }
     187             :     errorT SetAutoLoad (gamenumT gnum) {
     188           1 :         if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
     189           1 :         Header.autoLoad = gnum;
     190           1 :         Header.dirty_ = true;
     191           1 :         return flush();
     192             :     }
     193             : 
     194             :     /**
     195             :      * FetchEntry() - return a modifiable pointer to a game's IndexEntry
     196             :      *
     197             :      * The pointer returned by this function allow to modify the IndexEntry
     198             :      * informations of a game. If modified, the IndexEntry object must be
     199             :      * passed to WriteEntry() to write the changes to the disks.
     200             :      * This functions is very error prone. For example:
     201             :      * IndexEntry* ie = FetchEntry(0);
     202             :      * ie->SetWhiteName(nb, "New player with white");
     203             :      * oops(); // the function oops() may call GetEntry(0) and get a messy object.
     204             :      * ie->SetBlackName(nb, "New player with black");
     205             :      *
     206             :      * A safer alternative is to create a temporary copy of the IndexEntry object
     207             :      * returned by GetEntry() and then write all the changes in a single step
     208             :      */
     209             :     IndexEntry* FetchEntry (gamenumT g) {
     210           1 :         ASSERT(g < GetNumGames());
     211           2 :         return &(entries_[g]);
     212             :     }
     213             : 
     214             :     /**
     215             :      * WriteEntry() - modify a game in the Index
     216             :      */
     217       16041 :     errorT WriteEntry (const IndexEntry* ie, gamenumT idx, bool flush = true) {
     218       16041 :         errorT res = write(ie, idx);
     219       16041 :         if (flush && res == OK) res = this->flush();
     220       16041 :         return res;
     221             :     }
     222             : 
     223             :     /**
     224             :      * AddGame() - add a game to the Index
     225             :      * @ie: valid pointer to the IndexEntry object with data for the new game.
     226             :      *
     227             :      * For performance reasons this function can cache the changes and they are
     228             :      * automatically written to file when the object is destroyed or closed.
     229             :      * However, for maximum security against power loss, crash, etc, it is
     230             :      * recommended to call the function flush() after using this function.
     231             :      */
     232             :     errorT AddGame (const IndexEntry* ie) {
     233       12039 :         return WriteEntry(ie, GetNumGames(), false);
     234             :     }
     235             : 
     236             :     /**
     237             :      * flush() - writes all cached data to the file
     238             :      */
     239        4102 :     errorT flush() {
     240        4102 :         if (FilePtr == 0) return OK;
     241        2039 :         errorT errHeader = (Header.dirty_) ? WriteHeader() : OK;
     242        4078 :         errorT errSync = (FilePtr->pubsync() != 0) ? ERROR_FileWrite : OK;
     243        2039 :         return (errHeader == OK) ? errSync : errHeader;
     244             :     }
     245             : 
     246             : private:
     247             :     void Init ();
     248             :     errorT Clear ();
     249             :     errorT write (const IndexEntry* ie, gamenumT idx);
     250             :     errorT WriteHeader ();
     251             : };
     252             : 
     253             : 
     254             : #endif  // #ifdef SCID_INDEX_H
     255             : 
     256             : //////////////////////////////////////////////////////////////////////
     257             : //  EOF: index.h
     258             : //////////////////////////////////////////////////////////////////////
     259             : 

Generated by: LCOV version 1.12