5
5
6
6
#include < boost/python/detail/prefix.hpp>
7
7
#include < boost/mpl/lambda.hpp> // #including this first is an intel6 workaround
8
+ #include < boost/cstdint.hpp>
8
9
9
10
#include < boost/python/object/class.hpp>
10
11
#include < boost/python/object/instance.hpp>
@@ -721,28 +722,47 @@ namespace objects
721
722
} // namespace objects
722
723
723
724
724
- void * instance_holder::allocate (PyObject* self_, std::size_t holder_offset, std::size_t holder_size)
725
+ typedef unsigned int alignment_marker_t ;
726
+
727
+ void * instance_holder::allocate (PyObject* self_, std::size_t holder_offset, std::size_t holder_size, std::size_t alignment)
725
728
{
726
729
assert (PyType_IsSubtype (Py_TYPE (Py_TYPE (self_)), &class_metatype_object));
727
730
objects::instance<>* self = (objects::instance<>*)self_;
728
731
729
- int total_size_needed = holder_offset + holder_size;
732
+ int total_size_needed = holder_offset + holder_size + alignment - 1 ;
730
733
731
734
if (-Py_SIZE (self) >= total_size_needed)
732
735
{
733
736
// holder_offset should at least point into the variable-sized part
734
737
assert (holder_offset >= offsetof (objects::instance<>,storage));
735
738
739
+ size_t allocated = holder_size + alignment;
740
+ void * storage = (char *)self + holder_offset;
741
+ void * aligned_storage = ::boost::alignment::align (alignment, holder_size, storage, allocated);
742
+
736
743
// Record the fact that the storage is occupied, noting where it starts
737
- Py_SET_SIZE (self, holder_offset);
738
- return (char *)self + holder_offset;
744
+ const size_t offset = reinterpret_cast <uintptr_t >(aligned_storage) - reinterpret_cast <uintptr_t >(storage) + holder_offset;
745
+ Py_SET_SIZE (self, offset);
746
+ return (char *)self + offset;
739
747
}
740
748
else
741
749
{
742
- void * const result = PyMem_Malloc (holder_size);
743
- if (result == 0 )
750
+ const size_t base_allocation = sizeof (alignment_marker_t ) + holder_size + alignment - 1 ;
751
+ void * const base_storage = PyMem_Malloc (base_allocation);
752
+ if (base_storage == 0 )
744
753
throw std::bad_alloc ();
745
- return result;
754
+
755
+ const uintptr_t x = reinterpret_cast <uintptr_t >(base_storage) + sizeof (alignment_marker_t );
756
+ // this has problems for x -> max(void *)
757
+ // const size_t padding = alignment - ((x + sizeof(alignment_marker_t)) % alignment);
758
+ // only works for alignments with alignments of powers of 2, but no edge conditions
759
+ const uintptr_t padding = alignment == 1 ? 0 : ( alignment - (x & (alignment - 1 )) );
760
+ const size_t aligned_offset = sizeof (alignment_marker_t ) + padding;
761
+ void * const aligned_storage = (char *)base_storage + aligned_offset;
762
+ BOOST_ASSERT ((char *) aligned_storage + holder_size <= (char *)base_storage + base_allocation);
763
+ alignment_marker_t * const marker_storage = reinterpret_cast <alignment_marker_t *>((char *)aligned_storage - sizeof (alignment_marker_t ));
764
+ *marker_storage = static_cast <alignment_marker_t >(padding);
765
+ return aligned_storage;
746
766
}
747
767
}
748
768
@@ -752,7 +772,9 @@ void instance_holder::deallocate(PyObject* self_, void* storage) throw()
752
772
objects::instance<>* self = (objects::instance<>*)self_;
753
773
if (storage != (char *)self + Py_SIZE (self))
754
774
{
755
- PyMem_Free (storage);
775
+ alignment_marker_t * marker_storage = reinterpret_cast <alignment_marker_t *>((char *)storage - sizeof (alignment_marker_t ));
776
+ void *malloced_storage = (char *) storage - sizeof (alignment_marker_t ) - (*marker_storage);
777
+ PyMem_Free (malloced_storage);
756
778
}
757
779
}
758
780
0 commit comments