mirror of
https://github.com/boostorg/interprocess.git
synced 2026-01-19 04:12:13 +00:00
offset_ptr improvements:
- Use simplier traits to reduce dependencies and add support for nullptr - Add tests cover construction/assignment from literal zero and nullptr
This commit is contained in:
@@ -21,11 +21,7 @@
|
||||
|
||||
#include <boost/interprocess/detail/config_begin.hpp>
|
||||
#include <boost/interprocess/detail/workaround.hpp>
|
||||
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_constructible.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/is_unsigned.hpp>
|
||||
#include <boost/move/detail/type_traits.hpp>
|
||||
|
||||
#include <boost/interprocess/interprocess_fwd.hpp>
|
||||
#include <boost/interprocess/detail/utilities.hpp>
|
||||
@@ -33,15 +29,14 @@
|
||||
#include <boost/interprocess/detail/mpl.hpp>
|
||||
#include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <iosfwd>
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
|
||||
//!\file
|
||||
//!Describes a smart pointer that stores the offset between this pointer and
|
||||
//!target pointee, called offset_ptr.
|
||||
@@ -59,15 +54,62 @@ struct has_trivial_destructor;
|
||||
namespace interprocess {
|
||||
|
||||
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
|
||||
|
||||
#if !defined( BOOST_NO_CXX11_NULLPTR )
|
||||
typedef decltype(nullptr) op_nullptr_t;
|
||||
#else
|
||||
struct op_nullptr_t
|
||||
{
|
||||
void* lx; //to achieve pointer alignment
|
||||
|
||||
struct nat {int bool_conversion;};
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE op_nullptr_t() {}
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE op_nullptr_t(int nat::*) {}
|
||||
|
||||
BOOST_INTERPROCESS_FORCEINLINE operator int nat::*() const { return 0; }
|
||||
|
||||
template <class T>
|
||||
BOOST_INTERPROCESS_FORCEINLINE operator T*() const { return 0; }
|
||||
|
||||
template <class T, class U>
|
||||
BOOST_INTERPROCESS_FORCEINLINE operator T U::* () const { return 0; }
|
||||
|
||||
friend BOOST_INTERPROCESS_FORCEINLINE bool operator==(op_nullptr_t, op_nullptr_t) { return true; }
|
||||
friend BOOST_INTERPROCESS_FORCEINLINE bool operator!=(op_nullptr_t, op_nullptr_t) { return false; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
namespace ipcdetail {
|
||||
|
||||
//workarounds for void offset_ptrs
|
||||
struct op_nat{};
|
||||
|
||||
template <class T> struct op_reference
|
||||
: add_reference<T>
|
||||
{};
|
||||
|
||||
template <> struct op_reference<void>
|
||||
{ typedef op_nat type; };
|
||||
|
||||
template <> struct op_reference<void const>
|
||||
{ typedef op_nat type; };
|
||||
|
||||
template <> struct op_reference<void volatile>
|
||||
{ typedef op_nat type; };
|
||||
|
||||
template <> struct op_reference<void const volatile>
|
||||
{ typedef op_nat type; };
|
||||
|
||||
template<class OffsetType, std::size_t OffsetAlignment>
|
||||
union offset_ptr_internal
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(OffsetType) >= sizeof(uintptr_t));
|
||||
BOOST_STATIC_ASSERT(boost::is_integral<OffsetType>::value && boost::is_unsigned<OffsetType>::value);
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT(sizeof(OffsetType) >= sizeof(uintptr_t));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT(boost::move_detail::is_integral<OffsetType>::value && boost::move_detail::is_unsigned<OffsetType>::value);
|
||||
|
||||
explicit offset_ptr_internal(OffsetType off)
|
||||
BOOST_INTERPROCESS_FORCEINLINE explicit offset_ptr_internal(OffsetType off)
|
||||
: m_offset(off)
|
||||
{}
|
||||
|
||||
@@ -196,14 +238,14 @@ namespace ipcdetail {
|
||||
|
||||
template<class From, class To, class Ret = void>
|
||||
struct enable_if_convertible_equal_address
|
||||
: enable_if_c< ::boost::is_convertible<From*, To*>::value
|
||||
: enable_if_c< ::boost::move_detail::is_convertible<From*, To*>::value
|
||||
&& offset_ptr_maintains_address<From, To>::value
|
||||
, Ret>
|
||||
{};
|
||||
|
||||
template<class From, class To, class Ret = void>
|
||||
struct enable_if_convertible_unequal_address
|
||||
: enable_if_c< ::boost::is_convertible<From*, To*>::value
|
||||
: enable_if_c< ::boost::move_detail::is_convertible<From*, To*>::value
|
||||
&& !offset_ptr_maintains_address<From, To>::value
|
||||
, Ret>
|
||||
{};
|
||||
@@ -245,7 +287,8 @@ class offset_ptr
|
||||
typedef PointedType element_type;
|
||||
typedef PointedType * pointer;
|
||||
typedef typename ipcdetail::
|
||||
add_reference<PointedType>::type reference;
|
||||
op_reference<PointedType>::type reference;
|
||||
|
||||
typedef typename ipcdetail::
|
||||
remove_volatile<typename ipcdetail::
|
||||
remove_const<PointedType>::type
|
||||
@@ -262,17 +305,25 @@ class offset_ptr
|
||||
: internal(1)
|
||||
{}
|
||||
|
||||
//!Constructor from raw pointer (allows "0" pointer conversion).
|
||||
//!Constructor from nullptr.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(pointer ptr) BOOST_NOEXCEPT
|
||||
: internal(ipcdetail::offset_ptr_to_offset<OffsetType>(ptr, this))
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(op_nullptr_t) BOOST_NOEXCEPT
|
||||
: internal(1)
|
||||
{}
|
||||
|
||||
#if defined( BOOST_NO_CXX11_NULLPTR )
|
||||
//!Constructor from nullptr. Some compilers (e.g. g++14) in C++03 mode have problems with op_nullptr_t
|
||||
//!so a helper overload is needed. Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(int ipcdetail::op_nat::*) BOOST_NOEXCEPT
|
||||
: internal(1)
|
||||
{}
|
||||
#endif //BOOST_NO_CXX11_NULLPTR
|
||||
|
||||
//!Constructor from other pointer.
|
||||
//!Never throws.
|
||||
template <class T>
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( T *ptr
|
||||
, typename ipcdetail::enable_if< ::boost::is_convertible<T*, PointedType*> >::type * = 0) BOOST_NOEXCEPT
|
||||
, typename ipcdetail::enable_if< ::boost::move_detail::is_convertible<T*, PointedType*> >::type * = 0) BOOST_NOEXCEPT
|
||||
: internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr), this))
|
||||
{}
|
||||
|
||||
@@ -303,19 +354,6 @@ class offset_ptr
|
||||
|
||||
#endif
|
||||
|
||||
//!Constructor from other offset_ptr. Only takes part in overload resolution
|
||||
//!if PointedType* is constructible from T2* other than via a conversion (e.g. cast to a derived class). Never throws.
|
||||
template<class T2>
|
||||
BOOST_INTERPROCESS_FORCEINLINE explicit offset_ptr(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
, typename ipcdetail::enable_if_c<
|
||||
!::boost::is_convertible<T2*, PointedType*>::value && ::boost::is_constructible<T2*, PointedType*>::value
|
||||
>::type * = 0
|
||||
#endif
|
||||
) BOOST_NOEXCEPT
|
||||
: internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr.get()), this))
|
||||
{}
|
||||
|
||||
//!Emulates static_cast operator.
|
||||
//!Never throws.
|
||||
template<class T2, class P2, class O2, std::size_t A2>
|
||||
@@ -359,7 +397,7 @@ class offset_ptr
|
||||
|
||||
//!Dereferencing operator, if it is a null offset_ptr behavior
|
||||
//! is undefined. Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE reference operator* () const BOOST_NOEXCEPT
|
||||
BOOST_INTERPROCESS_FORCEINLINE reference operator*() const BOOST_NOEXCEPT
|
||||
{
|
||||
pointer p = this->get();
|
||||
reference r = *p;
|
||||
@@ -371,14 +409,6 @@ class offset_ptr
|
||||
BOOST_INTERPROCESS_FORCEINLINE reference operator[](difference_type idx) const BOOST_NOEXCEPT
|
||||
{ return this->get()[idx]; }
|
||||
|
||||
//!Assignment from pointer (saves extra conversion).
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (pointer from) BOOST_NOEXCEPT
|
||||
{
|
||||
this->internal.m_offset = ipcdetail::offset_ptr_to_offset<OffsetType>(from, this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Assignment from other offset_ptr.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (const offset_ptr & ptr) BOOST_NOEXCEPT
|
||||
@@ -387,12 +417,30 @@ class offset_ptr
|
||||
return *this;
|
||||
}
|
||||
|
||||
//!Assignment from nullptr.
|
||||
//!Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (op_nullptr_t) BOOST_NOEXCEPT
|
||||
{
|
||||
this->internal.m_offset = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined( BOOST_NO_CXX11_NULLPTR )
|
||||
//!Assignment from nullptr. Some compilers (e.g. g++14) in C++03 mode have problems with op_nullptr_t
|
||||
//!so a helper overload is needed. Never throws.
|
||||
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (int ipcdetail::op_nat::*) BOOST_NOEXCEPT
|
||||
{
|
||||
this->internal.m_offset = 1;
|
||||
return *this;
|
||||
}
|
||||
#endif //BOOST_NO_CXX11_NULLPTR
|
||||
|
||||
//!Assignment from related offset_ptr. If pointers of pointee types
|
||||
//! are assignable, offset_ptrs will be assignable. Never throws.
|
||||
template<class T2> BOOST_INTERPROCESS_FORCEINLINE
|
||||
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
|
||||
typename ipcdetail::enable_if_c
|
||||
< ::boost::is_convertible<T2*, PointedType*>::value, offset_ptr&>::type
|
||||
< ::boost::move_detail::is_convertible<T2*, PointedType*>::value, offset_ptr&>::type
|
||||
#else
|
||||
offset_ptr&
|
||||
#endif
|
||||
@@ -473,7 +521,7 @@ class offset_ptr
|
||||
|
||||
//!Compatibility with pointer_traits
|
||||
//!
|
||||
BOOST_INTERPROCESS_FORCEINLINE static offset_ptr pointer_to(reference r) BOOST_NOEXCEPT
|
||||
BOOST_INTERPROCESS_FORCEINLINE static offset_ptr pointer_to(typename ipcdetail::op_reference<PointedType>::type r) BOOST_NOEXCEPT
|
||||
{ return offset_ptr(&r); }
|
||||
|
||||
//!difference_type + offset_ptr
|
||||
@@ -714,7 +762,7 @@ struct pointer_plus_bits<boost::interprocess::offset_ptr<T, P, O, A>, NumBits>
|
||||
//Bits are stored in the lower bits of the pointer except the LSB,
|
||||
//because this bit is used to represent the null pointer.
|
||||
static const O Mask = ((static_cast<O>(1) << NumBits) - static_cast<O>(1)) << 1;
|
||||
BOOST_STATIC_ASSERT(0 ==(Mask&1));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT(0 ==(Mask&1));
|
||||
|
||||
//We must ALWAYS take argument "n" by reference as a copy of a null pointer
|
||||
//with a bit (e.g. offset == 3) would be incorrectly copied and interpreted as non-null.
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <boost/interprocess/offset_ptr.hpp>
|
||||
#include <boost/interprocess/detail/type_traits.hpp>
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
using namespace boost::interprocess;
|
||||
@@ -34,15 +33,15 @@ void test_types_and_conversions()
|
||||
typedef offset_ptr<volatile int> pvint_t;
|
||||
typedef offset_ptr<const volatile int> pcvint_t;
|
||||
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pint_t::element_type, int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pcint_t::element_type, const int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pvint_t::element_type, volatile int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pcvint_t::element_type, const volatile int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pint_t::element_type, int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pcint_t::element_type, const int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pvint_t::element_type, volatile int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pcvint_t::element_type, const volatile int>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pint_t::value_type, int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pcint_t::value_type, int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pvint_t::value_type, int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<pcvint_t::value_type, int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pint_t::value_type, int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pcint_t::value_type, int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pvint_t::value_type, int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<pcvint_t::value_type, int>::value));
|
||||
int dummy_int = 9;
|
||||
|
||||
{ pint_t pint(&dummy_int);
|
||||
@@ -71,6 +70,39 @@ void test_types_and_conversions()
|
||||
pvint_t pvint(0);
|
||||
pcvint_t pcvint(0);
|
||||
|
||||
{
|
||||
pint_t pint2 = 0;
|
||||
pcint_t pcint2 = 0;
|
||||
pvint_t pvint2 = 0;
|
||||
pcvint_t pcvint2 = 0;
|
||||
(void)pint2;
|
||||
(void)pcint2;
|
||||
(void)pvint2;
|
||||
(void)pcvint2;
|
||||
}
|
||||
|
||||
{
|
||||
pint_t pint2 = op_nullptr_t();
|
||||
pcint_t pcint2 = op_nullptr_t();
|
||||
pvint_t pvint2 = op_nullptr_t();
|
||||
pcvint_t pcvint2 = op_nullptr_t();
|
||||
(void)pint2;
|
||||
(void)pcint2;
|
||||
(void)pvint2;
|
||||
(void)pcvint2;
|
||||
}
|
||||
|
||||
{
|
||||
pint_t pint2((op_nullptr_t()));
|
||||
pcint_t pcint2((op_nullptr_t()));
|
||||
pvint_t pvint2((op_nullptr_t()));
|
||||
pcvint_t pcvint2((op_nullptr_t()));
|
||||
(void)pint2;
|
||||
(void)pcint2;
|
||||
(void)pvint2;
|
||||
(void)pcvint2;
|
||||
}
|
||||
|
||||
pint = &dummy_int;
|
||||
pcint = &dummy_int;
|
||||
pvint = &dummy_int;
|
||||
@@ -108,6 +140,47 @@ void test_types_and_conversions()
|
||||
|
||||
BOOST_TEST( (pcint - pint) == 0);
|
||||
BOOST_TEST( (pint - pcint) == 0);
|
||||
|
||||
typedef offset_ptr<void> pvoid_t;
|
||||
typedef offset_ptr<const void> pcvoid_t;
|
||||
typedef offset_ptr<volatile void> pvvoid_t;
|
||||
typedef offset_ptr<const volatile void> pcvvoid_t;
|
||||
{
|
||||
pvoid_t pvoid = pint;
|
||||
pcvoid_t pcvoid = pcint;
|
||||
pvvoid_t pvvoid = pvint;
|
||||
pcvvoid_t pcvvoid = pcvint;
|
||||
(void)pvoid;
|
||||
(void)pcvoid;
|
||||
(void)pvvoid;
|
||||
(void)pcvvoid;
|
||||
}
|
||||
{
|
||||
pvoid_t pvoid(pint);
|
||||
pcvoid_t pcvoid(pcint);
|
||||
pvvoid_t pvvoid(pvint);
|
||||
pcvvoid_t pcvvoid(pcvint);
|
||||
(void)pvoid;
|
||||
(void)pcvoid;
|
||||
(void)pvvoid;
|
||||
(void)pcvvoid;
|
||||
}
|
||||
{
|
||||
pvoid_t pvoid;
|
||||
pcvoid_t pcvoid;
|
||||
pvvoid_t pvvoid;
|
||||
pcvvoid_t pcvvoid;
|
||||
|
||||
pvoid = pint;
|
||||
pcvoid = pcint;
|
||||
pvvoid = pvint;
|
||||
pcvvoid = pcvint;
|
||||
|
||||
(void)pvoid;
|
||||
(void)pcvoid;
|
||||
(void)pvvoid;
|
||||
(void)pcvvoid;
|
||||
}
|
||||
}
|
||||
|
||||
template<class BasePtr, class DerivedPtr>
|
||||
@@ -116,6 +189,8 @@ void test_base_derived_impl()
|
||||
typename DerivedPtr::element_type d;
|
||||
DerivedPtr pderi(&d);
|
||||
|
||||
{ BasePtr pbase2 = pderi; (void)pbase2; }
|
||||
|
||||
BasePtr pbase(pderi);
|
||||
pbase = pderi;
|
||||
BOOST_TEST(pbase == pderi);
|
||||
@@ -234,10 +309,10 @@ bool test_pointer_traits()
|
||||
{
|
||||
typedef offset_ptr<int> OInt;
|
||||
typedef boost::intrusive::pointer_traits< OInt > PTOInt;
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::element_type, int>::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::pointer, OInt >::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::difference_type, OInt::difference_type >::value));
|
||||
BOOST_STATIC_ASSERT((ipcdetail::is_same<PTOInt::rebind_pointer<double>::type, offset_ptr<double> >::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<PTOInt::element_type, int>::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<PTOInt::pointer, OInt >::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<PTOInt::difference_type, OInt::difference_type >::value));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((ipcdetail::is_same<PTOInt::rebind_pointer<double>::type, offset_ptr<double> >::value));
|
||||
int dummy;
|
||||
OInt oi(&dummy);
|
||||
if(boost::intrusive::pointer_traits<OInt>::pointer_to(dummy) != oi){
|
||||
@@ -253,7 +328,7 @@ struct node
|
||||
|
||||
void test_pointer_plus_bits()
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::intrusive::max_pointer_plus_bits< offset_ptr<void>, boost::move_detail::alignment_of<node>::value >::value >= 1U));
|
||||
BOOST_INTERPROCESS_STATIC_ASSERT((boost::intrusive::max_pointer_plus_bits< offset_ptr<void>, boost::move_detail::alignment_of<node>::value >::value >= 1U));
|
||||
typedef boost::intrusive::pointer_plus_bits< offset_ptr<node>, 1u > ptr_plus_bits;
|
||||
|
||||
node n, n2;
|
||||
|
||||
Reference in New Issue
Block a user