LCOV - code coverage report
Current view: top level - src - scidbase.h (source / functions) Hit Total Coverage
Test: test_coverage.info Lines: 10 28 35.7 %
Date: 2017-06-21 14:32:49 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /*
       2             : # Copyright (C) 2014-2016 Fulvio Benini
       3             : 
       4             : * This file is part of Scid (Shane's Chess Information Database).
       5             : *
       6             : * Scid is free software: you can redistribute it and/or modify
       7             : * it under the terms of the GNU General Public License as published by
       8             : * the Free Software Foundation.
       9             : *
      10             : * Scid is distributed in the hope that it will be useful,
      11             : * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      13             : * GNU General Public License for more details.
      14             : *
      15             : * You should have received a copy of the GNU General Public License
      16             : * along with Scid. If not, see <http://www.gnu.org/licenses/>.
      17             : */
      18             : 
      19             : #ifndef SCIDBASE_H
      20             : #define SCIDBASE_H
      21             : 
      22             : #include "bytebuf.h"
      23             : #include "codec.h"
      24             : #include "fastgame.h"
      25             : #include "game.h"
      26             : #include "index.h"
      27             : #include "namebase.h"
      28             : #include "tree.h"
      29             : #include "undoredo.h"
      30             : #include <vector>
      31             : 
      32             : class SortCache;
      33             : 
      34             : 
      35             : const gamenumT INVALID_GAMEID = 0xffffffff;
      36             : 
      37             : struct scidBaseT {
      38             :         struct Stats {
      39             :                 uint flagCount[IndexEntry::IDX_NUM_FLAGS]; // Num of games with each flag set.
      40             :                 dateT minDate;
      41             :                 dateT maxDate;
      42             :                 uint64_t nYears;
      43             :                 uint64_t sumYears;
      44             :                 uint nResults [NUM_RESULT_TYPES];
      45             :                 uint nRatings;
      46             :                 uint64_t sumRatings;
      47             :                 uint minRating;
      48             :                 uint maxRating;
      49             : 
      50             :                 Stats(const scidBaseT* dbase);
      51             : 
      52             :                 struct Eco {
      53             :                         uint count;
      54             :                         uint results [NUM_RESULT_TYPES];
      55             : 
      56             :                         Eco();
      57             :                 };
      58             :                 const Eco* getEcoStats(const char* ecoStr) const;
      59             : 
      60             :         private:
      61             :                 Eco ecoEmpty_;
      62             :                 Eco ecoValid_;
      63             :                 Eco ecoStats_ [(1 + (1<<16)/131)*27];
      64             :                 Eco ecoGroup1_[(1 + (1<<16)/131)/100];
      65             :                 Eco ecoGroup2_[(1 + (1<<16)/131)/10];
      66             :                 Eco ecoGroup3_[(1 + (1<<16)/131)];
      67             :         };
      68             : 
      69           0 :         struct TreeStat {
      70             :                 colorT toMove;
      71             :                 std::string SAN;
      72             :                 int resultW, resultD, resultB;
      73             :                 double exp;
      74             :                 int ngames, nexp;
      75             : 
      76             :         public:
      77             :                 TreeStat();
      78             :                 void add(int result, int eloW, int eloB);
      79             :                 bool operator<(const TreeStat& cmp) const { return ngames > cmp.ngames; }
      80             : 
      81             :         private:
      82             :                 static double expVect_[1600];
      83             :         };
      84             : 
      85             :         scidBaseT();
      86             :         ~scidBaseT();
      87             : 
      88             :         errorT Open(ICodecDatabase::Codec dbtype,
      89             :                     fileModeT mode,
      90             :                     const char* filename = 0,
      91             :                     const Progress& progress = Progress());
      92             : 
      93             :         errorT Close ();
      94             : 
      95             :         const std::string& getFileName() const { return fileName_; }
      96             :         bool isReadOnly() const { return fileMode_ == FMODE_ReadOnly; }
      97        6398 :         gamenumT numGames() const { return idx->GetNumGames(); }
      98             :         errorT getExtraInfo(const std::string& tagname, std::string* res) const;
      99             :         errorT setExtraInfo(const std::string& tagname, const char* new_value);
     100             : 
     101             :         const IndexEntry* getIndexEntry(gamenumT g) const {
     102        1357 :                 return idx->GetEntry(g);
     103             :         }
     104             :         const IndexEntry* getIndexEntry_bounds(gamenumT g) const {
     105          44 :                 if (g < numGames()) return getIndexEntry(g);
     106             :                 return 0;
     107             :         }
     108             :         const NameBase* getNameBase() const {
     109             :                 return nb;
     110             :         }
     111           0 :         FastGame getGame(const IndexEntry* ie) const {
     112           0 :                 uint length = ie->GetLength();
     113           0 :                 const byte* b = codec_->getGameData(ie->GetOffset(), length);
     114           0 :                 if (b == 0) length = 0; // Error
     115           0 :                 return FastGame::Create(b, b + length);
     116             :         }
     117          12 :         errorT getGame(const IndexEntry* ie, ByteBuffer* destBuf) const {
     118          24 :                 uint length = ie->GetLength();
     119          12 :                 const byte* b = codec_->getGameData(ie->GetOffset(), length);
     120          12 :                 if (b == 0) return ERROR_FileRead;
     121             :                 // The data for the game is not actually copied into the bytebuffer, which would
     122             :                 // be slower and a waste of time if the bytebuffer is not going to be modified.
     123          12 :                 destBuf->ProvideExternal(const_cast<byte*>(b), length);
     124             :                 return OK;
     125             :         }
     126             : 
     127       38020 :         struct GamePos {
     128             :                 unsigned int RAVdepth;
     129             :                 unsigned int RAVnum;
     130             :                 std::string FEN;
     131             :                 std::vector<int> NAGs;
     132             :                 std::string comment;
     133             :                 std::string lastMoveSAN;
     134             :         };
     135             :         errorT getGame(const IndexEntry* ie, std::vector<GamePos>& dest);
     136             : 
     137             :         errorT importGame(const scidBaseT* srcBase, uint gNum);
     138             :         errorT importGames(const scidBaseT* srcBase, const HFilter& filter, const Progress& progress);
     139             :         template <class T, class P>
     140             :         errorT importGames(T& codec, const P& progress, uint& nImported, std::string& errorMsg);
     141             : 
     142             :         /**
     143             :          * Add or replace a game into the database.
     144             :          * @param game: valid pointer to a Game object with the data of the game.
     145             :          * @param replacedgameId: id of the game to replace.
     146             :          *                        If >= numGames(), a new game will be added.
     147             :          * @returns OK if successful or an error code.
     148             :          */
     149             :         errorT saveGame(Game* game, gamenumT replacedGameId = INVALID_GAMEID);
     150             :         // TODO: private:
     151             :         errorT saveGameHelper(Game* game, gamenumT gameId);
     152             : 
     153             : 
     154             :         bool getFlag(uint flag, uint gNum) const {
     155             :                 return idx->GetEntry(gNum)->GetFlag (flag);
     156             :         }
     157             :         errorT setFlag(bool value, uint flag, uint gNum);
     158             :         errorT setFlag(bool value, uint flag, const HFilter& filter);
     159             :         errorT invertFlag(uint flag, uint gNum);
     160             :         errorT invertFlag(uint flag, const HFilter& filter);
     161             : 
     162             :         /**
     163             :          * Filters
     164             :          * @filterId: unique identifier of a Filter
     165             :          *
     166             :          * A Filter is a selection of games, usually obtained searching the
     167             :          * database. A new Filter is created calling the function newFilter()
     168             :          * and must be released calling the function deleteFilter().
     169             :          * A composed Filter is a special contruct created combining two Filters
     170             :          * and includes only the games contained in both Filters.
     171             :          * A composed Filter should NOT be released.
     172             :          */
     173             :         std::string newFilter();
     174             :         std::string composeFilter(const std::string& mainFilter,
     175             :                                   const std::string& maskFilter) const;
     176             :         void deleteFilter(const char* filterId);
     177             :         HFilter getFilter(const std::string& filterId) const {
     178       36551 :                 return getFilterHelper(filterId, false);
     179             :         }
     180             :         HFilter getMainFilter(const std::string& filterId) const {
     181             :                 return getFilterHelper(filterId, true);
     182             :         }
     183             : 
     184             :         const Stats& getStats() const;
     185             :         std::vector<scidBaseT::TreeStat> getTreeStat(const HFilter& filter);
     186             :         uint getNameFreq (nameT nt, idNumberT id) {
     187             :                 if (nameFreq_[nt].size() == 0) idx->calcNameFreq(*nb, nameFreq_);
     188             :                 return nameFreq_[nt][id];
     189             :         }
     190             : 
     191             :         errorT getCompactStat(uint* n_deleted,
     192             :                               uint* n_unused,
     193             :                               uint* n_sparse,
     194             :                               uint* n_badNameId);
     195             :         errorT compact(const Progress& progress);
     196             : 
     197             : 
     198             :         /**
     199             :          * Increment the reference count of a SortCache object matching @e criteria.
     200             :          * @param criteria: the list of fields by which games will be ordered.
     201             :          *                  Each field should be followed by '+' to indicate an
     202             :          *                  ascending order or by '-' for a descending order.
     203             :          * @returns a pointer to a SortCache object in case of success, NULL
     204             :          * otherwise.
     205             :          */
     206             :         SortCache* createSortCache(const char* criteria);
     207             : 
     208             :         /**
     209             :          * Decrement the reference count of the SortCache object matching @e
     210             :          * criteria. Cached objects with refCount <= 0 are destroyed independently
     211             :          * from the value of @e criteria.
     212             :          * @param criteria: the list of fields by which games will be ordered.
     213             :          *                  Each field should be followed by '+' to indicate an
     214             :          *                  ascending order or by '-' for a descending order.
     215             :          */
     216             :         void releaseSortCache(const char* criteria);
     217             : 
     218             :         /**
     219             :          * Retrieve a list of ordered game indexes sorted by @e criteria.
     220             :          * This function will be much faster if a SortCache object matching @e
     221             :          * criteria already exists (previously created with @e createSortCache).
     222             :          * @param criteria: the list of fields by which games will be ordered.
     223             :          *                  Each field should be followed by '+' to indicate an
     224             :          *                  ascending order or by '-' for a descending order.
     225             :          * @param start:    the offset of the first row to return.
     226             :          *                  The offset of the initial row is 0.
     227             :          * @param count:    maximum number of rows to return.
     228             :          * @param filter:   a reference to a valid (!= NULL) HFilter object.
     229             :          *                  Games not included into the filter will be ignored.
     230             :          * @param[out] destCont: valid pointer to an array where the sorted list of
     231             :          *                       games will be stored (should be able to contain at
     232             :          *                       least @e count elements).
     233             :          * @returns the number of games' ids stored into @e destCont.
     234             :          */
     235             :         size_t listGames(const char* criteria, size_t start, size_t count,
     236             :                          const HFilter& filter, gamenumT* destCont);
     237             : 
     238             :         /**
     239             :          * Get the sorted position of a game.
     240             :          * This function will be much faster if a SortCache object matching @e
     241             :          * criteria already exists (previously created with @e createSortCache).
     242             :          * @param criteria: the list of fields by which games will be ordered.
     243             :          *                  Each field should be followed by '+' to indicate an
     244             :          *                  ascending order or by '-' for a descending order.
     245             :          * @param filter:   a reference to a valid (!= NULL) HFilter object.
     246             :          *                  Games not included into the filter will be ignored.
     247             :          * @param gameId:   the id of the game.
     248             :          * @returns the sorted position of @e gameId.
     249             :          */
     250             :         size_t sortedPosition(const char* criteria, const HFilter& filter,
     251             :                               gamenumT gameId);
     252             : 
     253             :         void setDuplicates(uint* duplicates) {
     254             :                 if (duplicates_ != NULL) { delete[] duplicates_; duplicates_ = NULL; }
     255             :                 duplicates_ = duplicates;
     256             :         }
     257             :         uint getDuplicates(gamenumT gNum) {
     258             :                 return (duplicates_ == NULL) ? 0 : duplicates_[gNum];
     259             :         }
     260             : 
     261             :         // TODO: private:
     262             :         /**
     263             :          * This function must be called before modifying the games of the database.
     264             :          * Currently this function do not guarantees that the database is not altered
     265             :          * in case of errors.
     266             :          */
     267             :         void beginTransaction();
     268             : 
     269             :         // TODO: private:
     270             :         /**
     271             :          * Update caches and flush the database's files.
     272             :          * This function must be called after changing one or more games.
     273             :          * @param gameId: id of the modified game
     274             :          *                INVALID_GAMEID to update all games.
     275             :          * @returns OK if successful or an error code.
     276             :          */
     277             :         errorT endTransaction(gamenumT gameId = INVALID_GAMEID);
     278             : 
     279             : public:
     280             :         Index* idx;       // the Index file in memory for this base.
     281             :         NameBase* nb;      // the NameBase file in memory.
     282             :         bool inUse;       // true if the database is open (in use).
     283             :         treeT tree;
     284             :         TreeCache treeCache;
     285             :         ByteBuffer* bbuf;
     286             :         Filter* dbFilter;
     287             :         Filter* treeFilter;
     288             : 
     289             : 
     290             :         //TODO: this vars do not belong to scidBaseT class
     291             :         Game* game;       // the active game for this base.
     292             :         int gameNumber;   // game number of active game.
     293             :         bool gameAltered; // true if game is modified
     294             :         UndoRedo<Game, 100> gameAlterations;
     295             : 
     296             : private:
     297             :         ICodecDatabase* codec_;
     298             :         std::string fileName_; // File name without ".si" suffix
     299             :         fileModeT fileMode_; // Read-only, write-only, or both.
     300             :         std::vector< std::pair<std::string, Filter*> > filters_;
     301             :         mutable Stats* stats_;
     302             :         std::vector <int> nameFreq_ [NUM_NAME_TYPES];
     303             :         uint* duplicates_; // For each game: idx of duplicate game + 1 (0 if there is no duplicate).
     304             :         std::vector< std::pair<std::string, SortCache*> > sortCaches_;
     305             : 
     306             : private:
     307             :         scidBaseT(const scidBaseT&);
     308             :         scidBaseT& operator=(const scidBaseT&);
     309             :         void clear();
     310             :         GamePos makeGamePos(Game& game, unsigned int ravNum);
     311             :         errorT importGameHelper(const scidBaseT* sourceBase, uint gNum);
     312             : 
     313             :         void extendFilters();
     314             :         Filter* fetchFilter(const std::string& filterId) const;
     315             :         HFilter getFilterHelper(const std::string& filterId,
     316             :                                 bool unmasked = false) const;
     317             :         SortCache* getSortCache(const char* criteria);
     318             : };
     319             : 
     320           0 : inline void scidBaseT::TreeStat::add(int result, int eloW, int eloB) {
     321           0 :         ngames++;
     322           0 :         double r = 0;
     323           0 :         switch (result) {
     324           0 :                 case RESULT_White: resultW++; r = 1; break;
     325           0 :                 case RESULT_Draw: resultD++; r = 0.5; break;
     326           0 :                 case RESULT_Black: resultB++; break;
     327             :                 default: return;
     328             :         }
     329           0 :         if (eloW == 0 || eloB == 0) return;
     330           0 :         int eloDiff = eloB - eloW;
     331           0 :         if (eloDiff < 800 && eloDiff >= -800) {
     332           0 :                 exp += r - expVect_[eloDiff+800];
     333           0 :                 nexp++;
     334             :         }
     335             : }
     336             : 
     337             : template <class T, class P>
     338             : inline errorT scidBaseT::importGames(T& codec, const P& progress, uint& nImported, std::string& errorMsg) {
     339             :         beginTransaction();
     340             :         errorT res;
     341             :         Game g;
     342             :         nImported = 0;
     343             :         while ((res = codec.parseNext(&g)) != ERROR_NotFound) {
     344             :                 if (res != OK) continue;
     345             : 
     346             :                 res = saveGameHelper(&g, INVALID_GAMEID);
     347             :                 if (res != OK) break;
     348             : 
     349             :                 if ((++nImported % 200) == 0) {
     350             :                         std::pair<size_t, size_t> count = codec.parseProgress();
     351             :                         if (!progress.report(count.first, count.second)) {
     352             :                                 res = ERROR_UserCancel;
     353             :                                 break;
     354             :                         }
     355             :                 }
     356             :         }
     357             : 
     358             :         errorMsg = codec.parseErrors();
     359             :         endTransaction();
     360             :         progress.report(1,1);
     361             : 
     362             :         if (res == ERROR_NotFound) res = OK;
     363             :         return res;
     364             : }
     365             : 
     366             : inline errorT scidBaseT::invertFlag(uint flag, uint gNum) {
     367             :         return setFlag(! getFlag(flag, gNum), flag, gNum);
     368             : }
     369             : 
     370             : inline errorT scidBaseT::invertFlag(uint flag, const HFilter& filter) {
     371             :         errorT res = OK;
     372             :         for (gamenumT i = 0, n = numGames(); i < n; i++) {
     373             :                 if (filter != 0 && filter->get(i) == 0) continue;
     374             :                 res = invertFlag(flag, i);
     375             :                 if (res != OK) return res;
     376             :         }
     377             :         return res;
     378             : }
     379             : 
     380             : inline errorT scidBaseT::setFlag(bool value, uint flag, uint gNum){
     381             :         ASSERT(gNum < idx->GetNumGames());
     382             :         IndexEntry* ie = idx->FetchEntry (gNum);
     383             :         ie->SetFlag (flag, value);
     384             :         errorT res = idx->WriteEntry (ie, gNum, false);
     385             :         if (stats_ != NULL) { delete stats_; stats_ = NULL;}
     386             :         // TODO: necessary only for sortcaches with SORTING_deleted (and SORTING_flags when implemented)
     387             :         // idx->IndexUpdated(gNum);
     388             :         return res;
     389             : }
     390             : 
     391             : inline errorT scidBaseT::setFlag(bool value, uint flag, const HFilter& filter) {
     392             :         errorT res = OK;
     393             :         for (gamenumT gNum = 0, n = numGames(); gNum < n; gNum++) {
     394             :                 if (filter != 0 && filter->get(gNum) == 0) continue;
     395             :                 res = setFlag(value, flag, gNum);
     396             :                 if (res != OK) return res;
     397             :         }
     398             :         return res;
     399             : }
     400             : 
     401             : 
     402             : 
     403             : #endif
     404             : 

Generated by: LCOV version 1.12