Skip to content

Commit

Permalink
Allow dynamic array indexing in a data address.
Browse files Browse the repository at this point in the history
  • Loading branch information
exjam committed Dec 4, 2023
1 parent 666690c commit f2b34d9
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 32 deletions.
8 changes: 5 additions & 3 deletions Include/RmlUi/Core/DataTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,16 @@ template <typename Object, typename AssignType>
using MemberSetterFunc = void (Object::*)(AssignType);

using DirtyVariables = SmallUnorderedSet<String>;
using DataAddress = Vector<struct DataAddressEntry>;

struct DataAddressEntry {
DataAddressEntry(String name) : name(std::move(name)), index(-1) {}
DataAddressEntry(int index) : index(index) {}
DataAddressEntry(String name_) : name(std::move(name_)), index(-1) {}
DataAddressEntry(DataAddress address_) : address(std::move(address_)), index(-1) {}
DataAddressEntry(int index_) : index(index_) {}
String name;
int index;
DataAddress address;
};
using DataAddress = Vector<DataAddressEntry>;

template <class T>
struct PointerTraits {
Expand Down
17 changes: 10 additions & 7 deletions Include/RmlUi/Core/DataVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

namespace Rml {

class DataModel;

enum class DataVariableType { Scalar, Array, Struct };

/*
Expand All @@ -56,7 +58,7 @@ class RMLUICORE_API DataVariable {
bool Get(Variant& variant);
bool Set(const Variant& variant);
int Size();
DataVariable Child(const DataAddressEntry& address);
DataVariable Child(const DataModel& model, const DataAddressEntry& address);
DataVariableType Type();

private:
Expand All @@ -79,11 +81,13 @@ class RMLUICORE_API VariableDefinition : public NonCopyMoveable {
virtual bool Set(void* ptr, const Variant& variant);

virtual int Size(void* ptr);
virtual DataVariable Child(void* ptr, const DataAddressEntry& address);
virtual DataVariable Child(const DataModel& model, void* ptr, const DataAddressEntry& address);

protected:
VariableDefinition(DataVariableType type) : type(type) {}

static int ResolveArrayIndex(const DataModel& model, const DataAddressEntry &address);

private:
DataVariableType type;
};
Expand Down Expand Up @@ -145,7 +149,7 @@ class RMLUICORE_API StructDefinition final : public VariableDefinition {
public:
StructDefinition();

DataVariable Child(void* ptr, const DataAddressEntry& address) override;
DataVariable Child(const DataModel& model, void* ptr, const DataAddressEntry& address) override;

void AddMember(const String& name, UniquePtr<VariableDefinition> member);

Expand All @@ -163,11 +167,10 @@ class ArrayDefinition final : public VariableDefinition {
int Size(void* ptr) override { return int(static_cast<Container*>(ptr)->size()); }

protected:
DataVariable Child(void* void_ptr, const DataAddressEntry& address) override
DataVariable Child(const DataModel& model, void* void_ptr, const DataAddressEntry& address) override
{
Container* ptr = static_cast<Container*>(void_ptr);
const int index = address.index;

const int index = VariableDefinition::ResolveArrayIndex(model, address);
const int container_size = int(ptr->size());
if (index < 0 || index >= container_size)
{
Expand Down Expand Up @@ -196,7 +199,7 @@ class RMLUICORE_API BasePointerDefinition : public VariableDefinition {
bool Get(void* ptr, Variant& variant) override;
bool Set(void* ptr, const Variant& variant) override;
int Size(void* ptr) override;
DataVariable Child(void* ptr, const DataAddressEntry& address) override;
DataVariable Child(const DataModel& model, void* ptr, const DataAddressEntry& address) override;

protected:
virtual void* DereferencePointer(void* ptr) = 0;
Expand Down
17 changes: 15 additions & 2 deletions Source/Core/DataExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1021,15 +1021,28 @@ bool DataExpression::Run(const DataExpressionInterface& expression_interface, Va
return true;
}

static void CollectAddresses(StringList& list, const DataAddress& address)
{
if (!address.empty())
list.push_back(address[0].name);

for (const DataAddressEntry& entry : address)
{
if (!entry.address.empty())
CollectAddresses(list, entry.address);
}
}

StringList DataExpression::GetVariableNameList() const
{
StringList list;
list.reserve(addresses.size());

for (const DataAddress& address : addresses)
{
if (!address.empty())
list.push_back(address[0].name);
CollectAddresses(list, address);
}

return list;
}

Expand Down
29 changes: 20 additions & 9 deletions Source/Core/DataModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace Rml {
static DataAddress ParseAddress(const String& address_str)
{
StringList list;
StringUtilities::ExpandString(list, address_str, '.');
StringUtilities::ExpandString(list, address_str, '.', '[', ']');

DataAddress address;
address.reserve(list.size() * 2);
Expand All @@ -55,15 +55,26 @@ static DataAddress ParseAddress(const String& address_str)

while (i_open != String::npos)
{
size_t i_close = item.find(']', i_open + 1);
if (i_close == String::npos)
return DataAddress();
int depth = 1;
size_t i_close = i_open;
while (depth > 0)
{
i_close = item.find_first_of("[]", i_close + 1);
if (i_close == String::npos)
return DataAddress();

int index = FromString<int>(item.substr(i_open + 1, i_close - i_open), -1);
if (index < 0)
return DataAddress();
if (item[i_close] == '[')
depth++;
else if (item[i_close] == ']')
depth--;
}

address.emplace_back(index);
std::string accessor = item.substr(i_open + 1, i_close - (i_open + 1));
int index = FromString<int>(accessor, -1);
if (index >= 0)
address.emplace_back(index);
else
address.emplace_back(ParseAddress(accessor));

i_open = item.find('[', i_close + 1);
}
Expand Down Expand Up @@ -308,7 +319,7 @@ DataVariable DataModel::GetVariable(const DataAddress& address) const

for (int i = 1; i < (int)address.size() && variable; i++)
{
variable = variable.Child(address[i]);
variable = variable.Child(*this, address[i]);
if (!variable)
return DataVariable();
}
Expand Down
34 changes: 28 additions & 6 deletions Source/Core/DataVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*/

#include "../../Include/RmlUi/Core/DataVariable.h"
#include "DataModel.h"

namespace Rml {

Expand All @@ -45,9 +46,9 @@ int DataVariable::Size()
return definition->Size(ptr);
}

DataVariable DataVariable::Child(const DataAddressEntry& address)
DataVariable DataVariable::Child(const DataModel& model, const DataAddressEntry& address)
{
return definition->Child(ptr, address);
return definition->Child(model, ptr, address);
}

DataVariableType DataVariable::Type()
Expand All @@ -70,12 +71,33 @@ int VariableDefinition::Size(void* /*ptr*/)
Log::Message(Log::LT_WARNING, "Tried to get the size from a non-array data type.");
return 0;
}
DataVariable VariableDefinition::Child(void* /*ptr*/, const DataAddressEntry& /*address*/)
DataVariable VariableDefinition::Child(const DataModel& /*model*/ , void* /*ptr*/, const DataAddressEntry& /*address*/)
{
Log::Message(Log::LT_WARNING, "Tried to get the child of a scalar type.");
return DataVariable();
}

int VariableDefinition::ResolveArrayIndex(const DataModel& model, const DataAddressEntry &address)
{
if (address.index >= 0)
return address.index;

if (!address.address.empty())
{
Rml::DataVariable variable_index = model.GetVariable(address.address);
if (variable_index)
{
Rml::Variant value;
if (variable_index.Get(value))
{
return value.Get<int>(-1);
}
}
}

return -1;
}

class LiteralIntDefinition final : public VariableDefinition {
public:
LiteralIntDefinition() : VariableDefinition(DataVariableType::Scalar) {}
Expand All @@ -95,7 +117,7 @@ DataVariable MakeLiteralIntVariable(int value)

StructDefinition::StructDefinition() : VariableDefinition(DataVariableType::Struct) {}

DataVariable StructDefinition::Child(void* ptr, const DataAddressEntry& address)
DataVariable StructDefinition::Child(const DataModel& /*model*/, void *ptr, const DataAddressEntry &address)
{
const String& name = address.name;
if (name.empty())
Expand Down Expand Up @@ -169,11 +191,11 @@ int BasePointerDefinition::Size(void* ptr)
return underlying_definition->Size(DereferencePointer(ptr));
}

DataVariable BasePointerDefinition::Child(void* ptr, const DataAddressEntry& address)
DataVariable BasePointerDefinition::Child(const DataModel& model, void* ptr, const DataAddressEntry& address)
{
if (!ptr)
return DataVariable();
return underlying_definition->Child(DereferencePointer(ptr), address);
return underlying_definition->Child(model, DereferencePointer(ptr), address);
}

} // namespace Rml
10 changes: 5 additions & 5 deletions Source/Lua/LuaDataModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class LuaTableDef : public VariableDefinition {
bool Get(void* ptr, Variant& variant) override;
bool Set(void* ptr, const Variant& variant) override;
int Size(void* ptr) override;
DataVariable Child(void* ptr, const DataAddressEntry& address) override;
DataVariable Child(const DataModel& model, void* ptr, const DataAddressEntry& address) override;

protected:
const struct LuaDataModel* model;
Expand All @@ -142,7 +142,7 @@ class LuaTableDef : public VariableDefinition {
class LuaScalarDef final : public LuaTableDef {
public:
LuaScalarDef(const struct LuaDataModel* model);
DataVariable Child(void* ptr, const DataAddressEntry& address) override;
DataVariable Child(const DataModel& model, void* ptr, const DataAddressEntry& address) override;
};

LuaTableDef::LuaTableDef(const struct LuaDataModel* model) : VariableDefinition(DataVariableType::Scalar), model(model) {}
Expand Down Expand Up @@ -206,7 +206,7 @@ int LuaTableDef::Size(void* ptr)
return size;
}

DataVariable LuaTableDef::Child(void* ptr, const DataAddressEntry& address)
DataVariable LuaTableDef::Child(const DataModel& /*model*/, void* ptr, const DataAddressEntry& address)
{
lua_State* L = model->dataL;
if (!L)
Expand Down Expand Up @@ -240,13 +240,13 @@ DataVariable LuaTableDef::Child(void* ptr, const DataAddressEntry& address)

LuaScalarDef::LuaScalarDef(const struct LuaDataModel* model) : LuaTableDef(model) {}

DataVariable LuaScalarDef::Child(void* ptr, const DataAddressEntry& address)
DataVariable LuaScalarDef::Child(const DataModel& model, void* ptr, const DataAddressEntry& address)
{
lua_State* L = model->dataL;
if (!L)
return DataVariable{};
lua_settop(L, model->top);
return LuaTableDef::Child(ptr, address);
return LuaTableDef::Child(model, ptr, address);
}

static void BindVariable(struct LuaDataModel* D, lua_State* L)
Expand Down

0 comments on commit f2b34d9

Please sign in to comment.