| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: SparseMatchFinder.h /////////////////////////////////////////////////////////////////////////
- // Author: Steven Johnson, March 2002
- // Desc:
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma once
- #ifndef __SparseMatchFinder_H_
- #define __SparseMatchFinder_H_
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "Common/BitFlags.h"
- #include "Common/STLTypedefs.h"
- #if defined(_DEBUG) || defined(_INTERNAL)
- #define SPARSEMATCH_DEBUG
- #else
- #undef SPARSEMATCH_DEBUG
- #endif
- //-------------------------------------------------------------------------------------------------
- template<class MATCHABLE, class BITSET>
- class SparseMatchFinder
- {
- private:
- //-------------------------------------------------------------------------------------------------
- // TYPEDEFS
- //-------------------------------------------------------------------------------------------------
- struct HashMapHelper
- {
- size_t operator()(const BITSET& p) const
- {
- /// @todo srj -- provide a better hash function for BITSET
- size_t result = 0;
- for (int i = 0; i < p.size(); ++i)
- if (p.test(i))
- result += (i + 1);
- return result;
- }
- Bool operator()(const BITSET& a, const BITSET& b) const
- {
- return (a == b);
- }
- };
- //-------------------------------------------------------------------------------------------------
- typedef std::hash_map< BITSET, const MATCHABLE*, HashMapHelper, HashMapHelper > MatchMap;
- //-------------------------------------------------------------------------------------------------
- // MEMBER VARS
- //-------------------------------------------------------------------------------------------------
-
- mutable MatchMap m_bestMatches;
- //-------------------------------------------------------------------------------------------------
- // METHODS
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- inline static Int countConditionIntersection(const BITSET& a, const BITSET& b)
- {
- return a.countIntersection(b);
- }
- //-------------------------------------------------------------------------------------------------
- inline static Int countConditionInverseIntersection(const BITSET& a, const BITSET& b)
- {
- return a.countInverseIntersection(b);
- }
- //-------------------------------------------------------------------------------------------------
- const MATCHABLE* findBestInfoSlow(const std::vector<MATCHABLE>& v, const BITSET& bits) const
- {
- const MATCHABLE* result = NULL;
- Int bestYesMatch = 0; // want to maximize this
- Int bestYesExtraneousBits = 999; // want to minimize this
- #ifdef SPARSEMATCH_DEBUG
- Int numDupMatches = 0;
- AsciiString curBestMatchStr, dupMatchStr;
- #endif
- for (std::vector<MATCHABLE>::const_iterator it = v.begin(); it != v.end(); ++it)
- {
- for (Int i = it->getConditionsYesCount()-1; i >= 0; --i)
- {
- const BITSET& yesFlags = it->getNthConditionsYes(i);
- // the best match has the most "yes" matches and the smallest number of "no" matches.
- // if there are ties, then prefer the model with the smaller number of irrelevant 'yes' bits.
- // (example of why tiebreaker is necessary: if we want to match FRONTCRUSHED,
- // it would tie with both FRONTCRUSHED and FRONTCRUSHED|BACKCRUSHED, since they
- // both match a single YES bit.)
- Int yesMatch = countConditionIntersection(bits, yesFlags);
- Int yesExtraneousBits = countConditionInverseIntersection(bits, yesFlags);
- #ifdef SPARSEMATCH_DEBUG
- if (yesMatch == bestYesMatch &&
- yesExtraneousBits == bestYesExtraneousBits)
- {
- ++numDupMatches;
- dupMatchStr = it->getDescription();
- }
- #endif
- if ((yesMatch > bestYesMatch) ||
- (yesMatch >= bestYesMatch && yesExtraneousBits < bestYesExtraneousBits))
- {
- result = &(*it);
- bestYesMatch = yesMatch;
- bestYesExtraneousBits = yesExtraneousBits;
- #ifdef SPARSEMATCH_DEBUG
- numDupMatches = 0;
- curBestMatchStr = it->getDescription();
- #endif
- }
- } // end for i
- } // end for it
- #ifdef SPARSEMATCH_DEBUG
- if (numDupMatches > 0)
- {
- AsciiString curConditionStr;
- bits.buildDescription(&curConditionStr);
- 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",
- curBestMatchStr.str(),
- dupMatchStr.str(),
- numDupMatches,
- curConditionStr.str()));
- }
- #endif
- return result;
- }
- //-------------------------------------------------------------------------------------------------
- public:
- //-------------------------------------------------------------------------------------------------
- void clear()
- {
- m_bestMatches.clear();
- }
- //-------------------------------------------------------------------------------------------------
- const MATCHABLE* findBestInfo(const std::vector<MATCHABLE>& v, const BITSET& bits) const
- {
- MatchMap::const_iterator it = m_bestMatches.find(bits);
- if (it != m_bestMatches.end())
- {
- return (*it).second;
- }
- const MATCHABLE* info = findBestInfoSlow(v, bits);
- DEBUG_ASSERTCRASH(info != NULL, ("no suitable match for criteria was found!\n"));
- if (info != NULL)
- m_bestMatches[bits] = info;
- return info;
- }
- };
- #endif // __SparseMatchFinder_H_
|