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