Scid  4.6.5
index.h
Go to the documentation of this file.
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;
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.
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.
82  // short description (8 chars) for the CUSTOM_FLAG_MAX bits for CUSTOM flags
84  bool dirty_; // If true, Header needs rewriting to disk.
85  } Header;
86 
87 public:
88  Index() { entries_.reserve(MAX_GAMES); Init(); }
89  Index(const Index&);
90  Index& operator=(const Index&);
91  ~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  errorT Close() { return Clear(); }
97 
98  const IndexEntry* GetEntry (gamenumT g) const {
99  ASSERT(g < GetNumGames());
100  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  void calcNameFreq(const NameBase& nb, std::vector<int>(&resVec)[NUM_NAME_TYPES]) const {
123  for (nameT n = NAME_PLAYER; n < NUM_NAME_TYPES; n++) {
124  resVec[n].clear();
125  resVec[n].resize(nb.GetNumNames(n), 0);
126  }
127 
128  for (gamenumT i = 0, n = GetNumGames(); i < n; i++) {
129  const IndexEntry* ie = GetEntry(i);
130  resVec[NAME_PLAYER][ie->GetWhite()] += 1;
131  resVec[NAME_PLAYER][ie->GetBlack()] += 1;
132  resVec[NAME_EVENT][ie->GetEvent()] += 1;
133  resVec[NAME_SITE][ie->GetSite()] += 1;
134  resVec[NAME_ROUND][ie->GetRound()] += 1;
135  }
136  }
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  const char* GetDescription () const { return Header.description; }
145  const char* GetCustomFlagDesc (byte c) const {
146  if (c < IndexEntry::IDX_FLAG_CUSTOM1 || c > IndexEntry::IDX_FLAG_CUSTOM6) return 0;
147  return Header.customFlagDesc[c - IndexEntry::IDX_FLAG_CUSTOM1];
148  }
150  return (Header.autoLoad <= Header.numGames) ? Header.autoLoad : Header.numGames;
151  }
152 
153  /**
154  * Header setter functions
155  */
157  if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
158  Header.baseType = src.Header.baseType;
159  Header.autoLoad = src.Header.autoLoad;
160  std::memcpy(Header.description, src.Header.description, sizeof Header.description);
161  std::memcpy(Header.customFlagDesc, src.Header.customFlagDesc, sizeof Header.customFlagDesc);
162  Header.dirty_ = true;
163  return flush();
164  }
166  if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
167  Header.baseType = t;
168  Header.dirty_ = true;
169  return flush();
170  }
171  errorT SetDescription (const char* str) {
172  if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
173  strncpy(Header.description, str, SCID_DESC_LENGTH);
174  Header.description[SCID_DESC_LENGTH] = 0;
175  Header.dirty_ = true;
176  return flush();
177  }
178  errorT SetCustomFlagDesc (byte c, const char* str) {
179  if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
180  if (c < IndexEntry::IDX_FLAG_CUSTOM1 || c > IndexEntry::IDX_FLAG_CUSTOM6) return ERROR_BadArg;
181  char* flagDesc = Header.customFlagDesc[c - IndexEntry::IDX_FLAG_CUSTOM1];
182  strncpy(flagDesc, str, CUSTOM_FLAG_DESC_LENGTH);
183  flagDesc[CUSTOM_FLAG_DESC_LENGTH] = 0;
184  Header.dirty_ = true;
185  return flush();
186  }
188  if (fileMode_ == FMODE_ReadOnly) return ERROR_FileMode;
189  Header.autoLoad = gnum;
190  Header.dirty_ = true;
191  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  */
210  ASSERT(g < GetNumGames());
211  return &(entries_[g]);
212  }
213 
214  /**
215  * WriteEntry() - modify a game in the Index
216  */
217  errorT WriteEntry (const IndexEntry* ie, gamenumT idx, bool flush = true) {
218  errorT res = write(ie, idx);
219  if (flush && res == OK) res = this->flush();
220  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  return WriteEntry(ie, GetNumGames(), false);
234  }
235 
236  /**
237  * flush() - writes all cached data to the file
238  */
240  if (FilePtr == 0) return OK;
241  errorT errHeader = (Header.dirty_) ? WriteHeader() : OK;
242  errorT errSync = (FilePtr->pubsync() != 0) ? ERROR_FileWrite : OK;
243  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 
gamenumT autoLoad
Definition: index.h:79
unsigned char byte
Definition: common.h:97
errorT SetAutoLoad(gamenumT gnum)
Definition: index.h:187
const uint INDEX_HEADER_SIZE
Definition: index.h:55
idNumberT GetEvent() const
Definition: indexentry.h:127
const errorT OK
Definition: error.h:23
const uint CUSTOM_FLAG_DESC_LENGTH
Definition: index.h:48
unsigned short versionT
Definition: common.h:44
const errorT ERROR_FileWrite
Definition: error.h:32
#define ASSERT(f)
Definition: common.h:67
~Index()
Definition: index.h:91
const char OLD_INDEX_SUFFIX[]
Definition: index.h:39
const errorT ERROR_BadArg
Definition: error.h:28
errorT AddGame(const IndexEntry *ie)
AddGame() - add a game to the Index : valid pointer to the IndexEntry object with data for the new ga...
Definition: index.h:232
const uint SCID_DESC_LENGTH
Definition: index.h:47
Definition: misc.h:124
bool dirty_
Definition: index.h:84
uint GetType() const
Definition: index.h:142
const char * GetDescription() const
Definition: index.h:144
uint baseType
Definition: index.h:77
errorT Close()
Definition: index.h:96
const gamenumT MAX_GAMES
Definition: index.h:44
const char * GetCustomFlagDesc(byte c) const
Definition: index.h:145
Definition: indexentry.h:399
Index()
Definition: index.h:88
versionT version
Definition: index.h:76
const char INDEX_MAGIC[8]
Definition: index.h:40
Index & operator=(const Index &)
uint nameT
Definition: namebase.h:29
errorT SetDescription(const char *str)
Definition: index.h:171
uint32_t uint
Definition: common.h:99
errorT flush()
flush() - writes all cached data to the file
Definition: index.h:239
void reserve(size_t count)
Definition: misc.h:95
IndexEntry * FetchEntry(gamenumT g)
FetchEntry() - return a modifiable pointer to a game&#39;s IndexEntry.
Definition: index.h:209
Definition: index.h:61
gamenumT GetNumGames() const
Header getter functions.
Definition: index.h:141
errorT ReadEntireFile(NameBase *nb, const Progress &progress)
Definition: index.cpp:137
errorT copyHeaderInfo(const Index &src)
Header setter functions.
Definition: index.h:156
unsigned short errorT
Definition: error.h:20
void calcNameFreq(const NameBase &nb, std::vector< int >(&resVec)[NUM_NAME_TYPES]) const
calcNameFreq() - calculate the usage of NameBase&#39;s names : the NameBase linked to this Index : an arr...
Definition: index.h:122
errorT Open(const char *filename, fileModeT fmode)
Definition: index.cpp:79
idNumberT GetNumNames(nameT n) const
Definition: namebase.h:107
errorT SetType(uint t)
Definition: index.h:165
const char INDEX_SUFFIX[]
Definition: index.h:38
errorT Create(const char *filename)
Definition: index.cpp:55
int GetBadNameIdCount() const
GetBadNameIdCount() - return the number of invalid name handles.
Definition: index.h:112
char description[SCID_DESC_LENGTH+1]
Definition: index.h:81
idNumberT GetRound() const
Definition: indexentry.h:141
char magic[9]
Definition: index.h:75
versionT GetVersion() const
Definition: index.h:143
gamenumT GetAutoLoad() const
Definition: index.h:149
idNumberT GetBlack() const
Definition: indexentry.h:116
Adds some helper functions to std::filebuf:
Definition: filebuf.h:35
Definition: indexentry.h:394
char customFlagDesc[CUSTOM_FLAG_MAX][CUSTOM_FLAG_DESC_LENGTH+1]
Definition: index.h:83
const uint OLD_INDEX_HEADER_SIZE
Definition: index.h:56
const IndexEntry * GetEntry(gamenumT g) const
Definition: index.h:98
gamenumT numGames
Definition: index.h:78
Extends the std:filebuf class with performance improvements.
uint gamenumT
Definition: common.h:159
fileModeT
Definition: common.h:144
const errorT ERROR_FileMode
Definition: error.h:38
errorT WriteEntry(const IndexEntry *ie, gamenumT idx, bool flush=true)
WriteEntry() - modify a game in the Index.
Definition: index.h:217
errorT SetCustomFlagDesc(byte c, const char *str)
Definition: index.h:178
idNumberT GetSite() const
Definition: indexentry.h:134
idNumberT GetWhite() const
Definition: indexentry.h:109
const uint CUSTOM_FLAG_MAX
Definition: index.h:49
Definition: indexentry.h:54