diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 0045d06..28adc46 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -46,6 +46,8 @@ #include //for std::initializer_list #endif +#include //offsetof + namespace boost { namespace container { @@ -452,61 +454,65 @@ struct small_vector_storage_definer typedef small_vector_storage type; }; + +/// Figure out the offset of the first element. Idea taken from LLVM's SmallVector template -struct small_vector_storage_strawman - : public small_vector_base - , public small_vector_storage_definer::type +struct small_vector_storage_offset { - typedef typename small_vector_storage_definer::type sm_storage_t; + typedef small_vector_base base_type; + typedef typename small_vector_storage_definer::type storage_type; + typename dtl::aligned_storage + < sizeof(base_type), dtl::alignment_of::value + >::type base; + + typename dtl::aligned_storage + < sizeof(storage_type), dtl::alignment_of::value + > ::type storage; }; +template +inline std::size_t get_small_vector_storage_offset() +{ + typedef small_vector_storage_offset struct_type; + return offsetof(struct_type, storage); +} + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + //Internal storage hack template inline typename small_vector_allocator::const_pointer small_vector_allocator::internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW { - typedef small_vector_storage_strawman strawman_t; - typedef typename strawman_t::sm_storage_t sm_storage_t; - - //These warnings are false positives, as we know the alignment is correct - //and aligned storage is allowed to hold any type - #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - #pragma GCC diagnostic ignored "-Wstrict-aliasing" - #endif const vector_type& v = reinterpret_cast(*this); - BOOST_ASSERT((std::size_t(this) % dtl::alignment_of::value) == 0); - const strawman_t &straw = static_cast(v); - const sm_storage_t& stor = static_cast(straw); - return boost::intrusive::pointer_traits::pointer_to(*((const T*)stor.m_storage.data)); - #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) - #pragma GCC diagnostic pop - #endif + BOOST_ASSERT((std::size_t(this) % dtl::alignment_of< small_vector_storage_offset >::value) == 0); + const char *addr = reinterpret_cast(&v); + typedef typename boost::intrusive::pointer_traits::template rebind_pointer::type const_char_pointer; + const_void_pointer vptr = boost::intrusive::pointer_traits::pointer_to(*addr) + + get_small_vector_storage_offset(); + return boost::intrusive::pointer_traits::static_cast_from(vptr); } template inline typename small_vector_allocator::pointer small_vector_allocator::internal_storage() BOOST_NOEXCEPT_OR_NOTHROW { - typedef small_vector_storage_strawman strawman_t; - typedef typename strawman_t::sm_storage_t sm_storage_t; - - #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - #pragma GCC diagnostic ignored "-Wstrict-aliasing" - #endif vector_type& v = reinterpret_cast(*this); - BOOST_ASSERT((std::size_t(this) % dtl::alignment_of::value) == 0); - strawman_t &straw = static_cast(v); - sm_storage_t& stor = static_cast(straw); - return boost::intrusive::pointer_traits::pointer_to(*((T*)stor.m_storage.data)); - #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) - #pragma GCC diagnostic pop - #endif + BOOST_ASSERT((std::size_t(this) % dtl::alignment_of< small_vector_storage_offset >::value) == 0); + char* addr = reinterpret_cast(&v); + typedef typename boost::intrusive::pointer_traits::template rebind_pointer::type char_pointer; + void_pointer vptr = boost::intrusive::pointer_traits::pointer_to(*addr) + + get_small_vector_storage_offset(); + return boost::intrusive::pointer_traits::static_cast_from(vptr); } +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED