Line data Source code
1 : /*
2 : * Copyright (C) 2017 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 :
20 : /** @file
21 : * Implements @e CodecNative, which is used as base class by native codecs.
22 : */
23 :
24 : #ifndef CODEC_NATIVE_H
25 : #define CODEC_NATIVE_H
26 :
27 : #include "bytebuf.h"
28 : #include "codec.h"
29 : #include "game.h"
30 : #include "index.h"
31 : #include "namebase.h"
32 :
33 : /**
34 : * This class stores the pointers to the @e Index and @e NameBase objects used
35 : * by a native codec. It also implements the addGame() and saveGame() functions
36 : * of the ICodecDatabase interface, splitting them into 2 function calls to a
37 : * derived class (CRTP technique):
38 : * - dyn_addName() should return the ID corresponding to a name, eventually
39 : * adding the name to the @e nb_ if necessary;
40 : * - dyn_addGameData() should stores the data of the game, encoded in native
41 : * format, and returns the offset that can be used to retrieve the data.
42 : */
43 50 : template <typename Derived> class CodecNative : public ICodecDatabase {
44 : protected:
45 : Index* idx_;
46 : NameBase* nb_;
47 : ByteBuffer bbuf_;
48 :
49 : protected:
50 50 : CodecNative() : idx_(0), nb_(0), bbuf_(BBUF_SIZE) {}
51 :
52 : public: // ICodecDatabase interface
53 3003 : errorT addGame(const IndexEntry* srcIe, const NameBase* srcNb,
54 : const byte* srcData, size_t dataLen) override {
55 3003 : IndexEntry ie = *srcIe;
56 3003 : errorT err = addGameHelper(
57 : &ie, srcData, dataLen,
58 : srcNb->GetName(NAME_PLAYER, srcIe->GetWhite()),
59 : srcNb->GetName(NAME_PLAYER, srcIe->GetBlack()),
60 : srcNb->GetName(NAME_EVENT, srcIe->GetEvent()),
61 : srcNb->GetName(NAME_SITE, srcIe->GetSite()),
62 : srcNb->GetName(NAME_ROUND, srcIe->GetRound()));
63 3003 : if (err != OK)
64 0 : return err;
65 :
66 3003 : return derived()->dyn_addIndexEntry(ie);
67 : }
68 :
69 7014 : errorT addGame(Game* game) override {
70 7014 : std::pair<errorT, IndexEntry> ie = addGameHelper(game);
71 7014 : if (ie.first != OK)
72 0 : return ie.first;
73 :
74 7014 : return derived()->dyn_addIndexEntry(ie.second);
75 : }
76 :
77 2001 : errorT saveGame(Game* game, gamenumT replaced) override {
78 2001 : if (replaced >= idx_->GetNumGames())
79 0 : return ERROR_BadArg;
80 :
81 2001 : std::pair<errorT, IndexEntry> ie = addGameHelper(game);
82 2001 : if (ie.first != OK)
83 0 : return ie.first;
84 :
85 2001 : return derived()->dyn_saveIndexEntry(ie.second, replaced);
86 : }
87 :
88 0 : errorT saveIndexEntry(const IndexEntry& ie, gamenumT replaced) override {
89 0 : return derived()->dyn_saveIndexEntry(ie, replaced);
90 : }
91 :
92 0 : std::pair<errorT, idNumberT> addName(nameT nt, const char* name) override {
93 0 : return derived()->dyn_addName(nt, name);
94 : }
95 :
96 : private:
97 9015 : std::pair<errorT, IndexEntry> addGameHelper(Game* game) {
98 9015 : std::pair<errorT, IndexEntry> res;
99 9015 : res.second.Init();
100 9015 : res.first = game->Encode(&bbuf_, &res.second);
101 9015 : if (res.first == OK) {
102 9015 : res.first = addGameHelper(&res.second, bbuf_.getData(),
103 : bbuf_.GetByteCount(), game->GetWhiteStr(),
104 : game->GetBlackStr(), game->GetEventStr(),
105 : game->GetSiteStr(), game->GetRoundStr());
106 : }
107 9015 : return res;
108 : }
109 :
110 12018 : errorT addGameHelper(IndexEntry* ie, const byte* srcData, size_t dataLen,
111 : const char* white, const char* black,
112 : const char* event, const char* site,
113 : const char* round) {
114 12018 : auto id = derived()->dyn_addName(NAME_PLAYER, white);
115 12018 : if (id.first != OK)
116 0 : return id.first;
117 12018 : ie->SetWhite(id.second);
118 12018 : nb_->AddElo(id.second, ie->GetWhiteElo());
119 :
120 12018 : id = derived()->dyn_addName(NAME_PLAYER, black);
121 12018 : if (id.first != OK)
122 0 : return id.first;
123 12018 : ie->SetBlack(id.second);
124 12018 : nb_->AddElo(id.second, ie->GetBlackElo());
125 :
126 12018 : id = derived()->dyn_addName(NAME_EVENT, event);
127 12018 : if (id.first != OK)
128 0 : return id.first;
129 12018 : ie->SetEvent(id.second);
130 :
131 12018 : id = derived()->dyn_addName(NAME_SITE, site);
132 12018 : if (id.first != OK)
133 0 : return id.first;
134 12018 : ie->SetSite(id.second);
135 :
136 12018 : id = derived()->dyn_addName(NAME_ROUND, round);
137 12018 : if (id.first != OK)
138 0 : return id.first;
139 12018 : ie->SetRound(id.second);
140 :
141 12018 : auto offset = derived()->dyn_addGameData(srcData, dataLen);
142 12018 : if (offset.first == OK) {
143 12018 : ie->SetOffset(offset.second);
144 12018 : ie->SetLength(dataLen);
145 : }
146 12018 : return offset.first;
147 : }
148 :
149 84126 : Derived* derived() { return static_cast<Derived*>(this); }
150 : };
151 :
152 : #endif
|