33 #ifndef MULTITHREADING_OFF 39 void SortCache::th_join() {
41 static_cast<std::thread*
>(th_)->join();
42 delete static_cast<std::thread*
>(th_);
53 void SortCache::th_sort() {
54 size_t nGames = this->nGames_;
58 auto comp = SortCache::CmpLess(
this);
60 std::iota(begin, end, 0);
64 ASSERT(nGames <
size_t(INT_MAX / 2));
65 const int lastNode =
static_cast<int>(nGames) - 1;
66 const auto lastRoot = (lastNode - 1) / 2;
67 for (
auto node = lastRoot; node >= 0; --node) {
68 if (this->th_interrupt_)
71 for (
auto toSift = node;;) {
72 const auto leftChild = 2 * toSift + 1;
73 const auto rightChild = 2 * toSift + 2;
74 if (leftChild > lastNode)
76 int maxChild = (rightChild <= lastNode && comp(v[leftChild], v[rightChild]))
79 if (!comp(v[toSift], v[maxChild]))
81 std::swap(v[toSift], v[maxChild]);
85 ASSERT(std::is_heap(begin, end, comp));
89 for (
auto it = end; it != begin; --it) {
90 if (this->th_interrupt_)
92 std::pop_heap(begin, it, comp);
94 ASSERT(std::is_sorted(begin, end, comp));
96 this->valid_fullMap_ =
true;
100 void SortCache::th_join() {}
101 void SortCache::th_sort() {}
105 SortCache::SortCache(
const Index* idx,
const NameBase* nbase)
106 : nGames_(0), valid_fullMap_(false), th_interrupt_(false),
107 partialHash_(false), fullMap_(NULL), th_(NULL), hash_(NULL), index_(idx),
108 nbase_(nbase), refCount_(0) {}
117 const char* criteria) {
118 ASSERT(idx != NULL && nb != NULL && criteria != NULL);
120 static const char fields[] = {
121 SORTING_date, SORTING_year, SORTING_event,
122 SORTING_site, SORTING_round, SORTING_white,
123 SORTING_black, SORTING_eco, SORTING_result,
124 SORTING_moveCount, SORTING_avgElo, SORTING_country,
125 SORTING_deleted, SORTING_eventdate, SORTING_whiteelo,
126 SORTING_blackelo, SORTING_commentcount, SORTING_varcount,
127 SORTING_nagcount, SORTING_resultwin, SORTING_resultdraw,
128 SORTING_resultloss, SORTING_rating, SORTING_number,
130 static const char* fields_end = fields +
sizeof(fields);
132 if (*criteria ==
'\0')
139 for (
const char *it = criteria; *it != 0; ++it) {
140 bool valid =
std::find(fields, fields_end, *it) != fields_end;
141 sc->criteria_[i++] = *it++;
142 bool reverse = (*it !=
'+');
143 sc->criteria_[i++] = reverse ? 1 : 0;
145 || (reverse && *it !=
'-')
146 || i >=
sizeof(sc->criteria_))
152 sc->criteria_[i] = SORTING_sentinel;
154 sc->generateHashCache();
155 sc->sortAsynchronously();
162 ASSERT(filter != NULL && filter->
size() <= nGames_);
165 size_t maxResults = filter->
size();
166 if (row_count == 0 || row_offset >= maxResults)
169 size_t row_end = std::min(row_offset + row_count, maxResults);
171 if (!valid_fullMap_) {
174 if (maxResults == nGames_) {
176 for (
gamenumT i = 0; i < maxResults; ++i) {
184 if (row_offset > 1000) {
186 std::nth_element(v, v + row_offset, v_end, CmpLess(
this));
188 std::partial_sort(v + skip, v + row_end, v_end, CmpLess(
this));
189 std::copy(v + row_offset, v + row_end, result);
192 if (maxResults == nGames_) {
193 std::copy(fullMap_ + row_offset, fullMap_ + row_end, result);
195 size_t filterCount = 0;
197 for (; filterCount < row_offset; i++) {
198 if (filter->
get(fullMap_[i]) != 0)
201 for (; filterCount != row_end; i++) {
202 if (filter->
get(fullMap_[i]) != 0) {
203 *result++ = fullMap_[i];
210 return row_end - row_offset;
214 ASSERT(filter != 0 && filter->
size() <= nGames_);
215 ASSERT(gameId < nGames_ && filter->
get(gameId) != 0);
218 if (valid_fullMap_) {
219 for (
gamenumT i = 0; i < nGames_; i++) {
220 if (filter->
get(fullMap_[i]) == 0)
222 if (fullMap_[i] == gameId)
228 for (
gamenumT i = 0; i < nGames_; i++) {
229 if (filter->
get(i) == 0)
242 sortAsynchronously();
244 hash_[id] = calcHash(
id);
245 if (valid_fullMap_) {
254 if (it != begin && comp(*it, *(it - 1))) {
256 std::upper_bound(begin, it, *it, comp),
258 }
else if (it + 1 != end && comp(*(it + 1), *it)) {
261 std::lower_bound(it + 1, end, *it, comp));
263 ASSERT(std::is_sorted(begin, end, comp));
265 sortAsynchronously();
273 void SortCache::generateHashCache() {
276 valid_fullMap_ =
false;
277 nGames_ = index_->GetNumGames();
281 hash_ =
new uint32_t[nGames_];
282 for (
gamenumT i = 0; i < nGames_; i++) {
283 hash_[i] = calcHash(i);
291 void SortCache::sortAsynchronously() {
294 #ifndef MULTITHREADING_OFF 297 th_ =
new std::thread(&SortCache::th_sort,
this);
309 ASSERT(g1 < sc_->nGames_ && g2 < sc_->nGames_);
311 if (sc_->hash_[g1] != sc_->hash_[g2])
312 return sc_->hash_[g1] < sc_->hash_[g2];
313 if (!sc_->partialHash_)
316 int cmp = sc_->fullCompare(g1, g2);
323 static const int RESULT_SORT[] = { 0, 3, 1, 2 };
327 return (id1 == id2) ? 0
342 const IndexEntry *ie1 = index_->GetEntry(left);
343 const IndexEntry *ie2 = index_->GetEntry(right);
345 for (
const char* field = criteria_; *field != SORTING_sentinel; field += 2) {
360 case SORTING_moveCount:
380 case SORTING_round: {
390 case SORTING_resultwin:
394 case SORTING_resultdraw:
398 case SORTING_resultloss:
414 case SORTING_country:
418 size_t slenOne = std::strlen(sOne);
419 size_t slenTwo = std::strlen(sTwo);
420 if (slenOne > 3) { sOne += slenOne - 3; }
421 if (slenTwo > 3) { sTwo += slenTwo - 3; }
426 case SORTING_deleted:
430 case SORTING_eventdate:
434 case SORTING_whiteelo:
438 case SORTING_blackelo:
442 case SORTING_commentcount:
446 case SORTING_varcount:
450 case SORTING_nagcount:
459 res = (int) left - (
int) right;
468 return *(field + 1) ? -res : res;
479 uint32_t SortCache::calcHash(
gamenumT gameId) {
480 uint64_t retValue = 0;
481 const size_t nHashBits = 32;
482 size_t totalBitsUsed = 0;
483 const IndexEntry* ie = index_->GetEntry(gameId);
485 for (
const char* field = criteria_; *field != SORTING_sentinel; ++field) {
491 bitsUsed = nHashBits;
496 bitsUsed = nHashBits;
501 bitsUsed = nHashBits;
506 bitsUsed = nHashBits;
511 bitsUsed = nHashBits;
514 case SORTING_country:
517 size_t slen = std::strlen(scountry);
519 scountry += slen - 3;
521 bitsUsed = nHashBits;
529 case SORTING_eventdate:
537 case SORTING_whiteelo:
541 case SORTING_blackelo:
553 case SORTING_resultwin:
557 case SORTING_resultdraw:
561 case SORTING_resultloss:
565 case SORTING_moveCount:
573 case SORTING_commentcount:
577 case SORTING_varcount:
581 case SORTING_nagcount:
585 case SORTING_deleted:
606 if (
sizeof(value) * 8 > bitsUsed) {
608 value <<=
sizeof(value) * 8 - bitsUsed;
609 value >>=
sizeof(value) * 8 - bitsUsed;
613 retValue <<= bitsUsed;
615 totalBitsUsed += bitsUsed;
618 if (totalBitsUsed > nHashBits) {
619 retValue >>= totalBitsUsed - nHashBits;
623 if (totalBitsUsed == nHashBits) {
624 if (*(field + 1) != SORTING_sentinel)
630 return static_cast<uint32_t
>(retValue);
const_iterator end() const
const char * GetBlackName(const NameBase *nb) const
uint32_t strStartHash(const char *str)
resultT GetResult() const
idNumberT GetSite() const
size_t select(size_t row_offset, size_t row_count, const HFilter &filter, gamenumT *result) const
Retrieve the sorted list of games' ids.
const char * GetWhiteName(const NameBase *nb) const
const char * GetEventName(const NameBase *nb) const
idNumberT GetEvent() const
const resultT RESULT_Black
byte get(gamenumT gnum) const
int strCompareRound(const char *str1, const char *str2)
uint16_t GetNumHalfMoves() const
const char * GetName(nameT nt, idNumberT id) const
Retrieve a name.
const resultT RESULT_Draw
size_t sortedPosition(gamenumT gameId, const HFilter &filter) const
Get the sorted position of a game.
int find(const char *filename)
find() - search for a database.
Defines the SortCache class, which sorts the games of an Index.
This class stores the database's names (players, events, sites and rounds).
const resultT RESULT_White
idNumberT GetRound() const
idNumberT GetWhite() const
bool GetDeleteFlag() const
uint GetCommentCount() const
byte GetRating(const NameBase *nb) const
int strCaseCompare(const char *str1, const char *str2)
uint32_t strGetUnsigned(const char *str)
idNumberT GetBlack() const
This class sorts games contained into an Index.
const char * GetSiteName(const NameBase *nb) const
const_iterator begin() const
static SortCache * create(const Index *idx, const NameBase *nb, const char *criteria)
Create a new SortCache object, builds the hash table, and asynchronously sorts all the games...
const char * GetRoundName(const NameBase *nb) const
void checkForChanges(gamenumT gameId)
Notify the object that a game's header data has changed.
uint GetVariationCount() const
dateT GetEventDate() const