LCOV - code coverage report
Current view: top level - src - hfilter.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 120 120 100.0 %
Date: 2019-01-29 11:06:41 Functions: 38 38 100.0 %

          Line data    Source code
       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         398 : 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         398 :         explicit Filter(gamenumT size)
      43         398 :             : size_(size), nonzero_(size), capacity_(0) {}
      44             : 
      45          56 :         void Init(gamenumT size) {
      46          56 :                 data_ = nullptr;
      47          56 :                 nonzero_ = size_ = size;
      48          56 :         }
      49             : 
      50             :         /// Return a pointer to the allocated data.
      51           4 :         byte* data() { return data_.get(); }
      52             : 
      53             :         /// Return the number of nonzero values in filter.
      54       16783 :         gamenumT Count() const { return nonzero_; }
      55             : 
      56             :         /// Return the number of elements in filter.
      57     3851084 :         gamenumT Size() const { return size_; }
      58             : 
      59             :         /// Changes the number of elements stored.
      60          27 :         void Resize(gamenumT size) {
      61          27 :                 if (!data_) {
      62          22 :                         nonzero_ = size;
      63           5 :                 } else if (size < size_) {
      64           4 :                         nonzero_ = size - static_cast<gamenumT>(std::count(
      65           2 :                                               data_.get(), data_.get() + size, 0));
      66           3 :                 } else if (size > size_) {
      67           3 :                         if (size > capacity_) {
      68           2 :                                 auto tmp(std::move(data_));
      69           1 :                                 allocate(size);
      70           1 :                                 std::copy_n(tmp.get(), size_, data_.get());
      71             :                         }
      72           3 :                         byte val = 0;
      73           3 :                         if (Count() == Size()) {
      74           1 :                                 val = 1;
      75           1 :                                 nonzero_ = size;
      76             :                         }
      77           3 :                         std::fill(data_.get() + size_, data_.get() + size, val);
      78             :                 }
      79          27 :                 size_ = size;
      80          27 :         }
      81             : 
      82             :         /// Gets the value at index.
      83     3844553 :         byte Get(gamenumT index) const {
      84     3844553 :                 ASSERT(index < Size());
      85     3844553 :                 return data_ ? data_[index] : 1;
      86             :         }
      87             : 
      88             :         /// Sets the value at index.
      89        3385 :         void Set(gamenumT index, byte value) {
      90        3385 :                 ASSERT(index < Size());
      91        3385 :                 if (data_) {
      92        2770 :                         if (value == 0) {
      93        1663 :                                 if (data_[index] != 0)
      94        1466 :                                         --nonzero_;
      95        1107 :                         } else if (data_[index] == 0) {
      96         173 :                                 ++nonzero_;
      97             :                         }
      98        2770 :                         data_[index] = value;
      99         615 :                 } else if (value != 1) {
     100         203 :                         allocate(size_);
     101         203 :                         std::fill(data_.get(), data_.get() + size_, 1);
     102         203 :                         data_[index] = value;
     103         203 :                         if (value == 0)
     104          98 :                                 --nonzero_;
     105             :                 }
     106        3385 :         }
     107             : 
     108             :         /// Sets all values.
     109          42 :         void Fill(byte value) {
     110          42 :                 if (value == 1) {
     111          20 :                         data_ = nullptr;
     112          20 :                         nonzero_ = size_;
     113             :                 } else {
     114          22 :                         if (!data_) {
     115           9 :                                 allocate(size_);
     116             :                         }
     117          22 :                         std::fill(data_.get(), data_.get() + size_, value);
     118          22 :                         nonzero_ = (value == 0) ? 0 : size_;
     119             :                 }
     120          42 :         }
     121             : 
     122             : private:
     123         213 :         void allocate(size_t size) {
     124         213 :                 auto capacity = (size | 63) + 1;
     125         213 :                 data_ = std::make_unique<byte[]>(capacity);
     126         213 :                 capacity_ = capacity;
     127         213 :         }
     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             :          */
     166             :         class const_iterator {
     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;
     175             :                 typedef gamenumT value_type;
     176             :                 typedef const gamenumT* pointer;
     177             :                 typedef const gamenumT& reference;
     178             : 
     179        1778 :                 const_iterator(gamenumT gnum, gamenumT end, const HFilter* hfilter,
     180             :                                bool inFilter = true)
     181        1778 :                     : gnum_(gnum), end_(end), hfilter_(hfilter), inFilter_(inFilter) {
     182        1778 :                         ASSERT(hfilter != 0);
     183        1778 :                         if (gnum_ != end_) {
     184         825 :                                 bool included = (hfilter_->get(gnum_) != 0);
     185         825 :                                 if (included != inFilter_)
     186         512 :                                         operator++();
     187             :                         }
     188        1778 :                 }
     189             : 
     190        1067 :                 reference operator*() const { return gnum_; }
     191             : 
     192        4950 :                 const_iterator& operator++() {
     193        8033 :                         while (++gnum_ != end_) {
     194        4125 :                                 bool included = (hfilter_->get(gnum_) != 0);
     195        4125 :                                 if (included == inFilter_)
     196        1042 :                                         break;
     197             :                         }
     198        1867 :                         return *this;
     199             :                 }
     200             : 
     201        2196 :                 bool operator!=(const const_iterator& b) const {
     202        2196 :                         return gnum_ != b.gnum_ || hfilter_ != b.hfilter_;
     203             :                 }
     204         438 :                 bool operator==(const const_iterator& b) const {
     205         438 :                         return !operator!=(b);
     206             :                 }
     207             :         };
     208             : 
     209         787 :         const_iterator begin() const {
     210         787 :                 return const_iterator(0, main_->Size(), this);
     211             :         }
     212         883 :         const_iterator end() const {
     213         883 :                 return const_iterator(main_->Size(), main_->Size(), this);
     214             :         }
     215          54 :         const_iterator beginInverted() const {
     216          54 :                 return const_iterator(0, main_->Size(), this, false);
     217             :         }
     218          54 :         const_iterator endInverted() const {
     219          54 :                 return const_iterator(main_->Size(), main_->Size(), this, false);
     220             :         }
     221          36 :         size_t sizeInverted() const { return main_->Size() - size(); }
     222             : 
     223             : public: // Pointer interface
     224       17427 :         bool operator==(const Filter* b) const { return main_ == b; }
     225       27298 :         bool operator!=(const Filter* b) const { return main_ != b; }
     226        2240 :         HFilter* operator->() { return this; }
     227     3841742 :         const HFilter* operator->() const { return this; }
     228          36 :         HFilter& operator*() { return *this; }
     229             :         const HFilter& operator*() const { return *this; }
     230             : 
     231             : public:
     232       36713 :         explicit HFilter(Filter* main = 0, const Filter* mask = 0)
     233       36713 :             : main_(main), mask_(mask) {}
     234             : 
     235          19 :         void clear() { return main_->Fill(0); }
     236         206 :         void erase(gamenumT gnum) { return main_->Set(gnum, 0); }
     237         179 :         void insert_or_assign(gamenumT gnum, uint8_t ply) {
     238         179 :                 return main_->Set(gnum, ply + 1);
     239             :         }
     240       16676 :         size_t size() const {
     241       16676 :                 if (mask_ == 0)
     242       16310 :                         return main_->Count();
     243         366 :                 if (main_->Count() == main_->Size())
     244          89 :                         return mask_->Count();
     245         277 :                 const_iterator::difference_type res = std::distance(begin(), end());
     246         277 :                 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          18 :         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     3842004 :         byte get(gamenumT gnum) const {
     261     3842004 :                 byte res = main_->Get(gnum);
     262     3842004 :                 if (res != 0 && mask_ != 0)
     263        2549 :                         res = mask_->Get(gnum);
     264             : 
     265     3842004 :                 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        1531 :         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             :  */
     289             : class HFilterInverted {
     290             :         const HFilter& hfilter_;
     291             : 
     292             : public:
     293          54 :         explicit HFilterInverted(const HFilter& hfilter) : hfilter_(hfilter) {
     294          54 :                 ASSERT(hfilter != 0);
     295          54 :         }
     296          36 :         HFilter::const_iterator begin() const { return hfilter_.beginInverted(); }
     297          36 :         HFilter::const_iterator end() const { return hfilter_.endInverted(); }
     298          18 :         size_t size() const { return hfilter_.sizeInverted(); }
     299             : };
     300             : 
     301             : #endif

Generated by: LCOV version 1.13