SparseMatchFinder.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: SparseMatchFinder.h /////////////////////////////////////////////////////////////////////////
  24. // Author: Steven Johnson, March 2002
  25. // Desc:
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #pragma once
  28. #ifndef __SparseMatchFinder_H_
  29. #define __SparseMatchFinder_H_
  30. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  31. #include "Common/BitFlags.h"
  32. #include "Common/STLTypedefs.h"
  33. #if defined(_DEBUG) || defined(_INTERNAL)
  34. #define SPARSEMATCH_DEBUG
  35. #else
  36. #undef SPARSEMATCH_DEBUG
  37. #endif
  38. //-------------------------------------------------------------------------------------------------
  39. template<class MATCHABLE, class BITSET>
  40. class SparseMatchFinder
  41. {
  42. private:
  43. //-------------------------------------------------------------------------------------------------
  44. // TYPEDEFS
  45. //-------------------------------------------------------------------------------------------------
  46. struct HashMapHelper
  47. {
  48. size_t operator()(const BITSET& p) const
  49. {
  50. /// @todo srj -- provide a better hash function for BITSET
  51. size_t result = 0;
  52. for (int i = 0; i < p.size(); ++i)
  53. if (p.test(i))
  54. result += (i + 1);
  55. return result;
  56. }
  57. Bool operator()(const BITSET& a, const BITSET& b) const
  58. {
  59. return (a == b);
  60. }
  61. };
  62. //-------------------------------------------------------------------------------------------------
  63. typedef std::hash_map< BITSET, const MATCHABLE*, HashMapHelper, HashMapHelper > MatchMap;
  64. //-------------------------------------------------------------------------------------------------
  65. // MEMBER VARS
  66. //-------------------------------------------------------------------------------------------------
  67. mutable MatchMap m_bestMatches;
  68. //-------------------------------------------------------------------------------------------------
  69. // METHODS
  70. //-------------------------------------------------------------------------------------------------
  71. //-------------------------------------------------------------------------------------------------
  72. inline static Int countConditionIntersection(const BITSET& a, const BITSET& b)
  73. {
  74. return a.countIntersection(b);
  75. }
  76. //-------------------------------------------------------------------------------------------------
  77. inline static Int countConditionInverseIntersection(const BITSET& a, const BITSET& b)
  78. {
  79. return a.countInverseIntersection(b);
  80. }
  81. //-------------------------------------------------------------------------------------------------
  82. const MATCHABLE* findBestInfoSlow(const std::vector<MATCHABLE>& v, const BITSET& bits) const
  83. {
  84. const MATCHABLE* result = NULL;
  85. Int bestYesMatch = 0; // want to maximize this
  86. Int bestYesExtraneousBits = 999; // want to minimize this
  87. #ifdef SPARSEMATCH_DEBUG
  88. Int numDupMatches = 0;
  89. AsciiString curBestMatchStr, dupMatchStr;
  90. #endif
  91. for (std::vector<MATCHABLE>::const_iterator it = v.begin(); it != v.end(); ++it)
  92. {
  93. for (Int i = it->getConditionsYesCount()-1; i >= 0; --i)
  94. {
  95. const BITSET& yesFlags = it->getNthConditionsYes(i);
  96. // the best match has the most "yes" matches and the smallest number of "no" matches.
  97. // if there are ties, then prefer the model with the smaller number of irrelevant 'yes' bits.
  98. // (example of why tiebreaker is necessary: if we want to match FRONTCRUSHED,
  99. // it would tie with both FRONTCRUSHED and FRONTCRUSHED|BACKCRUSHED, since they
  100. // both match a single YES bit.)
  101. Int yesMatch = countConditionIntersection(bits, yesFlags);
  102. Int yesExtraneousBits = countConditionInverseIntersection(bits, yesFlags);
  103. #ifdef SPARSEMATCH_DEBUG
  104. if (yesMatch == bestYesMatch &&
  105. yesExtraneousBits == bestYesExtraneousBits)
  106. {
  107. ++numDupMatches;
  108. dupMatchStr = it->getDescription();
  109. }
  110. #endif
  111. if ((yesMatch > bestYesMatch) ||
  112. (yesMatch >= bestYesMatch && yesExtraneousBits < bestYesExtraneousBits))
  113. {
  114. result = &(*it);
  115. bestYesMatch = yesMatch;
  116. bestYesExtraneousBits = yesExtraneousBits;
  117. #ifdef SPARSEMATCH_DEBUG
  118. numDupMatches = 0;
  119. curBestMatchStr = it->getDescription();
  120. #endif
  121. }
  122. } // end for i
  123. } // end for it
  124. #ifdef SPARSEMATCH_DEBUG
  125. if (numDupMatches > 0)
  126. {
  127. AsciiString curConditionStr;
  128. bits.buildDescription(&curConditionStr);
  129. DEBUG_CRASH(("ambiguous model match in findBestInfoSlow \n\nbetween \n(%s)\n<and>\n(%s)\n\n(%d extra matches found)\n\ncurrent bits are (\n%s)\n",
  130. curBestMatchStr.str(),
  131. dupMatchStr.str(),
  132. numDupMatches,
  133. curConditionStr.str()));
  134. }
  135. #endif
  136. return result;
  137. }
  138. //-------------------------------------------------------------------------------------------------
  139. public:
  140. //-------------------------------------------------------------------------------------------------
  141. void clear()
  142. {
  143. m_bestMatches.clear();
  144. }
  145. //-------------------------------------------------------------------------------------------------
  146. const MATCHABLE* findBestInfo(const std::vector<MATCHABLE>& v, const BITSET& bits) const
  147. {
  148. MatchMap::const_iterator it = m_bestMatches.find(bits);
  149. if (it != m_bestMatches.end())
  150. {
  151. return (*it).second;
  152. }
  153. const MATCHABLE* info = findBestInfoSlow(v, bits);
  154. DEBUG_ASSERTCRASH(info != NULL, ("no suitable match for criteria was found!\n"));
  155. if (info != NULL)
  156. m_bestMatches[bits] = info;
  157. return info;
  158. }
  159. };
  160. #endif // __SparseMatchFinder_H_