1 #ifndef OPENSIM_PROPERTY_TABLE_H_
2 #define OPENSIM_PROPERTY_TABLE_H_
3 /* -------------------------------------------------------------------------- *
4 * OpenSim: PropertyTable.h *
5 * -------------------------------------------------------------------------- *
6 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation. *
7 * See http://opensim.stanford.edu and the NOTICE file for more information. *
8 * OpenSim is developed at Stanford University and supported by the US *
9 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA *
10 * through the Warrior Web program. *
11 * *
12 * Copyright (c) 2005-2017 Stanford University and the Authors *
13 * Author(s): Cassidy Kelly, Michael A. Sherman *
14 * *
15 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
16 * not use this file except in compliance with the License. You may obtain a *
17 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
18 * *
19 * Unless required by applicable law or agreed to in writing, software *
20 * distributed under the License is distributed on an "AS IS" BASIS, *
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
22 * See the License for the specific language governing permissions and *
23 * limitations under the License. *
24 * -------------------------------------------------------------------------- */
25
26 // INCLUDES
27 #include "osimCommonDLL.h"
28 #include "Property.h"
29
30 #include <map>
31
32 namespace OpenSim {
33
34 //==============================================================================
35 // PROPERTY TABLE
36 //==============================================================================
37 /**
38 * A property table is the container that an OpenSim Object uses to hold its
39 * properties (each derived from base class AbstractProperty). It provides
40 * methods to add properties to the table, and preserves the order with which
41 * they are defined. Methods for retrieving properties by name or by ordinal
42 * are provided. The table is the owner of the individual property objects and
43 * those are deleted when the table is deleted.
44 *
45 * Duplicate property names are not allowed in the same property table. Some
46 * properties are unnamed, however; that is only allowed when the property
47 * holds a single object, and we use the object class name as though it were
48 * the property's name (and they can still be looked up by ordinal also). That
49 * means no Object can contain two unnamed properties holding the same type of
50 * object since that would appear as a duplicate name.
51 *
52 * @author Cassidy Kelly, Michael Sherman
53 * @see AbstractProperty, Property, Object
54 */
55 class OSIMCOMMON_API PropertyTable {
56 //==============================================================================
57 // METHODS
58 //==============================================================================
59 public:
60 /** Create an empty table. **/
PropertyTable()61 PropertyTable() {}
62 /** The destructor deletes all the property object in this table; any
63 existing references to them or to their values become invalid. **/
64 ~PropertyTable();
65 /** Copy constructor performs a deep copy; that is, this table contains
66 new property objects initialized from those in the source. **/
67 PropertyTable(const PropertyTable& source);
68 /** Copy assignment performs a deep copy; this table will be as though
69 it had been copy constructed from the source. **/
70 PropertyTable& operator=(const PropertyTable& source);
71
72 /** Delete all the properties currently in this table, restoring the
73 table to its default-constructed state. **/
74 void clear();
75
76 /** Compare this table to another one for equality. Two tables are defined
77 to be equal if they have the same number of properties, and each property
78 tests equal to the one with the same index. **/
79 bool equals(const PropertyTable& other) const;
80
81 #ifndef SWIG
82 /** See equals() for the meaning of this operator. **/
83 bool operator==(const PropertyTable& other) const {return equals(other);}
84 #endif
85
86 /** Add a new property to this table, taking over ownership of the
87 supplied heap-allocated property. Throws an exception if there is already
88 a property with the same name in the table. Returns an index (ordinal)
89 that can be used to retrieve this property quickly. **/
90 int adoptProperty(AbstractProperty* prop);
91
92 /** Return a const reference to a property of known type T from the
93 table by name. This will throw an exception if no property with this name
94 is present, or if the property is present but not of type T. **/
95 template <class T> const Property<T>&
96 getProperty(const std::string& name) const;
97
98 /** Return a const reference to a property of known type T from the
99 table by its index (numbered in order of addition to the table). This will
100 throw an exception if the index is out of range, or if the property is
101 present but not of type T. **/
102 template <class T> const Property<T>& getProperty(int index) const;
103
104 /** Return a writable reference to a property of known type T from the
105 table by name. This will throw an exception if no property with this name
106 is present, or if the property is present but not of type T. **/
107 template <class T> Property<T>& updProperty(const std::string& name);
108
109 /** Return a writable reference to a property of known type T from the
110 table by its index (numbered in order of addition to the table). This will
111 throw an exception if the index is out of range, or if the property is
112 present but not of type T. **/
113 template <class T> Property<T>& updProperty(int index);
114
115 /** Return true if there is a property with the given name currently
116 stored in this table. **/
hasProperty(const std::string & name)117 bool hasProperty(const std::string& name) const
118 { return findPropertyIndex(name) >= 0; }
119
120 /** Look up a property by name and return a pointer providing const access
121 to the stored AbstractProperty object if present, otherwise null. **/
getPropertyPtr(const std::string & name)122 const AbstractProperty* getPropertyPtr(const std::string& name) const {
123 const int ix = findPropertyIndex(name);
124 return ix < 0 ? NULL : &getAbstractPropertyByIndex(ix);
125 }
126 /** Look up a property by name and return a pointer providing writable
127 access to the stored AbstractProperty object if present, otherwise null. **/
updPropertyPtr(const std::string & name)128 AbstractProperty* updPropertyPtr(const std::string& name) {
129 const int ix = findPropertyIndex(name);
130 return ix < 0 ? NULL : &updAbstractPropertyByIndex(ix);
131 }
132
133 /** Return the number of properties currently in this table. If this
134 returns n, the properties are indexed 0 to n-1, in the order they were
135 added to the table. **/
getNumProperties()136 int getNumProperties() const {return (int)properties.size();}
137
138 /** Retrieve a property by its index, which must be in the range
139 0..getNumProperties()-1. The property index is assigned in the order that
140 the properties were added to this table. **/
141 const AbstractProperty& getAbstractPropertyByIndex(int index) const;
142
143 /** Retrieve a writable reference to a property by its index, which must be
144 in the range 0..getNumProperties()-1. The property index is assigned in the
145 order that the properties were added to this table. **/
146 AbstractProperty& updAbstractPropertyByIndex(int index);
147
148 /** Retrieve a property by name if it exists, otherwise throw an
149 exception. The property is returned as an AbstractProperty; see
150 getProperty<T>() if you know the property type. **/
151 const AbstractProperty&
152 getAbstractPropertyByName(const std::string& name) const;
153
154 /** Retrieve a writable reference to a property by name if it exists,
155 otherwise throw an exception. The property is returned as an
156 AbstractProperty; see updProperty<T>() if you know the property type. **/
157 AbstractProperty& updAbstractPropertyByName(const std::string& name);
158
159 /** Return the property's index if it is present, else -1. **/
160 int findPropertyIndex(const std::string& name) const;
161
162
163 //==============================================================================
164 // DATA
165 //==============================================================================
166 private:
167 // Make this properties array a deep copy of the source. Any existing
168 // properties are deleted first. The index map is updated appropriately.
169 void replaceProperties(const SimTK::Array_<AbstractProperty*>& source);
170 // Delete all properties and clear the index map.
171 void deleteProperties();
172
173 // The properties, in the order they were added.
174 SimTK::Array_<AbstractProperty*> properties;
175 // A mapping from property name to its index in the properties array.
176 std::map<std::string, int> propertyIndex;
177
178 //==============================================================================
179 }; // END of class PropertyTable
180
181
182 //==============================================================================
183 // IMPLEMENTATION OF TEMPLATIZED METHODS
184 //==============================================================================
185
186 template <class T> inline
getProperty(const std::string & name)187 const Property<T>& PropertyTable::getProperty(const std::string &name) const {
188 const AbstractProperty& prop = getAbstractPropertyByName(name);
189 return Property<T>::getAs(prop);
190 }
191
192 template <class T> inline
getProperty(int index)193 const Property<T>& PropertyTable::getProperty(int index) const {
194 const AbstractProperty& prop = getAbstractPropertyByIndex(index);
195 return Property<T>::getAs(prop);
196 }
197
198 template <class T> inline
updProperty(const std::string & name)199 Property<T>& PropertyTable::updProperty(const std::string &name) {
200 AbstractProperty& prop = updAbstractPropertyByName(name);
201 return Property<T>::updAs(prop);
202 }
203
204 template <class T> inline
updProperty(int index)205 Property<T>& PropertyTable::updProperty(int index) {
206 AbstractProperty& prop = updAbstractPropertyByIndex(index);
207 return Property<T>::updAs(prop);
208 }
209
210 }; //namespace
211
212 #endif // OPENSIM_PROPERTY_TABLE_H_
213