OpenSim
OpenSim 3.1
|
A Property<T> is a serializable (name, list-of-values) pair, where each value is of type T. More...
#include <Property.h>
Classes | |
struct | TypeHelper |
This is the generic definition of Property::TypeHelper to be used whenever T does not have a specialization, meaning that T must be a type derived from class Object. More... |
Public Member Functions | |
Property * | clone () const override=0 |
Make a new, deep copy (clone) of this concrete property and return a pointer to the heap space. | |
std::string | getTypeName () const final |
Use TypeHelper's getTypeName() to satisfy this pure virtual. | |
const T & | operator[] (int i) const |
Get a const reference to one of the values in the value list. | |
T & | operator[] (int i) |
Get a writable reference to one of the values in the value list. | |
Property & | operator= (const T &value) |
Assignment to a value of type T sets the value of this single-valued property to a copy of the supplied value; not allowed for a list property. | |
template<template< class > class Container> | |
Property & | operator= (const Container< T > &valueList) |
Assignment to a container of values of type T sets the entire value list of this list property to a copy of the values in the container. | |
void | setValue (int i, const T &value) |
Replace the i'th value list element with a copy of the given value. | |
void | setValue (const T &value) |
Provide a new value for a single-valued property. | |
template<template< class > class Container> | |
void | setValue (const Container< T > &valueList) |
Assignment to a container of values of type T sets the entire value list of this list property to a copy of the values in the container. | |
const T & | getValue (int index=-1) const |
Return a const reference to the selected value from this property's value list. | |
T & | updValue (int index=-1) |
Return a writable reference to the selected value from this property's value list. | |
int | appendValue (const T &value) |
Append a copy of the supplied value to the end of this property's value list. | |
int | appendValue (const T *value) |
Append a copy of the supplied value to the end of this property's value list. | |
int | adoptAndAppendValue (T *value) |
Add a new value to the end of this property's value list, taking over ownership of the supplied heap-allocated object. | |
int | findIndex (const T &value) const |
Search the value list for an element that has the given value and return its index if found, otherwise -1. | |
Public Member Functions inherited from OpenSim::AbstractProperty | |
void | setAllowableListSize (int aMin, int aMax) |
Require that the number of values n in the value list of this property be in the range aMin <= n <= aMax. | |
void | setAllowableListSize (int aNum) |
Require that the number of values n in the value list of this property be exactly n=aNum values. | |
virtual | ~AbstractProperty () |
Return all heap space used by this property. | |
virtual std::string | toString () const =0 |
For relatively simple types, return the current value of this property in a string suitable for displaying to a user in the GUI. | |
virtual bool | isObjectProperty () const =0 |
Return true if this is an "object property", meaning that its values are all concrete objects of types that ultimately derive from the OpenSim serializable base class Object. | |
virtual bool | isUnnamedProperty () const =0 |
An unnamed property is a one-object property whose name was given as null or as the contained object's type tag. | |
bool | equals (const AbstractProperty &other) const |
Compare this property with another one; this is primarily used for testing. | |
bool | isSamePropertyClass (const AbstractProperty &other) const |
Return true if the other property is an object of exactly the same concrete class as this one. | |
bool | operator== (const AbstractProperty &other) const |
See the equals() method for the meaning of this operator. | |
void | setAllPropertiesUseDefault (bool shouldUseDefault) |
This method sets the "use default" flag for this property and the properties of any objects it contains to the given value. | |
void | readFromXMLParentElement (SimTK::Xml::Element &parent, int versionNumber) |
Given an XML parent element expected to contain a value for this property as an immediate child element, find that property element and set the property value from it. | |
void | writeToXMLParentElement (SimTK::Xml::Element &parent) |
Given an XML parent element, append a single child element representing the serialized form of this property. | |
void | setName (const std::string &name) |
Set the property name. | |
void | setComment (const std::string &aComment) |
Set a user-friendly comment to be associated with property. | |
void | setValueIsDefault (bool isDefault) |
Set flag indicating whether the value of this property was simply taken from a default object and thus should not be written out when serializing. | |
const std::string & | getName () const |
Get the property name. | |
const std::string & | getComment () const |
Get the comment associated with this property. | |
bool | getValueIsDefault () const |
Get the flag indicating whether the current value is just the default value for this property (in which case it doesn't need to be written out). | |
int | getMinListSize () const |
Get the minimum number of values allowed in this property's value list. | |
int | getMaxListSize () const |
Get the maximum number of values allowed in this property's value list. | |
bool | isOptionalProperty () const |
This is an "optional" property if its value list can contain at most one value. | |
bool | isListProperty () const |
This is a "list" property if its value list can contain more than one value. | |
bool | isOneValueProperty () const |
This is a "one-value" property if its value list must always contain exactly one value. | |
bool | isOneObjectProperty () const |
This is a "one-object" property if it is a "one-value" property and it contains an Object-derived value. | |
int | size () const |
Return the number of values currently in this property's value list. | |
bool | empty () const |
Return true if this property's value list is currently empty. | |
void | clear () |
Empty the value list for this property; fails if zero is not an allowable size for this property. | |
virtual const Object & | getValueAsObject (int index=-1) const =0 |
For an object property, the values can be obtained as references to the abstract base class Object from which all the objects derive. | |
virtual Object & | updValueAsObject (int index=-1)=0 |
Get writable access to an existing object value. | |
virtual void | setValueAsObject (const Object &obj, int index=-1)=0 |
Set the indicated value element to a new copy of the supplied object. |
Static Public Member Functions | |
static bool | isA (const AbstractProperty &prop) |
Return true if the given AbstractProperty references a concrete property of this type (Property<T>). | |
static const Property & | getAs (const AbstractProperty &prop) |
Attempt to downcast the given AbstractProperty to a concrete property of this type (Property<T>). | |
static Property & | updAs (AbstractProperty &prop) |
Attempt to downcast the given AbstractProperty to a writable concrete property of this type (Property<T>). |
Related Functions | |
(Note that these are not member functions.) | |
#define | OpenSim_DECLARE_PROPERTY(name, T, comment) |
Declare a required, single-value property of the given name and type T, with an associated comment. | |
#define | OpenSim_DECLARE_UNNAMED_PROPERTY(T, comment) |
Declare a required, unnamed property holding exactly one object of type T derived from OpenSim's Object class and identified by that object's class name rather than a property name. | |
#define | OpenSim_DECLARE_OPTIONAL_PROPERTY(name, T, comment) |
Declare a property of the given name containing an optional value of the given type T (that is, the value list can be of length 0 or 1 only). | |
#define | OpenSim_DECLARE_LIST_PROPERTY(name, T, comment) |
Declare a property of the given name containing a variable-length list of values of the given type T. | |
#define | OpenSim_DECLARE_LIST_PROPERTY_SIZE(name, T, listSize, comment) |
Declare a property of the given name containing a list of values of the given type T, with the number of values in the list restricted to be exactly listSize (> 0) elements, no more or less. | |
#define | OpenSim_DECLARE_LIST_PROPERTY_ATLEAST(name, T, minSize, comment) |
Declare a property of the given name containing a list of values of the given type T, with the number of values required to be at least minSize (> 0) elements. | |
#define | OpenSim_DECLARE_LIST_PROPERTY_ATMOST(name, T, maxSize, comment) |
Declare a property of the given name containing a list of values of the given type T, with the number of values in the list restricted to be no more than maxSize (> 0) elements. | |
#define | OpenSim_DECLARE_LIST_PROPERTY_RANGE(name, T, minSize, maxSize, comment) |
Declare a property of the given name containing a list of values of the given type T, with the number of values in the list restricted to be in the range minSize (> 0) to maxSize (> minSize). |
Additional Inherited Members | |
Protected Member Functions inherited from OpenSim::AbstractProperty | |
AbstractProperty () | |
AbstractProperty (const std::string &name, const std::string &comment) | |
virtual bool | isEqualTo (const AbstractProperty &other) const =0 |
The base class equals() method will have already done a lot of checking prior to calling this method, including verifying that both values are non-default and that the value lists are the same size; the concrete property need only compare the values. | |
virtual void | readFromXMLElement (SimTK::Xml::Element &propertyElement, int versionNumber)=0 |
Read in a new value for this property from the XML element propertyElement. | |
virtual void | writeToXMLElement (SimTK::Xml::Element &propertyElement) const =0 |
Output a serialized representation of this property by writing its value to the given XML property element. | |
virtual int | getNumValues () const =0 |
How may values are currently stored in this property? If this is an object property you can use this with getValueAsObject() to iterate over the contained objects. | |
virtual void | clearValues ()=0 |
If the concrete property allows it, clear the value list. | |
virtual bool | isAcceptableObjectTag (const std::string &objectTypeTag) const =0 |
Return true if the given string is the XML tag name for one of the Object-derived types that is allowed by this property. |
A Property<T> is a serializable (name, list-of-values) pair, where each value is of type T.
The number of values allowed in the list is an attribute of the property; often it is just a single value. Properties are owned by classes that derive from OpenSim's serializable Object base class. The documentation here is most useful for developers who are interested in creating a new ModelComponent or other serializable class derived from Object.
A property's contained type T must be a serializable type. Serializable types come in two flavors:
When T is a simple type we'll write T=S and refer to a Property<S> as a "simple property". When T is an object type, we'll write T=O and refer to a Property<O> as an "object property".
In case type O is a still-abstract Object-derived type like Function or Controller, a Property<O> can hold a mix of any concrete objects derived from O (e.g., any Object that can be dynamic_cast to a Function can be held by a Property<Function>).
The objects in an object property will themselves have properties so a Property<O> can be viewed as a node in the tree of objects that constitute an OpenSim Model. Simple properties Property<S> can be viewed as the terminal nodes of that tree. Properties are thus an integral part of the structure of an OpenSim Model; anything contained in a property is owned by that property; deleting the property deletes its contained objects. If you want to reference another Object from within a property, use a string property to reference it by name; the result is a simple property. It is not permitted for type T to be a pointer or reference.
The general representation for a Property<T> with name "prop_name" is
where "T" is the XML representation for objects of type T. Note that if T is an object type O, its representation follows the pattern
where OTypeName
stands for the name of the concrete, Object-derived class being serialized, and OContents
is the representation generated by that class when asked to serialize itself.
A Property<O> that is restricted to holding exactly one object of type O is called a "one-object property". It could be represented in XML as
but we allow a more compact representation for one-object properties:
In the one-object case it is also permissible for the property to be unnamed, in which case it may be referenced as though its name were the same as the object type name, and there is no separate "name" attribute. The XML representation for an unnamed property is just:
On input, if a name attribute is seen for an unnamed property it is ignored; only the object type name tag matters in the unnamed case. Note that only one-object properties can be unnamed, and no single OpenSim object can have more than one unnamed property of the same type.
In addition to the name and list of values, every property has the following attributes:
The "used default value" flag specifies that the value stored with this property was taken from a default object and not subsequently changed. A property with this flag set is not written out when a model is serialized.
Properties are maintained in a PropertyTable by OpenSim's Object base class that is used for all serializable objects. Do not create Property objects directly; instead, use the provided macros to declare them in the class declarations for objects derived from Object. These macros should appear in the header file near the top of your class declaration, and should be preceded by Doxygen comments describing the property being declared.
Naming conventions: OpenSim property names should use lower case letters with words_separated_by_underscores
. In contrast, OpenSim object types begin with a capital letter and use camel case, that is, MixedUpperAndLowerLikeThis
. This prevents any possible collisions between property names and object types, allowing both to be used as XML tag identifiers with no conflicts.
These are the most common forms of property declaration. Click on the macro names below for more information.
In the above, T may be a simple type S or object type O. In the case of a single-value property where type T is a type derived from Object (i.e., T=O), you can declare the property to be unnamed and instead use the class name of the object type O to identify the property:
Only one unnamed property of a particular object type O may be declared in any given Object.
Finally, for list properties you can declare restrictions on the allowable list length:
Here is an example of an object declaring two properties, including our convention of documenting the property declarations in their own Doxygen group entitled "Property declarations".
* class ActuatorWorkMeter : public ModelComponent { * OpenSim_DECLARE_CONCRETE_OBJECT(ActuatorWorkMeter, ModelComponent); * public: * //======================================================================= * // PROPERTIES * //======================================================================= * /** @name Property declarations * These are the serializable properties associated with this class. **/ * /**@{**/ * OpenSim_DECLARE_PROPERTY(actuator_name, std::string, * "The name of the actuator whose work use will be calculated."); * OpenSim_DECLARE_PROPERTY(initial_actuator_work, double, * "Initial value for work; normally zero."); * /**@}**/ * //======================================================================= * // PUBLIC METHODS * //======================================================================= * ... * }; *
The constructors for your Object-derived class are required to construct and initialize the properties to whatever default values you want them to have. The above macros will have generated for each property a method for this purpose. If your property is named prop_name, then the method will be called constructProperty_prop_name(). (In the case of unnamed properties, the object type serves as prop_name.) The initial value is provided as an argument, which is optional for those properties that are allowed to contain a zero-length value list. Here are the various types of generated construction methods:
The first form above is generated for basic, optional, and unnamed properties. The second, uninitialized form is generated for optional, unrestricted list, and list "atmost" properties, since those can accept a zero-element value list. The last form is generated for all list properties, regardless of size restriction; a runtime check verifies that size restrictions are met. That form accepts any container type that supports a size() method and random access element selection with operator[], such as std::vector<T>, OpenSim::Array<T>, or SimTK::Array_<T>.
The above methods are conventionally collected into a private method of each object class called constructProperties()
. This method is then invoked from every constructor, except the copy constructor (which you normally should let the compiler generate, but see below).
Your best bet is to use the compiler-generated default copy constructor and default copy assignment operator that you get whenever you leave these methods undefined. If you do that, all your properties and their associated local data will be copied automatically. It is worth some effort to design your objects so that their data members can copy and assign themselves correctly; you might find SimTK::ReferencePtr<T> and SimTK::ClonePtr<T> useful for getting pointer members to behave themselves properly.
However, if you do have to write your own copy constructor and copy assignment operator (and if you write one you must write the other also), the property table will still have been copied properly by your superclass, it is only the local property indices that you have to deal with. For that, each property has defined a method like:
In the above, Self
is the type of the object being defined and source
is the argument that was passed to the containing copy constructor or copy assignment operator.
The property declaration macros also generate per-property methods for getting access to property values or the the Property objects themselves. These inline methods are very fast and can be used whenever you need access to a property value. The following are generated for single-valued property types, including the basic, optional, and unnamed properties:
Additional methods are generated for list properties:
The last form accepts any container that has a size() method and allows element access using operator[]. Runtime checks verify that the list length is within the allowable range for the property. Note that every property is considered to have a value list (even when restricted to one element) so the indexed forms above can also be used with single-valued properties as long as the index is zero.
To get access to the Property object rather than one of its values, the following methods are provided:
The Property<T> class acts as a container of values, and has the usual size(), empty(), and operator[] methods available so you can use getProperty...() above to get access to those methods. For example, to write out all the values of any property:
|
inline |
Add a new value to the end of this property's value list, taking over ownership of the supplied heap-allocated object.
An exception is thrown if the property can't hold any more values. The index assigned to this value is returned.
|
inline |
Append a copy of the supplied value to the end of this property's value list.
An exception is thrown if the property can't hold any more values. The index assigned to this value is returned.
Reimplemented from OpenSim::AbstractProperty.
|
inline |
Append a copy of the supplied value to the end of this property's value list.
An exception is thrown if the property can't hold any more values. The index assigned to this value is returned. Note that although we accept a pointer here, we do not take over ownership. See adoptAndAppendValue() if you want the property to take ownership.
|
overridepure virtual |
Make a new, deep copy (clone) of this concrete property and return a pointer to the heap space.
Caller must delete the returned object when done with it.
Implements OpenSim::AbstractProperty.
|
inline |
Search the value list for an element that has the given value and return its index if found, otherwise -1.
This requires only that the template type T supports operator==(). This is a linear search so will take time proportional to the length of the value list.
|
inlinestatic |
Attempt to downcast the given AbstractProperty to a concrete property of this type (Property<T>).
An exception is thrown if this is not the right type; see isA() if you need to check first.
|
inlinevirtual |
Use TypeHelper's getTypeName() to satisfy this pure virtual.
Implements OpenSim::AbstractProperty.
|
inline |
Return a const reference to the selected value from this property's value list.
If the property is at most single valued then the index is optional and we'll behave as though index=0 were supplied. You can use the square bracket operator property[index] instead.
Reimplemented from OpenSim::AbstractProperty.
|
inlinestatic |
Return true if the given AbstractProperty references a concrete property of this type (Property<T>).
Note that for this to return true, the type T must be exactly the type used when the concrete property was allocated; it is not sufficient for T to be a more general base type from which the actual type was derived.
|
inline |
Assignment to a value of type T sets the value of this single-valued property to a copy of the supplied value; not allowed for a list property.
This does not invoke the assignment operator on the existing value. Instead, the value list is cleared and then replaced by the new value. This is synonymous with setValue(value).
|
inline |
Assignment to a container of values of type T sets the entire value list of this list property to a copy of the values in the container.
The current value list is cleared before the assignment. This is synonymous with setValue(valueList).
|
inline |
Get a const reference to one of the values in the value list.
This will throw an exception if the index does not refer to an already-existing value. This operator is synonymous with getValue(i).
|
inline |
Get a writable reference to one of the values in the value list.
This will throw an exception if the index does not refer to an already-existing value. This operator is synonymous with updValue(i).
|
inline |
Replace the i'th value list element with a copy of the given value.
The index i must be between 0 and the current list length, meaning it is OK to refer one element past the last element. In that case the new value is appended to the list using appendValue(), which will throw an exception if the list is already at its maximum allowable size. In the case where index i refers to an existing element, a simple property will assign a new value to the existing element but an object property will delete the old object and replace it with a clone() of the new one – it will not invoke the old object's assignment operator. That means that the concrete object type may be changed by this operation, provided it is still a type derived from object type T. If you want to invoke the existing value's assignment operator, use updValue(i) rather than setValue(i).
|
inline |
Provide a new value for a single-valued property.
The current value (if any) is replaced, and size()==1 afterwards. An exception is thrown if this is a list property.
|
inline |
Assignment to a container of values of type T sets the entire value list of this list property to a copy of the values in the container.
The current value is cleared before the assignment.
|
inlinestatic |
Attempt to downcast the given AbstractProperty to a writable concrete property of this type (Property<T>).
An exception is thrown if this is not the right type; see isA() if you need to check first.
|
inline |
Return a writable reference to the selected value from this property's value list.
If the property is at most single valued then the index is optional and we'll behave as though index=0 were supplied. You can use the square bracket operator property[index] instead.
Reimplemented from OpenSim::AbstractProperty.
|
related |
Declare a property of the given name containing a variable-length list of values of the given type T.
The property may be constructed as empty, or with initialization to a templatized Container<T> for any Container that supports a size() method and operator[] element selection.
|
related |
Declare a property of the given name containing a list of values of the given type T, with the number of values required to be at least minSize (> 0) elements.
Such a property must be initialized at construction, by providing a templatized Container<T> with at least minSize elements, using any Container that supports a size() method and operator[] element selection.
|
related |
Declare a property of the given name containing a list of values of the given type T, with the number of values in the list restricted to be no more than maxSize (> 0) elements.
This kind of property may optionally be initialized at construction, by providing a templatized Container<T> with no more than maxSize elements, using any Container that supports a size() method and operator[] element selection.
|
related |
Declare a property of the given name containing a list of values of the given type T, with the number of values in the list restricted to be in the range minSize (> 0) to maxSize (> minSize).
This kind of property must be initialized with at least minSize values at construction. If you want to allow zero elements, so that initialization is optional, use OpenSim_DECLARE_PROPERTY_ATMOST() rather than this macro.
|
related |
Declare a property of the given name containing a list of values of the given type T, with the number of values in the list restricted to be exactly listSize (> 0) elements, no more or less.
A fixed-size property must be initialized at construction, by providing a templatized Container<T> with the right number of elements, using any Container that supports a size() method and operator[] element selection.
|
related |
Declare a property of the given name containing an optional value of the given type T (that is, the value list can be of length 0 or 1 only).
The property may be constructed as empty, or with initialization to a single value of type T.
|
related |
Declare a required, single-value property of the given name and type T, with an associated comment.
The value list for this property will always contain exactly one element, and the property must be initialized at construction. This macro, and the other similar macros, define several related methods. If the property name is my_prop_name, then the defined methods are:
For some property types, the initial value may be omitted during construction. A data member is also created but is intended for internal use only:
|
related |
Declare a required, unnamed property holding exactly one object of type T derived from OpenSim's Object class and identified by that object's class name rather than a property name.
At construction, this property must be initialized with an object of type T.