diff --git a/CMakeLists.txt b/CMakeLists.txt index fbfbe15217d253aa1c5ef4e00d2289b5d24024e1..4715efdfd9a81568a376cf907fb66e1f1dd761fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ SET(${PROJECT_NAME}_HEADERS src/fwd.hpp src/map.hpp src/geometry.hpp + src/memory.hpp src/angle-axis.hpp src/quaternion.hpp ) diff --git a/src/eigenpy.hpp b/src/eigenpy.hpp index 97d26c70cd02a7f3fa00f725a2e4258a0ce96a9d..9acb89771b16ad2058ed0871209dca787e1243b2 100644 --- a/src/eigenpy.hpp +++ b/src/eigenpy.hpp @@ -18,6 +18,7 @@ #define __eigenpy_eigenpy_hpp__ #include "eigenpy/fwd.hpp" +#include "eigenpy/memory.hpp" namespace eigenpy { diff --git a/src/memory.hpp b/src/memory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a9fa9ba20448847ad51d6d5885a3430d001fcfbd --- /dev/null +++ b/src/memory.hpp @@ -0,0 +1,104 @@ +/* + * Copyright 2016, Justin Carpentier, LAAS-CNRS + * + * This file is part of eigenpy. + * eigenpy is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * eigenpy is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. You should + * have received a copy of the GNU Lesser General Public License along + * with eigenpy. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __eigenpy_memory_hpp__ +#define __eigenpy_memory_hpp__ + +#include <boost/python.hpp> + +/** + * This section contains a convenience MACRO which allows an easy specialization of + * Boost Python Object allocator for struct data types containing Eigen objects and requiring + * strict alignment. + */ +#define EIGENPY_DEFINE_STRUCT_ALLOCATOR_SPECIALIZATION(...) \ +namespace boost { namespace python { namespace objects { \ + template<> \ + struct instance< value_holder<__VA_ARGS__> > \ + { \ + typedef value_holder<__VA_ARGS__> Data; \ + PyObject_VAR_HEAD \ + PyObject* dict; \ + PyObject* weakrefs; \ + instance_holder* objects; \ + \ + typedef typename type_with_alignment< \ + ::boost::alignment_of<Data>::value \ + >::type align_t; \ + \ + union \ + { \ + align_t align; \ + char bytes[sizeof(Data) + 16]; \ + } storage; \ + }; \ + \ + template<class Derived> \ + struct make_instance_impl<__VA_ARGS__, value_holder<__VA_ARGS__>, Derived> \ + { \ + typedef __VA_ARGS__ T; \ + typedef value_holder<__VA_ARGS__> Holder; \ + typedef objects::instance<Holder> instance_t; \ + \ + template <class Arg> \ + static inline PyObject* execute(Arg & x) \ + { \ + BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >)); \ + \ + PyTypeObject* type = Derived::get_class_object(x); \ + \ + if (type == 0) \ + return python::detail::none(); \ + \ + PyObject* raw_result = type->tp_alloc(type, objects::additional_instance_size<Holder>::value); \ + if (raw_result != 0) \ + { \ + python::detail::decref_guard protect(raw_result); \ + instance_t* instance = (instance_t*)(void*)raw_result; \ + Holder* holder = Derived::construct(&instance->storage, (PyObject*)instance, x); \ + holder->install(raw_result); \ + \ + size_t holder_offset = reinterpret_cast<size_t>(holder) \ + - reinterpret_cast<size_t>(&instance->storage) \ + + offsetof(instance_t, storage); \ + Py_SIZE(instance) = holder_offset; \ + \ + protect.cancel(); \ + } \ + return raw_result; \ + } \ + }; \ + \ + template<> \ + struct make_instance<__VA_ARGS__, value_holder<__VA_ARGS__> > \ + : make_instance_impl<__VA_ARGS__, value_holder<__VA_ARGS__>, make_instance<__VA_ARGS__,value_holder<__VA_ARGS__> > > \ + { \ + template <class U> \ + static inline PyTypeObject* get_class_object(U &) \ + { \ + return converter::registered<__VA_ARGS__>::converters.get_class_object(); \ + } \ + \ + static inline value_holder<__VA_ARGS__>* construct(void* storage, PyObject* instance, reference_wrapper<__VA_ARGS__ const> x) \ + { \ + void* aligned_storage = reinterpret_cast<void*>((reinterpret_cast<size_t>(storage) & ~(size_t(15))) + 16); \ + value_holder<__VA_ARGS__>* new_holder = new (aligned_storage) value_holder<__VA_ARGS__>(instance, x); \ + return new_holder; \ + } \ + }; \ + }}} + +#endif // __eigenpy_memory_hpp__