1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Reduce size of Bonus struct from 320 bytes to 296 bytes.

- Internal enums were resized to occupy single byte.
- Duration bitmask uses 16 bit integer directly instead of std::bitset<11> which consumed 8 bytes.
- Fields shuffled to minimise padding and keep the most useful data on first 2 cache lines.
This commit is contained in:
K 2024-07-14 16:56:58 +02:00
parent 6f5710e809
commit c1e6bbddfe
5 changed files with 50 additions and 42 deletions

View File

@ -119,7 +119,7 @@ std::string Bonus::Description(std::optional<si32> customValue) const
if(descriptionHelper.empty())
{
// still no description - try to generate one based on duration
if ((duration & BonusDuration::ONE_BATTLE).any())
if ((duration & BonusDuration::ONE_BATTLE) != 0)
{
if (val > 0)
descriptionHelper.appendTextID("core.arraytxt.110"); //+%d Temporary until next battle"
@ -248,7 +248,7 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
#define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
printField(val);
out << "\tSubtype: " << bonus.subtype.toString() << "\n";
printField(duration.to_ulong());
printField(duration);
printField(source);
out << "\tSource ID: " << bonus.sid.toString() << "\n";
if(bonus.additionalInfo != CAddInfo::NONE)

View File

@ -58,21 +58,22 @@ public:
/// Struct for handling bonuses of several types. Can be transferred to any hero
struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>, public Serializeable
{
BonusDuration::Type duration = BonusDuration::PERMANENT; //uses BonusDuration values
BonusDuration::Type duration = BonusDuration::PERMANENT; //uses BonusDuration values - 2 bytes
si16 turnsRemain = 0; //used if duration is N_TURNS, N_DAYS or ONE_WEEK
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 1 byte
BonusSubtypeID subtype;
BonusSource source = BonusSource::OTHER; //source type" uses BonusSource values - what gave that bonus
BonusSource targetSourceType = BonusSource::OTHER;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE.
si32 val = 0;
BonusValueType valType = BonusValueType::ADDITIVE_VALUE; // 1 byte
BonusSource source = BonusSource::OTHER; //source type" uses BonusSource values - what gave that bonus - 1 byte
BonusSource targetSourceType = BonusSource::OTHER;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE. - 1 byte
BonusType type = BonusType::NONE; //uses BonusType values - says to what is this bonus - 1 byte
BonusLimitEffect effectRange = BonusLimitEffect::NO_LIMIT; // 1 byte
// 3 bytes padding
BonusSubtypeID subtype;
BonusSourceID sid; //source id: id of object/artifact/spell
BonusValueType valType = BonusValueType::ADDITIVE_VALUE;
std::string stacking; // bonuses with the same stacking value don't stack (e.g. Angel/Archangel morale bonus)
CAddInfo additionalInfo;
BonusLimitEffect effectRange = BonusLimitEffect::NO_LIMIT;
TLimiterPtr limiter;
TPropagatorPtr propagator;
@ -128,57 +129,57 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>, public Se
static bool NDays(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::N_DAYS;
return set.any();
return set != 0;
}
static bool NTurns(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::N_TURNS;
return set.any();
return set != 0;
}
static bool OneDay(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::ONE_DAY;
return set.any();
return set != 0;
}
static bool OneWeek(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::ONE_WEEK;
return set.any();
return set != 0;
}
static bool OneBattle(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::ONE_BATTLE;
return set.any();
return set != 0;
}
static bool Permanent(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::PERMANENT;
return set.any();
return set != 0;
}
static bool UntilGetsTurn(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::STACK_GETS_TURN;
return set.any();
return set != 0;
}
static bool UntilAttack(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::UNTIL_ATTACK;
return set.any();
return set != 0;
}
static bool UntilBeingAttacked(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::UNTIL_BEING_ATTACKED;
return set.any();
return set != 0;
}
static bool UntilCommanderKilled(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::COMMANDER_KILLED;
return set.any();
return set != 0;
}
static bool UntilOwnAttack(const Bonus *hb)
{
auto set = hb->duration & BonusDuration::UNTIL_OWN_ATTACK;
return set.any();
return set != 0;
}
inline bool operator == (const BonusType & cf) const
{

View File

@ -60,10 +60,11 @@ namespace BonusDuration
JsonNode toJson(const Type & duration)
{
std::vector<std::string> durationNames;
for(auto durBit = 0; durBit < duration.size(); durBit++)
for(size_t durBit = 0; durBit < Size; durBit++)
{
if(duration[durBit])
durationNames.push_back(vstd::findKey(bonusDurationMap, duration & Type().set(durBit)));
Type value = duration & (1 << durBit);
if(value)
durationNames.push_back(vstd::findKey(bonusDurationMap, value));
}
if(durationNames.size() == 1)
{

View File

@ -212,7 +212,7 @@ class JsonNode;
BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY bonus
enum class BonusType
enum class BonusType : uint8_t
{
#define BONUS_NAME(x) x,
BONUS_LIST
@ -220,21 +220,27 @@ enum class BonusType
};
namespace BonusDuration //when bonus is automatically removed
{
using Type = std::bitset<11>;
// We use uint16_t directly because std::bitset<11> eats whole 8 byte word.
using Type = uint16_t;
constexpr static size_t Size = 11;
enum BonusDuration : Type {
PERMANENT = 1 << 0,
ONE_BATTLE = 1 << 1, //at the end of battle
ONE_DAY = 1 << 2, //at the end of day
ONE_WEEK = 1 << 3, //at the end of week (bonus lasts till the end of week, thats NOT 7 days
N_TURNS = 1 << 4, //used during battles, after battle bonus is always removed
N_DAYS = 1 << 5,
UNTIL_BEING_ATTACKED = 1 << 6, /*removed after attack and counterattacks are performed*/
UNTIL_ATTACK = 1 << 7, /*removed after attack and counterattacks are performed*/
STACK_GETS_TURN = 1 << 8, /*removed when stack gets its turn - used for defensive stance*/
COMMANDER_KILLED = 1 << 9,
UNTIL_OWN_ATTACK = 1 << 10 /*removed after attack is performed (not counterattack)*/,
};
extern JsonNode toJson(const Type & duration);
constexpr Type PERMANENT = 1 << 0;
constexpr Type ONE_BATTLE = 1 << 1; //at the end of battle
constexpr Type ONE_DAY = 1 << 2; //at the end of day
constexpr Type ONE_WEEK = 1 << 3; //at the end of week (bonus lasts till the end of week, thats NOT 7 days
constexpr Type N_TURNS = 1 << 4; //used during battles, after battle bonus is always removed
constexpr Type N_DAYS = 1 << 5;
constexpr Type UNTIL_BEING_ATTACKED = 1 << 6; /*removed after attack and counterattacks are performed*/
constexpr Type UNTIL_ATTACK = 1 << 7; /*removed after attack and counterattacks are performed*/
constexpr Type STACK_GETS_TURN = 1 << 8; /*removed when stack gets its turn - used for defensive stance*/
constexpr Type COMMANDER_KILLED = 1 << 9;
constexpr Type UNTIL_OWN_ATTACK = 1 << 10; /*removed after attack is performed (not counterattack)*/;
};
enum class BonusSource
enum class BonusSource : uint8_t
{
#define BONUS_SOURCE(x) x,
BONUS_SOURCE_LIST
@ -242,13 +248,13 @@ enum class BonusSource
NUM_BONUS_SOURCE /*This is a dummy value, which will be always last*/
};
enum class BonusLimitEffect
enum class BonusLimitEffect : uint8_t
{
NO_LIMIT = 0,
ONLY_DISTANCE_FIGHT=1, ONLY_MELEE_FIGHT, //used to mark bonuses for attack/defense primary skills from spells like Precision (distance only)
};
enum class BonusValueType
enum class BonusValueType : uint8_t
{
#define BONUS_VALUE(x) x,
BONUS_VALUE_LIST

View File

@ -19,7 +19,7 @@ class CBattleInfoCallback;
struct BattleHex;
class CStack;
class PlayerColor;
enum class BonusType;
enum class BonusType : uint8_t;
namespace battle
{