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()) if(descriptionHelper.empty())
{ {
// still no description - try to generate one based on duration // 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) if (val > 0)
descriptionHelper.appendTextID("core.arraytxt.110"); //+%d Temporary until next battle" 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" #define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
printField(val); printField(val);
out << "\tSubtype: " << bonus.subtype.toString() << "\n"; out << "\tSubtype: " << bonus.subtype.toString() << "\n";
printField(duration.to_ulong()); printField(duration);
printField(source); printField(source);
out << "\tSource ID: " << bonus.sid.toString() << "\n"; out << "\tSource ID: " << bonus.sid.toString() << "\n";
if(bonus.additionalInfo != CAddInfo::NONE) 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 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 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 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; 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 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) std::string stacking; // bonuses with the same stacking value don't stack (e.g. Angel/Archangel morale bonus)
CAddInfo additionalInfo; CAddInfo additionalInfo;
BonusLimitEffect effectRange = BonusLimitEffect::NO_LIMIT;
TLimiterPtr limiter; TLimiterPtr limiter;
TPropagatorPtr propagator; 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) static bool NDays(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::N_DAYS; auto set = hb->duration & BonusDuration::N_DAYS;
return set.any(); return set != 0;
} }
static bool NTurns(const Bonus *hb) static bool NTurns(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::N_TURNS; auto set = hb->duration & BonusDuration::N_TURNS;
return set.any(); return set != 0;
} }
static bool OneDay(const Bonus *hb) static bool OneDay(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::ONE_DAY; auto set = hb->duration & BonusDuration::ONE_DAY;
return set.any(); return set != 0;
} }
static bool OneWeek(const Bonus *hb) static bool OneWeek(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::ONE_WEEK; auto set = hb->duration & BonusDuration::ONE_WEEK;
return set.any(); return set != 0;
} }
static bool OneBattle(const Bonus *hb) static bool OneBattle(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::ONE_BATTLE; auto set = hb->duration & BonusDuration::ONE_BATTLE;
return set.any(); return set != 0;
} }
static bool Permanent(const Bonus *hb) static bool Permanent(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::PERMANENT; auto set = hb->duration & BonusDuration::PERMANENT;
return set.any(); return set != 0;
} }
static bool UntilGetsTurn(const Bonus *hb) static bool UntilGetsTurn(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::STACK_GETS_TURN; auto set = hb->duration & BonusDuration::STACK_GETS_TURN;
return set.any(); return set != 0;
} }
static bool UntilAttack(const Bonus *hb) static bool UntilAttack(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::UNTIL_ATTACK; auto set = hb->duration & BonusDuration::UNTIL_ATTACK;
return set.any(); return set != 0;
} }
static bool UntilBeingAttacked(const Bonus *hb) static bool UntilBeingAttacked(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::UNTIL_BEING_ATTACKED; auto set = hb->duration & BonusDuration::UNTIL_BEING_ATTACKED;
return set.any(); return set != 0;
} }
static bool UntilCommanderKilled(const Bonus *hb) static bool UntilCommanderKilled(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::COMMANDER_KILLED; auto set = hb->duration & BonusDuration::COMMANDER_KILLED;
return set.any(); return set != 0;
} }
static bool UntilOwnAttack(const Bonus *hb) static bool UntilOwnAttack(const Bonus *hb)
{ {
auto set = hb->duration & BonusDuration::UNTIL_OWN_ATTACK; auto set = hb->duration & BonusDuration::UNTIL_OWN_ATTACK;
return set.any(); return set != 0;
} }
inline bool operator == (const BonusType & cf) const inline bool operator == (const BonusType & cf) const
{ {

View File

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

View File

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

View File

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