Let us first change the old SGPropertyNode class to better meet our ideas. Each of the raw setters/getters (the ones like get_bool that deal with the type of the node) should get an underscore and be made to be "private": these are now the raw variants. The new versions of those (named without the underscore) will be wrappers for them and will be declared "virtual", so that they can be overwritten by derived classes. For the SGPropertyNode class, these will be simple wrappers -- essentially the functions themselves. For derived classes, they will wrap them and also have special behavior "on top" of it: limiting, blocking, randomizing: anything! (all without tied nodes and preserving almost everything about the node.) The advantage is that these things become bi-liners (check-and-set) or tri-liners (check-change-and-set), etc., and they deal with the type of the node, versus the input type, so that if a node is only going to be a double, only that has to be overloaded. Additionally, a macro could be defined to overload all numeric types, so that something simple like limiting to +-1 could affect all get_type's with one line (though it might not make sense for non-doubles/non-floats).
Also, would it be possible to limit a derived class to only have one type? And unable to be tied? Maybe define an attribute for "do not change type" and set the type in the class:
- Code: Select all
int _attr=simgear::node::Type::DOUBLE
If we add support for these things, then we in theory just have to figure out how to initialize them, as all of the existing API including SGPropertyObjects should work. Maybe make an equivalent to Nasal's initNode() and give it a template to specify what SGPropertyNode-derived class to use?
Addendum: This is a re-post, I originally deleted it thinking that SGRawValue would do this, which it can, but that is actually a tied value and my solution is more elegant. I now realize that SGRawValue's are not what I want, so I am reposting this. One advantage is that these could easily be exposed to Nasal, so that it can define simple behavior changes for itself, besides the fact that there would obviously be ready-made limiting and wrapping classes with _min and _max.
P.S. One random thought: couldn't we compress the local stored value and tied/aliased pointers into one union, saving space? We don't necessarily have to change names, either, as an enum can be unnamed:
- Code: Select all
union {
// The right kind of pointer...
union {
SGPropertyNode * alias;
SGRaw* val;
} _value;
union {
bool bool_val;
int int_val;
long long_val;
float float_val;
double double_val;
char * string_val;
} _local_val;
};