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