Skip to content

Commit

Permalink
Make logic resolving 4x faster and allow CI codes for stages
Browse files Browse the repository at this point in the history
Not all code comparisons were case-insensitive (CI).
Also adds tests, primarily for CI.
Introduces an object cache that could change behaviour in some packs but shouldn't.
Replaces list<> by vector<> for code.

Testing if vector<> for _ciAllCodes would be better was not done yet (TODO).
  • Loading branch information
black-sliver committed Sep 7, 2024
1 parent 8f51c4b commit 879275d
Show file tree
Hide file tree
Showing 10 changed files with 409 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dist/
*~
.DS_Store
thumbs.db
gmon.out

# exclude unused and scratch pad files
.trash
Expand Down
9 changes: 5 additions & 4 deletions src/core/baseitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class BaseItem { // TODO: move stuff over to JsonItem; TODO: make some stuff pur
std::string _id;
std::string _name;
Type _type = Type::NONE;
std::list<std::string> _codes;
std::vector<std::string> _codes;
bool _capturable = false;
bool _loop = false;
bool _allowDisabled = false;
Expand Down Expand Up @@ -122,9 +122,10 @@ class BaseItem { // TODO: move stuff over to JsonItem; TODO: make some stuff pur
}


virtual int providesCode(const std::string code) const { // FIXME: make this pure?
if (_count && canProvideCode(code)) return _count;
return (_stage1 && canProvideCode(code));
virtual int providesCode(const std::string& code) const { // FIXME: make this pure?
if (_count && canProvideCode(code))
return _count;
return _stage1 && canProvideCode(code);
}

virtual bool canProvideCode(const std::string& code) const { // FIXME: make this pure?
Expand Down
12 changes: 10 additions & 2 deletions src/core/jsonitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ std::string JsonItem::getCodesString() const {
return s;
}

const std::list<std::string>& JsonItem::getCodes(int stage) const {
const std::vector<std::string>& JsonItem::getCodes(int stage) const {
if (_type == Type::TOGGLE) return _codes;
if (stage>=0 && (size_t)stage<_stages.size()) return _stages[stage].getCodes();
return _codes;
Expand Down Expand Up @@ -117,7 +117,15 @@ JsonItem JsonItem::FromJSON(json& j)
item._stage2 = std::max(0,std::min(to_int(j["initial_stage_idx"],0), (int)item._stages.size()-1));
item._count = std::max(item._minCount, std::min(to_int(j["initial_quantity"],0), item._maxCount));
if (item._type == Type::CONSUMABLE && item._count > 0) item._stage1=1;


#ifdef JSONITEM_CI_QUIRK
for (const auto& code : item._codes)
item._ciAllCodes.emplace(toLower(code));
for (const auto& stage : item._stages)
for (const auto& code : stage.getCodes())
item._ciAllCodes.emplace(toLower(code));
#endif

return item;
}

Expand Down
96 changes: 79 additions & 17 deletions src/core/jsonitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <luaglue/luainterface.h>
#include <algorithm>
#include <nlohmann/json.hpp>
#include <algorithm>
#include <unordered_set>
#ifdef _MSC_VER
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
Expand All @@ -24,7 +26,7 @@ class JsonItem final : public LuaInterface<JsonItem>, public BaseItem {

class Stage final {
protected:
std::list<std::string> _codes;
std::vector<std::string> _codes;
std::list<std::string> _secondaryCodes;
std::string _img;
std::string _disabledImg;
Expand All @@ -42,19 +44,26 @@ class JsonItem final : public LuaInterface<JsonItem>, public BaseItem {
const std::string& getDisabledImage() const { return _disabledImg; }
const std::list<std::string>& getImageMods() const { return _imgMods; }
const std::list<std::string>& getDisabledImageMods() const { return _disabledImgMods; }
const std::list<std::string>& getCodes() const { return _codes; }
const std::vector<std::string>& getCodes() const { return _codes; }
const std::list<std::string>& getSecondaryCodes() const { return _secondaryCodes; }
std::string getCodesString() const;
bool hasCode(const std::string& code) const { // NOTE: this is called canProvideCode in lua
#ifdef JSONITEM_CI_QUIRK
const auto cmp = [&code](const std::string& s) {
return code.length() == s.length() && strcasecmp(code.c_str(), s.c_str()) == 0;
};
return std::find_if(_codes.begin(), _codes.end(), cmp) != _codes.end();
#else
return std::find(_codes.begin(), _codes.end(), code) != _codes.end();
#endif
}
bool hasSecondaryCode(const std::string& code) const {
return std::find(_secondaryCodes.begin(), _secondaryCodes.end(), code) != _secondaryCodes.end();
}
const bool getInheritCodes() const { return _inheritCodes; }
const std::string& getName() const { return _name; }
};

protected:
std::vector<Stage> _stages;
bool _imgOverridden = false;
Expand All @@ -69,7 +78,23 @@ class JsonItem final : public LuaInterface<JsonItem>, public BaseItem {
bool _imgChanged = false;
bool _ignoreUserInput = false;

public:
#ifdef JSONITEM_CI_QUIRK
// CI comparison in list is way too expensive, so we create a lowercase set instead
std::unordered_set<std::string> _ciAllCodes; // includes codes for stages
#endif

public:
static void toLowerInPlace(std::string& s)
{
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
}

static std::string toLower(std::string s)
{
toLowerInPlace(s);
return s;
}

virtual size_t getStageCount() const override { return _stages.size(); }

virtual const std::string& getImage(size_t stage) const override {
Expand Down Expand Up @@ -100,9 +125,16 @@ class JsonItem final : public LuaInterface<JsonItem>, public BaseItem {
return _name;
}

#ifdef JSONITEM_CI_QUIRK
bool canProvideCodeLower(const std::string& code) const
{
return _ciAllCodes.count(code);
}
#endif

virtual bool canProvideCode(const std::string& code) const override {
#ifdef JSONITEM_CI_QUIRK
auto cmp = [&code](const std::string& s) {
const auto cmp = [&code](const std::string& s) {
return code.length() == s.length() && strcasecmp(code.c_str(), s.c_str()) == 0;
};
if (std::find_if(_codes.begin(), _codes.end(), cmp) != _codes.end()) return true;
Expand All @@ -115,28 +147,58 @@ class JsonItem final : public LuaInterface<JsonItem>, public BaseItem {
return false;
}

virtual int providesCode(const std::string code) const override {
// TODO: split at ':' for consumables to be able to check for a specific amount?
private:
int providesCodeImpl(const std::string& code, bool assumeCanProvide) const
{
if (_type == Type::COMPOSITE_TOGGLE) {
// composites do not provide left/right codes since that would duplicate numbers
#ifdef JSONITEM_CI_QUIRK
const auto cmp = [&code](const std::string& s) {
return code.length() == s.length() && strcasecmp(code.c_str(), s.c_str()) == 0;
};
if (std::find_if(_codes.begin(), _codes.end(), cmp) != _codes.end())
#else
if (std::find(_codes.begin(), _codes.end(), code) != _codes.end())
#endif
return ((_stage2&1) ? 1 : 0) + ((_stage2&2) ? 1 : 0);
else
return 0;
return 0;
}
if ((int)_stages.size()>_stage2) {
if (_allowDisabled && !_stage1) return 0;

if ((int)_stages.size() > _stage2) {
if (_allowDisabled && !_stage1)
return 0;
for (int i=_stage2; i>=0; i--) {
if (_stages[i].hasCode(code)) return 1;
if (!_stages[i].getInheritCodes()) break;
if (_stages[i].hasCode(code))
return 1;
if (!_stages[i].getInheritCodes())
break;
}
return false;
}
if (_count && canProvideCode(code)) return _count;
return (_stage1 && canProvideCode(code));

if (_count && (assumeCanProvide || canProvideCode(code)))
return _count;
return _stage1 && (assumeCanProvide || canProvideCode(code));
}

public:
#ifdef JSONITEM_CI_QUIRK
int providesCodeLower(const std::string& code) const
{
if (!canProvideCodeLower(code))
return 0;
return providesCodeImpl(code, true);
}
#endif

int providesCode(const std::string& code) const override
{
// TODO: split at ':' for consumables to be able to check for a specific amount?
return providesCodeImpl(code, false);
}
virtual std::string getCodesString() const override;
virtual const std::list<std::string>& getCodes(int stage) const;

std::string getCodesString() const override;
const std::vector<std::string>& getCodes(int stage) const;

virtual bool changeState(BaseItem::Action action) override {
if (_ignoreUserInput)
Expand Down
15 changes: 9 additions & 6 deletions src/core/jsonutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ static nlohmann::json parse_jsonc(std::string& s)
return j;
}

static void commasplit(const std::string& s, std::list<std::string>& l)
template <template <class> class T>
static void commasplit(const std::string& s, T<std::string>& l)
{
auto sta = s.find_first_not_of(' '); // ltrim
auto end = s.find(',');
Expand All @@ -55,17 +56,19 @@ static void commasplit(const std::string& s, std::list<std::string>& l)
l.push_back(s.substr(sta, end - sta));
}

static std::list<std::string> commasplit(const std::string& s)
template <template <class> class T = std::list>
static T<std::string> commasplit(const std::string& s)
{
std::list<std::string> lst;
commasplit(s, lst);
T<std::string> lst;
commasplit<T>(s, lst);
return lst;
}

static std::list<std::string> commasplit(std::string&& s)
template <template <class> class T = std::list>
static T<std::string> commasplit(std::string&& s)
{
std::string tmp = s;
return commasplit(tmp);
return commasplit<T>(tmp);
}


Expand Down
2 changes: 1 addition & 1 deletion src/core/luaitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ bool LuaItem::canProvideCode(const std::string& code) const
return res;
}

int LuaItem::providesCode(const std::string code) const
int LuaItem::providesCode(const std::string& code) const
{
if (!_providesCodeFunc.valid()) return false;
lua_rawgeti(_L, LUA_REGISTRYINDEX, _providesCodeFunc.ref);
Expand Down
2 changes: 1 addition & 1 deletion src/core/luaitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class LuaItem final : public LuaInterface<LuaItem>, public BaseItem {
LuaVariant Get(const char* key);

virtual bool canProvideCode(const std::string& code) const override;
virtual int providesCode(const std::string code) const override;
int providesCode(const std::string& code) const override;
virtual bool changeState(Action action) override;

virtual void SetOverlay(const char* text) override {
Expand Down
Loading

0 comments on commit 879275d

Please sign in to comment.