Skip to content

Commit

Permalink
Merge pull request #3469 from opensim-org/fix_3468-make-macros-namesp…
Browse files Browse the repository at this point in the history
…ace-independent

Make OpenSim macros namespace-independent (#3468)
  • Loading branch information
adamkewley authored May 30, 2023
2 parents a67074f + b965bc8 commit 38346cf
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ v4.5
- Fixed `CMC_TaskSet` memory leak whenever it is copied (#3457)
- Added `SIMBODY_EXTRA_CMAKE_ARGS` to `dependencies/CMakeLists.txt`, which lets integrators customize Simbody via the OpenSim superbuild (#3455)
- Fixed out-of-bounds memory access in testAssemblySolver (#3460)
- The property, input, output, and socket macros (e.g. OpenSim_DECLARE_PROPERTY) can now be used outside of the OpenSim namespace
and no longer require a `using namespace OpenSim;` declaration in order to work (#3468)
- Fixed runtime segfault that can occur when trying to use a `WrapObject` that is not a child of a `PhysicalFrame` (#3465)


Expand Down
7 changes: 5 additions & 2 deletions OpenSim/Common/ComponentOutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ class Output<T>::Channel : public AbstractChannel {
friend Output<T>& Output<T>::operator=(const Output&);
#endif
};
} // end of namespace OpenSim

// below: macro definitions (care: these must be defined such that they
// can be expanded in classes that are outside of the OpenSim
// namespace: see issue #3468)

// TODO consider using std::reference_wrapper<T> as type for _output_##oname,
// since it is copyable.
Expand Down Expand Up @@ -503,6 +508,4 @@ class Output<T>::Channel : public AbstractChannel {
//=============================================================================
//=============================================================================

} // end of namespace OpenSim

#endif // OPENSIM_COMPONENT_OUTPUT_H_
32 changes: 18 additions & 14 deletions OpenSim/Common/ComponentSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,12 @@ class Input : public AbstractInput {
SimTK::ResetOnCopy<AliasList> _aliases;
}; // END class Input<Y>

} // end of namespace OpenSim


// below: macro definitions (care: these must be defined such that they
// can be expanded in classes that are outside of the OpenSim
// namespace: see issue #3468)

/// @name Creating Sockets to other objects for your Component
/// Use these macros at the top of your component class declaration,
Expand Down Expand Up @@ -1002,7 +1008,7 @@ class Input : public AbstractInput {
OpenSim_DOXYGEN_Q_PROPERTY(T, cname) \
/** @} */ \
/** @cond */ \
PropertyIndex PropertyIndex_socket_##cname { \
OpenSim::PropertyIndex PropertyIndex_socket_##cname { \
this->template constructSocket<T>(#cname, \
"Path to a Component that satisfies the Socket '" \
#cname "' of type " #T " (description: " comment ").") \
Expand All @@ -1014,7 +1020,7 @@ class Input : public AbstractInput {
/** Call finalizeConnections() afterwards to update the socket's */ \
/** connectee path property. The reference to the connectee set here */ \
/** takes precedence over the connectee path property. */ \
void connectSocket_##cname(const Object& object) { \
void connectSocket_##cname(const OpenSim::Object& object) { \
this->updSocket(#cname).connect(object); \
} \
/** @} */
Expand Down Expand Up @@ -1079,12 +1085,12 @@ class Input : public AbstractInput {
OpenSim_DOXYGEN_Q_PROPERTY(T, cname) \
/** @} */ \
/** @cond */ \
PropertyIndex PropertyIndex_socket_##cname { \
OpenSim::PropertyIndex PropertyIndex_socket_##cname { \
constructSocket_##cname() \
}; \
/* Declare the method used in the in-class member initializer. */ \
/* This method will be defined by OpenSim_DEFINE_SOCKET_FD. */ \
PropertyIndex constructSocket_##cname(); \
OpenSim::PropertyIndex constructSocket_##cname(); \
/* Remember the provided type so we can use it in the DEFINE macro. */ \
typedef T _socket_##cname##_type; \
/** @endcond */ \
Expand All @@ -1094,7 +1100,7 @@ class Input : public AbstractInput {
/** Call finalizeConnections() afterwards to update the socket's */ \
/** connectee path property. The reference to the connectee set here */ \
/** takes precedence over the connectee path property. */ \
void connectSocket_##cname(const Object& object) { \
void connectSocket_##cname(const OpenSim::Object& object) { \
this->updSocket(#cname).connect(object); \
} \
/** @} */
Expand All @@ -1118,7 +1124,7 @@ class Input : public AbstractInput {
// than `MyComponent` but that include MyComponent.h). OpenSim::Geometry is an
// example of this scenario.
#define OpenSim_DEFINE_SOCKET_FD(cname, Class) \
PropertyIndex Class::constructSocket_##cname() { \
OpenSim::PropertyIndex Class::constructSocket_##cname() { \
using T = _socket_##cname##_type; \
std::string typeStr = T::getClassName(); \
return this->template constructSocket<T>(#cname, \
Expand Down Expand Up @@ -1171,7 +1177,7 @@ PropertyIndex Class::constructSocket_##cname() { \
OpenSim_DOXYGEN_Q_PROPERTY(T, iname) \
/** @} */ \
/** @cond */ \
PropertyIndex PropertyIndex_input_##iname { \
OpenSim::PropertyIndex PropertyIndex_input_##iname { \
this->template constructInput<T>(#iname, false, \
"Path to an output (channel) to satisfy the one-value Input '" \
#iname "' of type " #T " (description: " comment ").", istage) \
Expand All @@ -1188,7 +1194,7 @@ PropertyIndex Class::constructSocket_##cname() { \
/** Call finalizeConnections() afterwards to update the input's */ \
/** connectee path property. The reference to the output set here */ \
/** takes precedence over the connectee path property. */ \
void connectInput_##iname(const AbstractOutput& output, \
void connectInput_##iname(const OpenSim::AbstractOutput& output, \
const std::string& alias = "") { \
updInput(#iname).connect(output, alias); \
} \
Expand All @@ -1198,7 +1204,7 @@ PropertyIndex Class::constructSocket_##cname() { \
/** Call finalizeConnections() afterwards to update the input's */ \
/** connectee path property. The reference to the channel set here */ \
/** takes precedence over the connectee path property. */ \
void connectInput_##iname(const AbstractChannel& channel, \
void connectInput_##iname(const OpenSim::AbstractChannel& channel, \
const std::string& alias = "") { \
updInput(#iname).connect(channel, alias); \
} \
Expand Down Expand Up @@ -1238,7 +1244,7 @@ PropertyIndex Class::constructSocket_##cname() { \
OpenSim_DOXYGEN_Q_PROPERTY(T, iname) \
/** @} */ \
/** @cond */ \
PropertyIndex PropertyIndex_input_##iname { \
OpenSim::PropertyIndex PropertyIndex_input_##iname { \
this->template constructInput<T>(#iname, true, \
"Paths to outputs (channels) to satisfy the list Input '" \
#iname "' of type " #T " (description: " comment "). " \
Expand All @@ -1257,7 +1263,7 @@ PropertyIndex Class::constructSocket_##cname() { \
/** Call finalizeConnections() afterwards to update the input's */ \
/** connectee path property. The reference to the output set here */ \
/** takes precedence over the connectee path property. */ \
void connectInput_##iname(const AbstractOutput& output, \
void connectInput_##iname(const OpenSim::AbstractOutput& output, \
const std::string& alias = "") { \
updInput(#iname).connect(output, alias); \
} \
Expand All @@ -1267,13 +1273,11 @@ PropertyIndex Class::constructSocket_##cname() { \
/** Call finalizeConnections() afterwards to update the input's */ \
/** connectee path property. The reference to the channel set here */ \
/** takes precedence over the connectee path property. */ \
void connectInput_##iname(const AbstractChannel& channel, \
void connectInput_##iname(const OpenSim::AbstractChannel& channel, \
const std::string& alias = "") { \
updInput(#iname).connect(channel, alias); \
} \
/** @} */
/// @}

} // end of namespace OpenSim

#endif // OPENSIM_COMPONENT_SOCKET_H_
12 changes: 8 additions & 4 deletions OpenSim/Common/Property.h
Original file line number Diff line number Diff line change
Expand Up @@ -1251,16 +1251,21 @@ TypeHelper::create(const std::string& name, bool isOne)
#ifndef SWIG
SimTK_DEFINE_UNIQUE_INDEX_TYPE(PropertyIndex);
#endif
} //namespace

// below: macro definitions (care: these must be defined such that they
// can be expanded in classes that are outside of the OpenSim
// namespace: see issue #3468)

// Used by OpenSim_DECLARE_PROPERTY_HELPER below to control the members
// that are used with SWIG.
#ifndef SWIG
#define OpenSim_DECLARE_PROPERTY_HELPER_PROPERTY_MEMBERS(name, T) \
/** @cond **/ \
PropertyIndex PropertyIndex_##name; \
const Property<T>& getProperty_##name() const \
OpenSim::PropertyIndex PropertyIndex_##name; \
const OpenSim::Property<T>& getProperty_##name() const \
{ return this->template getProperty<T>(PropertyIndex_##name); } \
Property<T>& updProperty_##name() \
OpenSim::Property<T>& updProperty_##name() \
{ return this->template updProperty<T>(PropertyIndex_##name); } \
/** @endcond **/
#else
Expand Down Expand Up @@ -1607,7 +1612,6 @@ OpenSim_DECLARE_PROPERTY_ATMOST() rather than this macro.
(minSize), (maxSize)) \
/** @} */

} //namespace
//=============================================================================
//=============================================================================

Expand Down
22 changes: 22 additions & 0 deletions OpenSim/Common/Test/testComponentInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@
#include <simbody/internal/MobilizedBody_Ground.h>
#include <random>

namespace
{
// compiler test (see issue #3468)
//
// - this component must be compiled before the `using namespace` declarations below
// - this component must be compile-able
// - it exists to test whether OpenSim's component+macro system works for components
// defined in their own namespace, without an implict dependency on `using namespace OpenSim`
// - this is effectively a compiler assertion that the OpenSim macros work as expected
// - more information available in issue #3468
class ComponentInAnonymousNamespace : public OpenSim::Component {
OpenSim_DECLARE_CONCRETE_OBJECT(ComponentInAnonymousNamespace, OpenSim::Component);

double getDoubleOutput(const SimTK::State&) const { return 0.0; }
public:
OpenSim_DECLARE_PROPERTY(some_prop, SimTK::Vec3, "comment");
OpenSim_DECLARE_INPUT(some_input, float, SimTK::Stage::Acceleration, "some other comment");
OpenSim_DECLARE_OUTPUT(some_output, double, getDoubleOutput, SimTK::Stage::Model);
OpenSim_DECLARE_SOCKET(some_socket, OpenSim::Component, "some socket comment");
};
}

using namespace OpenSim;
using namespace std;
using namespace SimTK;
Expand Down

0 comments on commit 38346cf

Please sign in to comment.