Chris@16: ///////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // (C) Copyright Ion Gaztanaga 2007-2013 Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/intrusive for documentation. Chris@16: // Chris@16: ///////////////////////////////////////////////////////////////////////////// Chris@16: #ifndef BOOST_INTRUSIVE_DETAIL_PARENT_FROM_MEMBER_HPP Chris@16: #define BOOST_INTRUSIVE_DETAIL_PARENT_FROM_MEMBER_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@101: # pragma once Chris@101: #endif Chris@101: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #if defined(BOOST_MSVC) || ((defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && defined(BOOST_INTEL)) Chris@16: #define BOOST_INTRUSIVE_MSVC_ABI_PTR_TO_MEMBER Chris@16: #include Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: namespace intrusive { Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member) Chris@16: { Chris@16: //The implementation of a pointer to member is compiler dependent. Chris@16: #if defined(BOOST_INTRUSIVE_MSVC_ABI_PTR_TO_MEMBER) Chris@16: Chris@16: //MSVC compliant compilers use their the first 32 bits as offset (even in 64 bit mode) Chris@16: union caster_union Chris@16: { Chris@16: const Member Parent::* ptr_to_member; Chris@101: int offset; Chris@16: } caster; Chris@16: Chris@16: //MSVC ABI can use up to 3 int32 to represent pointer to member data Chris@16: //with virtual base classes, in those cases there is no simple to Chris@16: //obtain the address of the parent. So static assert to avoid runtime errors Chris@101: BOOST_STATIC_ASSERT( sizeof(caster) == sizeof(int) ); Chris@16: Chris@16: caster.ptr_to_member = ptr_to_member; Chris@16: return std::ptrdiff_t(caster.offset); Chris@101: //Additional info on MSVC behaviour for the future. For 2/3 int ptr-to-member Chris@16: //types dereference seems to be: Chris@16: // Chris@16: // vboffset = [compile_time_offset if 2-int ptr2memb] / Chris@16: // [ptr2memb.i32[2] if 3-int ptr2memb]. Chris@16: // vbtable = *(this + vboffset); Chris@16: // adj = vbtable[ptr2memb.i32[1]]; Chris@16: // var = adj + (this + vboffset) + ptr2memb.i32[0]; Chris@16: // Chris@16: //To reverse the operation we need to Chris@16: // - obtain vboffset (in 2-int ptr2memb implementation only) Chris@16: // - Go to Parent's vbtable and obtain adjustment at index ptr2memb.i32[1] Chris@16: // - parent = member - adj - vboffset - ptr2memb.i32[0] Chris@16: // Chris@16: //Even accessing to RTTI we might not be able to obtain this information Chris@16: //so anyone who thinks it's possible, please send a patch. Chris@16: Chris@16: //This works with gcc, msvc, ac++, ibmcpp Chris@16: #elif defined(__GNUC__) || defined(__HP_aCC) || defined(BOOST_INTEL) || \ Chris@16: defined(__IBMCPP__) || defined(__DECCXX) Chris@16: const Parent * const parent = 0; Chris@16: const char *const member = static_cast(static_cast(&(parent->*ptr_to_member))); Chris@16: return std::ptrdiff_t(member - static_cast(static_cast(parent))); Chris@16: #else Chris@16: //This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC Chris@16: union caster_union Chris@16: { Chris@16: const Member Parent::* ptr_to_member; Chris@16: std::ptrdiff_t offset; Chris@16: } caster; Chris@16: caster.ptr_to_member = ptr_to_member; Chris@16: return caster.offset - 1; Chris@16: #endif Chris@16: } Chris@16: Chris@16: template Chris@16: inline Parent *parent_from_member(Member *member, const Member Parent::* ptr_to_member) Chris@16: { Chris@16: return static_cast Chris@16: ( Chris@16: static_cast Chris@16: ( Chris@16: static_cast(static_cast(member)) - offset_from_pointer_to_member(ptr_to_member) Chris@16: ) Chris@16: ); Chris@16: } Chris@16: Chris@16: template Chris@16: inline const Parent *parent_from_member(const Member *member, const Member Parent::* ptr_to_member) Chris@16: { Chris@16: return static_cast Chris@16: ( Chris@16: static_cast Chris@16: ( Chris@16: static_cast(static_cast(member)) - offset_from_pointer_to_member(ptr_to_member) Chris@16: ) Chris@16: ); Chris@16: } Chris@16: Chris@16: } //namespace detail { Chris@16: } //namespace intrusive { Chris@16: } //namespace boost { Chris@16: Chris@16: #ifdef BOOST_INTRUSIVE_MSVC_ABI_PTR_TO_MEMBER Chris@16: #undef BOOST_INTRUSIVE_MSVC_ABI_PTR_TO_MEMBER Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //#ifndef BOOST_INTRUSIVE_DETAIL_PARENT_FROM_MEMBER_HPP