// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef PXR_BASE_TF_PY_OBJ_WRAPPER_H #define PXR_BASE_TF_PY_OBJ_WRAPPER_H #include "pxr/pxr.h" #include "pxr/base/tf/api.h" #include #include #include #include #include PXR_NAMESPACE_OPEN_SCOPE /// \class TfPyObjWrapper /// /// Boost Python object wrapper. /// /// Provides a wrapper around boost::python::object that works correctly for the /// following basic operations regardless of the GIL state: default construction, /// copy construction, assignment, (in)equality comparison, hash_value(), and /// destruction. /// /// None of those work correctly in the presence of an unlocked GIL for /// boost::python::object. This class only actually acquires the GIL for default /// construction, destruction and for some (in)equality comparisons. The other /// operations do not require taking the GIL. /// /// This is primarily useful in cases where a boost::python::object might be /// destroyed without a locked GIL by a client blind to that fact. This occurs /// when a registry, for example, holds type-erased objects. If one /// of the type-erased objects in the registry happens to hold a /// boost::python::object, that type-erased object must be destroyed while the /// GIL is held but it's unreasonable to require that the registry know that. /// This class helps solve that problem. /// /// This class also provides many of the operators that boost::python::object /// provides, by virtue of deriving from boost::python::api::object_operators. /// However it is important to note that callers must ensure the GIL is held /// before using these operators! class TfPyObjWrapper : public boost::python::api::object_operators { typedef boost::python::object object; public: /// Default construct a TfPyObjWrapper holding a reference to python None. /// The GIL need not be held by the caller. TF_API TfPyObjWrapper(); /// Construct a TfPyObjectWrapper wrapping \a obj. /// The GIL must be held by the caller. Note, allowing the implicit /// conversion is intended here. TF_API TfPyObjWrapper(object obj); /// Underlying object access. /// This method returns a reference, so technically, the GIL need not be /// held to call this. However, the caller is strongly advised to ensure /// the GIL is held, since assigning this object to another or otherwise /// operating on the returned object requires it. object const &Get() const { return *_objectPtr; } /// Underlying PyObject* access. /// This method returns a pointer, so technically, the GIL need not be /// held to call this. However, the caller is strongly advised to ensure /// the GIL is held, since assigning this object to another or otherwise /// operating on the returned object requires it. The returned PyObject * /// is a "borrowed reference", meaning that the underlying object's /// reference count has not been incremented on behalf of the caller. TF_API PyObject *ptr() const; /// Produce a hash code for this object. /// Note that this does not attempt to hash the underlying python object, /// it returns a hash code that's suitable for hash-table lookup of /// TfPyObjWrapper instances, and does not require taking the python lock. friend inline size_t hash_value(TfPyObjWrapper const &o) { return (size_t) o.ptr(); } /// Equality. /// Returns true if \a other refers to the same python object. TF_API bool operator==(TfPyObjWrapper const &other) const; /// Inequality. /// Returns false if \a other refers to the same python object. TF_API bool operator!=(TfPyObjWrapper const &other) const; private: // Befriend object_operators to allow it access to implicit conversion to // boost::python::object. friend class boost::python::api::object_operators; operator object const &() const { return Get(); } // Store a shared_ptr to a python object. std::shared_ptr _objectPtr; }; PXR_NAMESPACE_CLOSE_SCOPE #endif // PXR_BASE_TF_PY_OBJ_WRAPPER_H