Implement basic library class that other libraries inherit from for performance.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2020-02-15 18:51:21 +01:00
parent a47f60cdf7
commit d6ea16b467
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
11 changed files with 87 additions and 195 deletions

View File

@ -24,14 +24,14 @@ CreateCreature* CreateCreature::WithAttack(const std::string& attackName, Attack
if (_attacks.size() >= _library->GetSettings()->GetMaximalMoves()) if (_attacks.size() >= _library->GetSettings()->GetMaximalMoves())
throw CreatureException("You have already set the maximum amount of allowed moves."); throw CreatureException("You have already set the maximum amount of allowed moves.");
auto attackData = _library->GetAttackLibrary()->GetAttack(attackName); auto attackData = _library->GetAttackLibrary()->Get(attackName.c_str());
_attacks.emplace_back(attackData, learnMethod); _attacks.emplace_back(attackData, learnMethod);
return this; return this;
} }
Creature* CreateCreature::Create() { Creature* CreateCreature::Create() {
auto rand = Core::Random(); auto rand = Core::Random();
auto species = this->_library->GetSpeciesLibrary()->GetSpecies(this->_species); auto species = this->_library->GetSpeciesLibrary()->Get(this->_species.c_str());
auto variant = species->GetVariant(this->_variant); auto variant = species->GetVariant(this->_variant);
int8_t talent; int8_t talent;
if (this->_talent.empty()) { if (this->_talent.empty()) {
@ -49,7 +49,9 @@ Creature* CreateCreature::Create() {
} }
const Library::Item* heldItem = nullptr; const Library::Item* heldItem = nullptr;
if (!this->_heldItem.empty()) { if (!this->_heldItem.empty()) {
heldItem = _library->GetItemLibrary()->GetItem(this->_heldItem); if (!_library->GetItemLibrary()->TryGet(this->_heldItem.c_str(), heldItem)) {
throw CreatureException("Invalid held item.");
}
} }
// FIXME: implement experience // FIXME: implement experience
auto experience = 0; auto experience = 0;

View File

@ -1,37 +1 @@
#include "AttackLibrary.hpp" #include "AttackLibrary.hpp"
bool CreatureLib::Library::AttackLibrary::TryGetAttack(const std::string& name,
const CreatureLib::Library::AttackData*& move) const {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
auto find = _attacks.find(key);
if (find == _attacks.end()) {
move = nullptr;
return false;
}
move = find->second;
return true;
}
const CreatureLib::Library::AttackData* CreatureLib::Library::AttackLibrary::GetAttack(const std::string& name) const {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
return this->_attacks.at(key);
}
const CreatureLib::Library::AttackData* CreatureLib::Library::AttackLibrary::operator[](const std::string& name) const {
return GetAttack(name);
}
void CreatureLib::Library::AttackLibrary::LoadAttack(const std::string& name,
const CreatureLib::Library::AttackData* attack) {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
this->_attacks.insert({key, attack});
}
void CreatureLib::Library::AttackLibrary::DeleteAttack(const std::string& name) {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
this->_attacks.erase(key);
}

View File

@ -4,31 +4,11 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "Attacks/AttackData.hpp" #include "Attacks/AttackData.hpp"
#include "BaseLibrary.hpp"
namespace CreatureLib::Library { namespace CreatureLib::Library {
class AttackLibrary { class AttackLibrary : public BaseLibrary<AttackData> {
private:
std::unordered_map<std::string, const AttackData*> _attacks;
public: public:
AttackLibrary(size_t initialCapacity = 32) AttackLibrary(size_t initialCapacity = 32) : BaseLibrary(initialCapacity){};
: _attacks(std::unordered_map<std::string, const AttackData*>(initialCapacity)){};
virtual ~AttackLibrary() {
for (auto attack : _attacks) {
delete attack.second;
}
_attacks.clear();
}
[[nodiscard]] bool TryGetAttack(const std::string& name, const AttackData*& move) const;
[[nodiscard]] const AttackData* GetAttack(const std::string& name) const;
[[nodiscard]] const AttackData* operator[](const std::string& name) const;
void LoadAttack(const std::string& name, const AttackData* attack);
void DeleteAttack(const std::string& name);
const std::unordered_map<std::string, const AttackData*>& GetIterator() { return _attacks; }
}; };
} }

View File

@ -0,0 +1 @@
#include "BaseLibrary.hpp"

View File

@ -0,0 +1,50 @@
#ifndef CREATURELIB_BASELIBRARY_HPP
#define CREATURELIB_BASELIBRARY_HPP
#include <algorithm>
#include <string>
#include <unordered_map>
namespace CreatureLib::Library {
template <class T> class BaseLibrary {
inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; }
inline static uint32_t constexpr Hash(char const* input) {
return charToLower(*input) ? static_cast<uint32_t>(charToLower(*input)) + 33 * Hash(input + 1) : 5381;
}
std::unordered_map<uint32_t, const T*> _values;
public:
BaseLibrary(size_t initialCapacity = 32) : _values(initialCapacity) {}
virtual ~BaseLibrary() {
for (const auto& v : _values) {
delete v.second;
}
_values.clear();
}
inline void Insert(const char* key, const T* value) { _values.insert({Hash(key), value}); }
inline void Delete(const char* key) { _values.erase(Hash(key)); }
bool TryGet(const char* name, const T*& out) const {
auto find = this->_values.find(Hash(name));
if (find == this->_values.end()) {
out = nullptr;
return false;
}
out = find->second;
return true;
}
inline const T* Get(const char* name) const { return _values.at(Hash(name)); }
inline const T* operator[](const char* name) const { return Get(name); }
inline const std::unordered_map<uint32_t, const T*>& GetIterator() const { return _values; }
size_t GetCount() const { return _values.count(); }
};
}
#endif // CREATURELIB_BASELIBRARY_HPP

View File

@ -1,36 +1 @@
#include "ItemLibrary.hpp" #include "ItemLibrary.hpp"
bool CreatureLib::Library::ItemLibrary::TryGetItem(const std::string& name,
const CreatureLib::Library::Item*& item) const {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
auto find = this->_items.find(key);
if (find == this->_items.end()) {
item = nullptr;
return false;
}
item = find->second;
return true;
}
const CreatureLib::Library::Item* CreatureLib::Library::ItemLibrary::GetItem(const std::string& name) const {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
return this->_items.at(key);
}
const CreatureLib::Library::Item* CreatureLib::Library::ItemLibrary::operator[](const std::string& name) const {
return this->GetItem(name);
}
void CreatureLib::Library::ItemLibrary::LoadItem(const std::string& name, const CreatureLib::Library::Item* item) {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
this->_items.insert({key, item});
}
void CreatureLib::Library::ItemLibrary::DeleteItem(const std::string& name) {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
this->_items.erase(key);
}

View File

@ -3,26 +3,13 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "BaseLibrary.hpp"
#include "Items/Item.hpp" #include "Items/Item.hpp"
namespace CreatureLib::Library { namespace CreatureLib::Library {
class ItemLibrary { class ItemLibrary : public BaseLibrary<Item> {
private:
std::unordered_map<std::string, const Item*> _items;
public: public:
ItemLibrary(size_t initialCapacity = 32) ItemLibrary(size_t initialCapacity = 32) : BaseLibrary(initialCapacity){};
: _items(std::unordered_map<std::string, const Item*>(initialCapacity)){};
virtual ~ItemLibrary() { _items.clear(); }
[[nodiscard]] bool TryGetItem(const std::string& name, const Item*& item) const;
[[nodiscard]] const Item* GetItem(const std::string& name) const;
[[nodiscard]] const Item* operator[](const std::string& name) const;
void LoadItem(const std::string& name, const Item* item);
void DeleteItem(const std::string& name);
const std::unordered_map<std::string, const Item*>& GetIterator() { return _items; }
}; };
} }

View File

@ -1,39 +1 @@
#include "SpeciesLibrary.hpp" #include "SpeciesLibrary.hpp"
bool CreatureLib::Library::SpeciesLibrary::TryGetSpecies(
const std::string& name, const CreatureLib::Library::CreatureSpecies*& outSpecies) const {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
auto find = _species.find(key);
if (find == _species.end()) {
outSpecies = nullptr;
return false;
}
outSpecies = find->second;
return true;
}
const CreatureLib::Library::CreatureSpecies*
CreatureLib::Library::SpeciesLibrary::GetSpecies(const std::string& name) const {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
return _species.at(key);
}
const CreatureLib::Library::CreatureSpecies*
CreatureLib::Library::SpeciesLibrary::operator[](const std::string& name) const {
return GetSpecies(name);
}
void CreatureLib::Library::SpeciesLibrary::LoadSpecies(const std::string& name,
const CreatureLib::Library::CreatureSpecies* species) {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
_species.insert({key, species});
}
void CreatureLib::Library::SpeciesLibrary::DeleteSpecies(const std::string& name) {
std::string key = name;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
_species.erase(key);
}

View File

@ -3,33 +3,14 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "BaseLibrary.hpp"
#include "CreatureData/CreatureSpecies.hpp" #include "CreatureData/CreatureSpecies.hpp"
namespace CreatureLib::Library { namespace CreatureLib::Library {
class SpeciesLibrary { class SpeciesLibrary : public BaseLibrary<CreatureSpecies> {
private: private:
std::unordered_map<std::string, const CreatureSpecies*> _species;
public: public:
SpeciesLibrary(size_t initialCapacity = 32) SpeciesLibrary(size_t initialCapacity = 32) : BaseLibrary(initialCapacity){};
: _species(std::unordered_map<std::string, const CreatureSpecies*>(initialCapacity)){};
virtual ~SpeciesLibrary() {
for (auto s : _species)
delete s.second;
_species.clear();
}
[[nodiscard]] bool TryGetSpecies(const std::string& name, const CreatureSpecies*& outSpecies) const;
[[nodiscard]] const CreatureSpecies* GetSpecies(const std::string& name) const;
[[nodiscard]] const CreatureSpecies* operator[](const std::string& name) const;
void LoadSpecies(const std::string& name, const CreatureSpecies* species);
void DeleteSpecies(const std::string& name);
size_t GetCount() const { return _species.size(); }
const std::unordered_map<std::string, const CreatureSpecies*>& GetIterator() { return _species; }
}; };
} }

View File

@ -28,8 +28,8 @@ TEST_CASE("Turn ordering: Attack before pass", "[Battling]") {
TEST_CASE("Turn ordering: High priority goes before no priority", "[Battling]") { TEST_CASE("Turn ordering: High priority goes before no priority", "[Battling]") {
auto l = TestLibrary::Get()->GetAttackLibrary(); auto l = TestLibrary::Get()->GetAttackLibrary();
auto a1 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); auto a1 = new LearnedAttack(l->Get("standard"), AttackLearnMethod::Unknown);
auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->Get("highPriority"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0));
auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
@ -50,8 +50,8 @@ TEST_CASE("Turn ordering: High priority goes before no priority", "[Battling]")
TEST_CASE("Turn ordering: Higher priority goes before high priority", "[Battling]") { TEST_CASE("Turn ordering: Higher priority goes before high priority", "[Battling]") {
auto l = TestLibrary::Get()->GetAttackLibrary(); auto l = TestLibrary::Get()->GetAttackLibrary();
auto a1 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); auto a1 = new LearnedAttack(l->Get("highPriority"), AttackLearnMethod::Unknown);
auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->Get("higherPriority"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0));
auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
@ -72,8 +72,8 @@ TEST_CASE("Turn ordering: Higher priority goes before high priority", "[Battling
TEST_CASE("Turn ordering: High priority goes before low priority", "[Battling]") { TEST_CASE("Turn ordering: High priority goes before low priority", "[Battling]") {
auto l = TestLibrary::Get()->GetAttackLibrary(); auto l = TestLibrary::Get()->GetAttackLibrary();
auto a1 = new LearnedAttack(l->GetAttack("lowPriority"), AttackLearnMethod::Unknown); auto a1 = new LearnedAttack(l->Get("lowPriority"), AttackLearnMethod::Unknown);
auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->Get("higherPriority"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0));
auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
@ -94,8 +94,8 @@ TEST_CASE("Turn ordering: High priority goes before low priority", "[Battling]")
TEST_CASE("Turn ordering: No priority goes before low priority", "[Battling]") { TEST_CASE("Turn ordering: No priority goes before low priority", "[Battling]") {
auto l = TestLibrary::Get()->GetAttackLibrary(); auto l = TestLibrary::Get()->GetAttackLibrary();
auto a1 = new LearnedAttack(l->GetAttack("lowPriority"), AttackLearnMethod::Unknown); auto a1 = new LearnedAttack(l->Get("lowPriority"), AttackLearnMethod::Unknown);
auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->Get("standard"), AttackLearnMethod::Unknown);
auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0));
auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2}; auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};

View File

@ -22,25 +22,25 @@ BattleLibrary* TestLibrary::Get() {
SpeciesLibrary* TestLibrary::BuildSpeciesLibrary() { SpeciesLibrary* TestLibrary::BuildSpeciesLibrary() {
auto l = new SpeciesLibrary(); auto l = new SpeciesLibrary();
l->LoadSpecies("testSpecies1", l->Insert("testSpecies1",
new CreatureSpecies( new CreatureSpecies(0, "testSpecies1",
0, "testSpecies1", new SpeciesVariant("default", 1, 1, 10, {0, 1},
new SpeciesVariant("default", 1, 1, 10, {0, 1}, StatisticSet<uint16_t>(10, 10, 10, 10, 10, 10), StatisticSet<uint16_t>(10, 10, 10, 10, 10, 10), {"testTalent"},
{"testTalent"}, {"testSecretTalent"}, new LearnableAttacks(100)), {"testSecretTalent"}, new LearnableAttacks(100)),
0.5f, "testGrowthRate", 5)); 0.5f, "testGrowthRate", 5));
return l; return l;
} }
AttackLibrary* TestLibrary::BuildAttackLibrary() { AttackLibrary* TestLibrary::BuildAttackLibrary() {
auto l = new AttackLibrary(); auto l = new AttackLibrary();
l->LoadAttack("standard", new AttackData("standard", 0, AttackCategory::Physical, 20, 100, 30, l->Insert("standard", new AttackData("standard", 0, AttackCategory::Physical, 20, 100, 30,
AttackTarget::AdjacentOpponent, 0, {})); AttackTarget::AdjacentOpponent, 0, {}));
l->LoadAttack("highPriority", new AttackData("highPriority", 0, AttackCategory::Physical, 20, 100, 30, l->Insert("highPriority", new AttackData("highPriority", 0, AttackCategory::Physical, 20, 100, 30,
AttackTarget::AdjacentOpponent, 1, {})); AttackTarget::AdjacentOpponent, 1, {}));
l->LoadAttack("higherPriority", new AttackData("higherPriority", 0, AttackCategory::Physical, 20, 100, 30, l->Insert("higherPriority", new AttackData("higherPriority", 0, AttackCategory::Physical, 20, 100, 30,
AttackTarget::AdjacentOpponent, 2, {})); AttackTarget::AdjacentOpponent, 2, {}));
l->LoadAttack("lowPriority", new AttackData("lowPriority", 0, AttackCategory::Physical, 20, 100, 30, l->Insert("lowPriority", new AttackData("lowPriority", 0, AttackCategory::Physical, 20, 100, 30,
AttackTarget::AdjacentOpponent, -1, {})); AttackTarget::AdjacentOpponent, -1, {}));
return l; return l;
} }