libscid 0.1.0
Chess applications made easy.
Loading...
Searching...
No Matches
hfilter.h
1/*
2# Copyright (C) 2016-2018 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 SCID_HFILTER_H
20#define SCID_HFILTER_H
21
22#include "scid/database/common.h"
23#include "scid/database/game_id.h"
24#include <algorithm>
25#include <iterator>
26#include <memory>
27
28/*
29 * A database can be searched according to different criteria and the list of
30 * matching games is stored into a Filter object.
31 * A value of 0 indicates the game is excluded, or 1-255 indicates
32 * the game is included, and what position to show when the game
33 * is loaded: 1 means the start position, 2 means the position after
34 * Whites first move, etc.
35 */
36namespace scid::database {
37
38class Filter {
39 std::unique_ptr<scid::core::byte[]> data_; // The actual filter data.
40 gamenumT size_; // Number of values in filter.
41 gamenumT nonzero_; // Number of nonzero values in filter.
42 size_t capacity_; // Number of values allocated for data_.
43
44public:
45 explicit Filter(gamenumT size)
46 : size_(size), nonzero_(size), capacity_(0) {}
47
48 void Init(gamenumT size) {
49 data_ = nullptr;
50 nonzero_ = size_ = size;
51 }
52
54 scid::core::byte* data() { return data_.get(); }
55
57 gamenumT Count() const { return nonzero_; }
58
60 gamenumT Size() const { return size_; }
61
63 void Resize(gamenumT size) {
64 if (!data_) {
65 nonzero_ = size;
66 } else if (size < size_) {
67 nonzero_ = size - static_cast<gamenumT>(std::count(
68 data_.get(), data_.get() + size, 0));
69 } else if (size > size_) {
70 if (size > capacity_) {
71 auto tmp(std::move(data_));
72 allocate(size);
73 std::copy_n(tmp.get(), size_, data_.get());
74 }
75 scid::core::byte val = 0;
76 if (Count() == Size()) {
77 val = 1;
78 nonzero_ = size;
79 }
80 std::fill(data_.get() + size_, data_.get() + size, val);
81 }
82 size_ = size;
83 }
84
86 scid::core::byte Get(gamenumT index) const {
87 ASSERT(index < Size());
88 return data_ ? data_[index] : 1;
89 }
90
92 void Set(gamenumT index, scid::core::byte value) {
93 ASSERT(index < Size());
94 if (data_) {
95 if (value == 0) {
96 if (data_[index] != 0)
97 --nonzero_;
98 } else if (data_[index] == 0) {
99 ++nonzero_;
100 }
101 data_[index] = value;
102 } else if (value != 1) {
103 allocate(size_);
104 std::fill(data_.get(), data_.get() + size_, 1);
105 data_[index] = value;
106 if (value == 0)
107 --nonzero_;
108 }
109 }
110
112 void Fill(scid::core::byte value) {
113 if (value == 1) {
114 data_ = nullptr;
115 nonzero_ = size_;
116 } else {
117 if (!data_) {
118 allocate(size_);
119 }
120 std::fill(data_.get(), data_.get() + size_, value);
121 nonzero_ = (value == 0) ? 0 : size_;
122 }
123 }
124
125private:
126 void allocate(size_t size) {
127 auto capacity = (size | 63) + 1;
128 data_ = std::make_unique<scid::core::byte[]>(capacity);
129 capacity_ = capacity;
130 }
131};
132
133/*
134 * This class abstracts the Filter class providing an interface equivalent to a
135 * pointer to a std::map<gamenumT, uint8_t> object, where the keys are the
136 * gamenumT of matching games and the mapped_types are the number of half-moves
137 * necessary to reach the matching position.
138 * Searches that use only header informations (player names, dates, ...) match
139 * at the starting position (0 half-moves).
140 *
141 * It is also possible to combine two filters in an efficient and transparent
142 * way. If a secondary "mask" filter is supplied, the functions get(), size()
143 * and the const_iterator consider only the games included in both filters.
144 * Their behavior is equal to:
145 * using Filter = std::map<gamenumT, uint8_t>;
146 * Filter tmp_combined;
147 * std::set_intersection(mask->begin(), mask->end(), main->begin(), main->end(),
148 * std::inserter(tmp_combined, tmp_combined.end()),
149 * [](auto& a, auto& b) { return a.first < b.first; });
150 * return HFilter(&tmp_combined).begin/get/size();
151 */
152class HFilter {
153 Filter* main_;
154 const Filter* mask_;
155
156public:
170 gamenumT gnum_;
171 gamenumT end_;
172 const HFilter* hfilter_;
173 bool inFilter_;
174
175 public:
176 typedef std::forward_iterator_tag iterator_category;
177 typedef std::ptrdiff_t difference_type;
178 typedef gamenumT value_type;
179 typedef const gamenumT* pointer;
180 typedef const gamenumT& reference;
181
182 const_iterator(gamenumT gnum, gamenumT end, const HFilter* hfilter,
183 bool inFilter = true)
184 : gnum_(gnum), end_(end), hfilter_(hfilter), inFilter_(inFilter) {
185 ASSERT(hfilter != 0);
186 if (gnum_ != end_) {
187 bool included = (hfilter_->get(gnum_) != 0);
188 if (included != inFilter_)
189 operator++();
190 }
191 }
192
193 reference operator*() const { return gnum_; }
194
195 const_iterator& operator++() {
196 while (++gnum_ != end_) {
197 bool included = (hfilter_->get(gnum_) != 0);
198 if (included == inFilter_)
199 break;
200 }
201 return *this;
202 }
203
204 bool operator!=(const const_iterator& b) const {
205 return gnum_ != b.gnum_ || hfilter_ != b.hfilter_;
206 }
207 bool operator==(const const_iterator& b) const {
208 return !operator!=(b);
209 }
210 };
211
212 const_iterator begin() const {
213 return const_iterator(0, main_->Size(), this);
214 }
215 const_iterator end() const {
216 return const_iterator(main_->Size(), main_->Size(), this);
217 }
218 const_iterator beginInverted() const {
219 return const_iterator(0, main_->Size(), this, false);
220 }
221 const_iterator endInverted() const {
222 return const_iterator(main_->Size(), main_->Size(), this, false);
223 }
224 size_t sizeInverted() const { return main_->Size() - size(); }
225
226public: // Pointer interface
227 bool operator==(const Filter* b) const { return main_ == b; }
228 bool operator!=(const Filter* b) const { return main_ != b; }
229 HFilter* operator->() { return this; }
230 const HFilter* operator->() const { return this; }
231 HFilter& operator*() { return *this; }
232 const HFilter& operator*() const { return *this; }
233
234public:
235 explicit HFilter(Filter* main, const Filter* mask = 0)
236 : main_(main), mask_(mask) {}
237
238 Filter* mainFilter() const { return main_; }
239 const Filter* maskFilter() const { return mask_; }
240
241 void clear() { return main_->Fill(0); }
242 void erase(gamenumT gnum) { return main_->Set(gnum, 0); }
243 void insert_or_assign(gamenumT gnum, uint8_t ply) {
244 return main_->Set(gnum, ply + 1);
245 }
246 gamenumT size() const {
247 if (!mask_ || mask_->Count() == mask_->Size())
248 return main_->Count();
249 if (main_->Count() == main_->Size())
250 return mask_->Count();
251 return static_cast<gamenumT>(std::distance(begin(), end()));
252 }
253
255 size_t mainSize() const { return main_->Count(); }
256
257 /* Convenience function, behave like:
258 * for (gamenumT gnum = 0; gnum < scidBaseT::numGames(); gnum++)
259 * std:map::insert_or_assign(gnum, 0);
260 */
261 void includeAll() { return main_->Fill(1); }
262
263 /* Convenience function, behave like:
264 * auto it = std::map::find(gnum);
265 * if (it == std::map::end()) return 0;
266 * return 1 + it->second;
267 */
268 scid::core::byte get(gamenumT gnum) const {
269 scid::core::byte res = main_->Get(gnum);
270 if (res != 0 && mask_ != 0)
271 res = mask_->Get(gnum);
272
273 return res;
274 }
275
276 /* Convenience function, behave like:
277 * if (value == 0)
278 * erase(gnum);
279 * else
280 * insert_or_assign(gnum, value - 1);
281 */
282 void set(gamenumT gnum, scid::core::byte value) { return main_->Set(gnum, value); }
283};
284
298 const HFilter& hfilter_;
299
300public:
301 explicit HFilterInverted(const HFilter& hfilter) : hfilter_(hfilter) {
302 ASSERT(hfilter != 0);
303 }
304 HFilter::const_iterator begin() const { return hfilter_.beginInverted(); }
305 HFilter::const_iterator end() const { return hfilter_.endInverted(); }
306 size_t size() const { return hfilter_.sizeInverted(); }
307};
308
309
310} // namespace scid::database
311#endif
Definition hfilter.h:38
void Fill(scid::core::byte value)
Sets all values.
Definition hfilter.h:112
scid::core::byte Get(gamenumT index) const
Gets the value at index.
Definition hfilter.h:86
gamenumT Size() const
Return the number of elements in filter.
Definition hfilter.h:60
gamenumT Count() const
Return the number of nonzero values in filter.
Definition hfilter.h:57
void Resize(gamenumT size)
Changes the number of elements stored.
Definition hfilter.h:63
scid::core::byte * data()
Return a pointer to the allocated data.
Definition hfilter.h:54
void Set(gamenumT index, scid::core::byte value)
Sets the value at index.
Definition hfilter.h:92
class HFilterInverted - iterate through games excluded from a filter
Definition hfilter.h:297
class const_iterator - iterator for HFilter objects
Definition hfilter.h:169
Definition hfilter.h:152
size_t mainSize() const
Returns the number of games included in the main filter.
Definition hfilter.h:255
class StrRange - parse a string interpreting its content as 1 or 2 integers separated by whitespace.
Definition common.h:30