How to automatically initialize component parameters? - c++

While doing a game engine that uses .lua files in order to read parameter values, I got stuck when I had to read these values and assign them to the parameters of each component in C++. I tried to investigate the way Unity does it, but I didn't find it (and I'm starting to doubt that Unity has to do it at all).
I want the parameters to be initialized automatically, without the user having to do the process of
myComponentParameter = readFromLuaFile("myParameterName")
for each one of the parameters.
My initial idea is to use the std::variant type, and storing an array of variants in order to read them automatically. My problems with this are:
First of all, I don't know how to know the type that std::variant is storing at the moment (tried with std::variant::type, but it didn't work for the template), in order to cast from the untyped .lua value to the C++ value. For reference, my component initialization looks like this:
bool init(luabridge::LuaRef parameterTable)
{
myIntParameter = readVariable<int>(parameterTable, "myIntParameter");
myStringParameter = readVariable<std::string>(parameterTable, "myStringParameter");
return true;
}
(readVariable function is already written in this question, in case you're curious)
The second problem is that the user would have to write std::get(myIntParameter); whenever they want to access to the value stored by the variant, and that sounds like something worse than making the user read the parameter value.
The third problem is that I can't create an array of std::variant<any type>, which is what I would like to do in order to automatically initialize the parameters.
Is there any good solution for this kind of situation where I want the init function to not be necessary, and the user doesn't need to manually set up the parameter values?
Thanks in advance.

Let's expand my comment. In a nutshell, you need to get from
"I have some things entered by the user in some file"
to:
"the client code can read the value without std::get"
…which roughly translates to:
"input validation was done, and values are ready for direct use."
…which implies you do not store your variables in variants.
In the end it is a design question. One module somewhere must have the knowledge of which variable names exist, and the type of each, and the valid values.
The input of that module will be unverified values.
The output of the module will probably be some regular c++ struct.
And the body of that module will likely have a bunch of those:
config.foo = readVariable<int>("foo");
config.bar = readVariable<std::string>("bar");
// you also want to validate values there - all ints may not be valid values for foo,
// maybe bar must follow some specific rules, etc
assuming somewhere else it was defined as:
struct Configuration {
int fooVariable;
std::string bar;
};
Where that module lives depends on your application. If all expected types are known, there is no reason to ever use a variant, just parse right away.
You would read to variants if some things do not make sense until later. For instance if you want to read configuration values that will be used by plugins, so you cannot make sense of them yet.
(actually even then simply re-parsing the file later, or just saving values as text for later parsing would work)

Related

Lua: how to verify that a table contains a specific function

I'm developing a module that returns a table full of functions based on the arguments that are passed in. Specifically, the module returns a set of data transformation rules (functions) that need to be applied to a data set depending on which customer is sending it.
I decided to decouple my rule library (biz logic) from the code that decides which of the rules should be applied (config logic).
Here's the unit test I'm writing to verify that the ruleBuilder is adding the correct rule (function) based on one of my scenarios:
ruleBuilder = require("ruleBuilder")
ruleLibrary = require("ruleLibrary")
local rules = ruleBuilder.assembleRules("Customer1231")
assert(rules[1] == ruleLibrary.missingSSNRule)
Is this the correct way to do that verification? Will this work even if the ruleLibrary.missingSSNRule function has references to several other functions via a closure or parameter?
To verify that a table contains a particular function you may use the fact that keys in Lua tables can be anything (including functions). In your assembleRules code you can write something like this:
function assembleRules(...)
...
return {
[someOtherCoolModule.coolFunction] = someOtherCoolModule.coolFunction,
[yetAnotherModule.anotherFunction] = yetAnotherModule.anotherFunction,
}
end
Then later you can simply check if the key exists:
local rules = ruleBuilder.assembleRules("somedata")
assert(rules[someOtherCoolModule.coolFunction])
On the assumption that the return value of ruleBuilder.assembleRules is supposed to somehow know to put someOtherCoolModule.coolFunction in the 0-th index (note: Lua uses 1-based indices. Don't use 0 as an index) of its return value, then yes.
Will this work even if someOtherCoolModule.coolFunction is a closure?
All functions in Lua are closures. However, I'm going to assume that you mean that ruleBuilder.assembleRules is going to take someOtherCoolModule.coolFunction and build a new function around it.
A function is equal to itself. But it is only equal to itself. Just like two tables are only equal if they are the same table object, two functions are only equal if they are the same function. Functions are not equal to a different instantiation of the same function, nor is it equal to any other function. Here are examples of this.

Convert std::string to existing function with parameters in C++

I've got an implemented function MyFunc(int, double, string) in my project. How can I call this function with necessary parameters having its string representation, for example
std::string str = "MyFunc(2, 3.12, \"Lemon Juice\")";
And what about the standard functions, for example, how can I call time() having std::string "time()"?
Ok, here's more detailed task.
I've got a map <string, Data>
Data is a class-wrapper with many childs. When I call Data.GetValue() method, it returns a std::string, depending of child class inner data. One of Data childs must return the string representation of int, another - the string representation of double, and the last one - the string representation of current date and time. Here's the problem - I don't know how to call the standard function ctime() for getting information from one of Data childs.
You cannot in general execute code in C++ whose source is contained in a string. Probably the most compelling motivation for this is so that a C++ implementation is not required to have a C++ compiler on the machine that the code runs on, although there is more to it than just that.
You may be able to do it for specific cases. That could be:
Platform-specific, for example:
Wrap the source up in some boilerplate, then either call the compiler externally, link against it, or embed it in your program. This gives you a program or library.
Run that new program externally, or dynamically link against that library.
Input-specific, for example:
You could parse a function call to a particular known function, with literals as arguments, relatively easily without needing a complete C++ compiler. Get the argument values out into variables and call the function. But if you're going to do that, you could specify a more easily parsable format for the string, than one that looks like a C++ function call.
It sounds as though in your task you have a string that is one of:
a representation of an int
a representation of a double
a representation of a date and time.
You don't say what you want to do with this string, but whatever that is you probably need to (a) examine the string to find out which of the three it is, and then (b) do something appropriate to that format. Better, you could give the derived class the responsibility of returning the same representation no matter which of the three GetValue() returns. For example, if what you really want is seconds since 1970, add a GetSecondsSinceEpoc function, and implement it differently in each class.
As mentioned by others, C++ in itself is not able to do that. However external frameworks can help you.
ROOT (used at CERN) provides reflection for C++ along with an interpreter. You will be able to execute/interpret a method call or a macro written in C++ from within your code.
You can not do that using C++.

C++: use of “().” and “()[].”

I am trying to understand the programming of Siemens scanner using C++ and given that my C++ skills are limited, I am having problems in understanding many parts of the code provided by the vendor.
Problem 1
For instance, the code uses reference (rMrProt) to object MrProt and notations (such as the use of use of (). and ()[].) are very confusing to me.
For instance:
ImageSamples = rMrProt.kSpace().baseResolution()
ImageSize = rMrProt.sliceSeries()[0].readoutFOV()
Some explanation of these statements would be appreciated.
All information regarding object MrProt are in “MrProt.h”, “MrProt.dll”, “MrProt.lib”. All these files have been shared at:
https://docs.google.com/open?id=0B0Ah9soYnrlIYWZkNDU2M2EtYTNmNC00YTc5LTllMzItYzIyMWU4M2ZhY2Fi
Problem 2
Also, I have been trying to read MrProt.dll and MrProt.lib without any success. Only now, I came to know of dumpbin. Any help would be appreciated.
Problem 3
Another confusion that I have is related to some part of MrProt.h itself. There is a statement in MrProt.h:
class __IMP_EXP MrProt: public MrProtocolData::MrProtDataDelegate
{
typedef MrProtocolData::MrProtDataDelegate BasicImplementation;
public:
MrProt();
MrProt(const MrProt& rSource);
…
….
}
Here, __IMP_EXP, I guess that it’s some compiler specific stuff.. some decoration etc. But, I still have no idea what to make of this.
Problem 1.
rMrProt.sliceSeries()[0].readoutFOV()
means
Take rMrProt's sliceSeries member and call that. Apparently, it returns an array-like object, something that can be indexed.
From the result, take the first element ([0]). That's some kind of object.
On that element/object, call readoutFOV.
Problem 2. You're not really supposed to read binary files. There should be documentation with them.
1)
ImageSamples = rMrProt.kSpace().baseResolution()
This is just method chaining. You call the method kSpace() on rMrPrto which returns an object, and you call baseResolution() on that object.
2) Those are binary files. What would you expect to see? To read them you'd have to be an expert in asm or at least know some low-level concepts.
3) __IMP_EXP is a common type of directive that tells the compiler that the class is either exported or imported.
It expands to _declspec(dllimport) or _declspec(dllexport), depending on whether the definition of the class is in the current module or another module.
identifier() is a method/function call
identifier[i] returns the i'th element in an array.
identifier()[i] returns the i'th element of the array returned by identifier()
I can only help on problem 1:
if the return value of rMrProt.kSpace() is a struct. instead of saving it to a struct and then access it's member you can directly access a member of his with rMrProt.kSpace().MemberName
same for rMrProt.sliceSeries() which I guess is returning an array. so rMrProt.sliceSeries()[0] will access the first value in the returning array.

C++ howto use the same function twice with different name and different names for variables

I have a function that commands a device. This device is available twice so I need the same functionality for two devices. Out of maintenance reasons I don't want to have to code the function twice (one for each device) because then I always need to apply changes twice.
The functions are the same in principle but are supposed to work on different variables. Is it possible to instantiate this function with kind of a "varying" name, similar to template but not with classes but names?
I try to provide an example. It should look something like this.
void function_x (int Var, double Vary, ...) {
int var3_x = getFunctionFromDatabase(var3_x);
double var2_x = getFunctionFromDatabase(var2_x);
// some operations
}
The functions are applied by two instances of a Device Handler class.
The variables var1_x, var2_x and var3_x are stored in a data pool as var1_1, var1_2, var2_1, ... the "same" variable but one for each device. One Controller commands the two devices via these variables and the data pool.
Is this possible somehow?
I hope that the problem got clear ;). This is my first question here :P.
Thanks in advance for any help.
Why not use an array? E.g.
var1[0], var1[1], etc.
Use an array element for each device that you manage.
You could do some trickery with macros, but I think the code will be more clear if you use arrays.
Even if the variables are in a library that you can't change, you could set up arrays of pointers to the original variables in an initialization function. E.g.:
var1[0] = &var1_0;
var1[1] = &var1_1;
Then, function_x becomes function and would accept a parameter for the device index.
You say they have different variables, in which case it would be a simple case of overloading the function. Your example implies that you want to get the function from a database in which case you would need to use function pointers. Another option is that you have 1 function and you pass a handle (or some such) to it (as well as your arguments) to identify which device it is.

Generating data structures by parsing plain text files

I wrote a file parser for a game I'm writing to make it easy for myself to change various aspects of the game (things like the character/stage/collision data). For example, I might have a character class like this:
class Character
{
public:
int x, y; // Character's location
Character* teammate;
}
I set up my parser to read in from a file the data structure with syntax similar to C++
Character Sidekick
{
X = 12
Y = 0
}
Character AwesomeDude
{
X = 10
Y = 50
Teammate = Sidekick
}
This will create two data structures and put them in a map<std::string, Character*>, where the key string is whatever name I gave it (in this case Sidekick and AwesomeDude). When my parser sees a pointer to a class, like the teammate pointer, it's smart enough to look up in the map to fetch the pointer to that data structure. The problem is that I can't declare Sidekick's teammate to be AwesomeDude because it hasn't been placed into the Character map yet.
I'm trying to find the best way to solve this so that I can have my data structures reference objects that haven't yet been added to the map. The two easiest solutions that I can think of are (a) add the ability to forward declare data structures or (b) have the parser read through the file twice, once to populate the map with pointers to empty data structures and a second time to go through and fill them in.
The problem with (a) is that I also can decide which constructor to call on a class, and if I forward declare something I'd have to have the constructor be apart from the rest of the data, which could be confusing. The problem with (b) is that I might want to declare Sidekick and AwesomeDude in their own files. I'd have to make my parser be able to take a list of files to read rather than just one at a time (this isn't so bad I guess, although sometimes I might want to get a list of files to read from a file). (b) also has the drawback of not being able to use data structures declared later in the constructor itself, but I don't think that's a huge deal.
Which way sounds like a better approach? Is there a third option I haven't thought of? It seems like there ought to be some clever solution to this with pointer references or binding or something... :-/ I suppose this is somewhat subjective based on what features I want to give myself, but any input is welcome.
When you encounter the reference the first time, simply store it as a reference. Then, you can put the character, or the reference, or whatever on a list of "references that need to be resolved later".
When the file is done, run through those that have references and resolve them.
Well, you asked for a third option. You don't have to use XML, but if you follow the following structure, it would be very simple to use a SAX parser to build your data structure.
At any rate, instead of referencing a teammate, each character references a team (Blue team in this case). This will decouple the circular reference issue. Just make sure you list the teams before the characters.
<team>Blue</team>
<character>
<name>Sidekick</name>
<X>12</X>
<Y>0</Y>
<teamref>Blue</teamref>
</character>
<character>
<name>Sidekick</name>
<X>10</X>
<Y>50</Y>
<teamref>Blue</teamref>
</character>
Personally, I'd go with b). Splitting your code into Parser and Validator classes, both operating on the same data structure. The Parser will read and parse a file, filling the data structure and storing any object references as their textual names, leaving the real pointer null in your structure for now.
When you are finished loading the files, use the Validator class to validate and resolve any references, filling in the "real" pointers. You will want to consider how to structure your data to make these lookups nice and fast.
Will said exactly what I was about to write. Just keep a list or something with the unsolved references.
And don't forget to throw an error if there are unsolved references once you finish reading the file =P
Instead of storing Character object in your map, store a proxy for Character. The proxy will than contain a pointer to the actual Character object when the object is loaded. The type of Character::teammate will be changed to this proxy type. When you read in a reference that is not already in your map, you create a proxy and use the proxy. When you load an character which you already have an empty proxy in the map, populate it with your newly loaded character. You may also want to add a counter to keep track of how many empty proxy you have in the map so you know when all referenced characters have been loaded.
Another layer of indirection....it always make programming easier and slower.
One option would be to reverse the obligation. The Map is responsible for filling in the reference
template<T> class SymbolMap // I never could rememeber C++ template syntax
{
...
/// fill in target with thing name
/// if no name yet, add it to the list of thing that will be name
void Set(T& target, std::string name);
/// define name as target
/// go back and fill in anything that needs to be name
void Define(T target, std::string name);
/// make sure everything is resolved
~SymbolMap()
}
that won't interact well with value/moving semantics but I suspect that not much will.