1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Merge pull request #894 from vcmi/optimization_rebase

Bonus and string optimization
This commit is contained in:
DjWarmonger 2022-09-14 13:03:30 +02:00 committed by GitHub
commit 627b63ca56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 18 deletions

View File

@ -555,6 +555,7 @@ void BonusList::getBonuses(BonusList & out, const CSelector &selector) const
void BonusList::getBonuses(BonusList & out, const CSelector &selector, const CSelector &limit) const
{
out.reserve(bonuses.size());
for (auto & b : bonuses)
{
//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
@ -620,6 +621,11 @@ void BonusList::resize(BonusList::TInternalContainer::size_type sz, std::shared_
changed();
}
void BonusList::reserve(TInternalContainer::size_type sz)
{
bonuses.reserve(sz);
}
void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusList::TInternalContainer::size_type n, std::shared_ptr<Bonus> const &x)
{
bonuses.insert(position, n, x);
@ -654,14 +660,16 @@ int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector)
int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype) const
{
boost::format fmt("type_%ds_%d");
fmt % (int)type % subtype;
//This part is performance-critical
char cachingStr[20] = {};
std::sprintf(cachingStr, "type_%ds_%d", (int)type, subtype);
CSelector s = Selector::type()(type);
if(subtype != -1)
s = s.And(Selector::subtype()(subtype));
return valOfBonuses(s, fmt.str());
return valOfBonuses(s, cachingStr);
}
int IBonusBearer::valOfBonuses(const CSelector &selector, const std::string &cachingStr) const
@ -672,6 +680,7 @@ int IBonusBearer::valOfBonuses(const CSelector &selector, const std::string &cac
}
bool IBonusBearer::hasBonus(const CSelector &selector, const std::string &cachingStr) const
{
//TODO: We don't need to count all bonuses and could break on first matching
return getBonuses(selector, cachingStr)->size() > 0;
}
@ -682,14 +691,15 @@ bool IBonusBearer::hasBonus(const CSelector &selector, const CSelector &limit, c
bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype) const
{
boost::format fmt("type_%ds_%d");
fmt % (int)type % subtype;
//This part is performance-ciritcal
char cachingStr[20] = {};
std::sprintf(cachingStr, "type_%ds_%d", (int)type, subtype);
CSelector s = Selector::type()(type);
if(subtype != -1)
s = s.And(Selector::subtype()(subtype));
return hasBonus(s, fmt.str());
return hasBonus(s, cachingStr);
}
TConstBonusListPtr IBonusBearer::getBonuses(const CSelector &selector, const std::string &cachingStr) const
@ -943,16 +953,29 @@ void CBonusSystemNode::getAllParents(TCNodes & out) const //retrieves list of pa
void CBonusSystemNode::getAllBonusesRec(BonusList &out) const
{
//out has been reserved sufficient capacity at getAllBonuses() call
BonusList beforeUpdate;
TCNodes lparents;
getAllParents(lparents);
for(auto parent : lparents)
parent->getAllBonusesRec(beforeUpdate);
if (lparents.size())
{
//estimate on how many bonuses are missing yet - must be positive
beforeUpdate.reserve(std::max(out.capacity() - out.size(), bonuses.size()));
}
else
{
beforeUpdate.reserve(bonuses.size()); //at most all local bonuses
}
for (auto parent : lparents)
{
parent->getAllBonusesRec(beforeUpdate);
}
bonuses.getAllBonuses(beforeUpdate);
for(auto b : beforeUpdate)
for(const auto & b : beforeUpdate)
{
auto updated = b->updater
? getUpdatedBonus(b, b->updater)
@ -976,10 +999,12 @@ TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, co
// cache all bonus objects. Selector objects doesn't matter.
if (cachedLast != treeChanged)
{
BonusList allBonuses;
allBonuses.reserve(cachedBonuses.capacity()); //we assume we'll get about the same number of bonuses
cachedBonuses.clear();
cachedRequests.clear();
BonusList allBonuses;
getAllBonusesRec(allBonuses);
limitBonuses(allBonuses, cachedBonuses);
cachedBonuses.stackBonuses();

View File

@ -549,6 +549,8 @@ public:
void clear();
bool empty() const { return bonuses.empty(); }
void resize(TInternalContainer::size_type sz, std::shared_ptr<Bonus> c = nullptr );
void reserve(TInternalContainer::size_type sz);
TInternalContainer::size_type capacity() const { return bonuses.capacity(); }
STRONG_INLINE std::shared_ptr<Bonus> &operator[] (TInternalContainer::size_type n) { return bonuses[n]; }
STRONG_INLINE const std::shared_ptr<Bonus> &operator[] (TInternalContainer::size_type n) const { return bonuses[n]; }
std::shared_ptr<Bonus> &back() { return bonuses.back(); }

View File

@ -158,11 +158,11 @@ public:
//returns "(x y z)" string
std::string toString() const
{
std::string result("(");
result += boost::lexical_cast<std::string>(x); result += ' ';
result += boost::lexical_cast<std::string>(y); result += ' ';
result += boost::lexical_cast<std::string>(z); result += ')';
return result;
//Performance is important here
char str[16] = {};
std::sprintf(str, "(%d %d %d)", x, y, z);
return std::string(str);
}
bool valid() const //Should be named "isValid"?

View File

@ -76,7 +76,11 @@ void CArmedInstance::updateMoraleBonusFromArmy()
factions.insert(creature->faction);
// Check for undead flag instead of faction (undead mummies are neutral)
hasUndead |= inst->hasBonus(undeadSelector, undeadCacheKey);
if (!hasUndead)
{
//this is costly check, let's skip it at first undead
hasUndead |= inst->hasBonus(undeadSelector, undeadCacheKey);
}
}
size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account