1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP
12 #define BOOST_INTERPROCESS_OFFSET_PTR_HPP
13 
14 #ifndef BOOST_CONFIG_HPP
15 #  include <boost/config.hpp>
16 #endif
17 #
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 #  pragma once
20 #endif
21 
22 #include <boost/interprocess/detail/config_begin.hpp>
23 #include <boost/interprocess/detail/workaround.hpp>
24 
25 #include <boost/type_traits/is_convertible.hpp>
26 #include <boost/type_traits/is_constructible.hpp>
27 #include <boost/type_traits/is_integral.hpp>
28 #include <boost/type_traits/is_unsigned.hpp>
29 
30 #include <boost/interprocess/interprocess_fwd.hpp>
31 #include <boost/interprocess/detail/utilities.hpp>
32 #include <boost/interprocess/detail/cast_tags.hpp>
33 #include <boost/interprocess/detail/mpl.hpp>
34 #include <boost/container/detail/type_traits.hpp>  //alignment_of, aligned_storage
35 #include <boost/assert.hpp>
36 #include <iosfwd>
37 
38 //!\file
39 //!Describes a smart pointer that stores the offset between this pointer and
40 //!target pointee, called offset_ptr.
41 
42 namespace boost {
43 
44 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
45 
46 //Predeclarations
47 template <class T>
48 struct has_trivial_destructor;
49 
50 #endif   //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
51 
52 namespace interprocess {
53 
54 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
55 namespace ipcdetail {
56 
57    template<class OffsetType, std::size_t OffsetAlignment>
58    union offset_ptr_internal
59    {
60       BOOST_STATIC_ASSERT(sizeof(OffsetType) >= sizeof(uintptr_t));
61       BOOST_STATIC_ASSERT(boost::is_integral<OffsetType>::value && boost::is_unsigned<OffsetType>::value);
62 
offset_ptr_internal(OffsetType off)63       explicit offset_ptr_internal(OffsetType off)
64          : m_offset(off)
65       {}
66 
67       OffsetType m_offset; //Distance between this object and pointee address
68 
69       typename ::boost::container::dtl::aligned_storage
70          < sizeof(OffsetType)//for offset_type_alignment m_offset will be enough
71          , (OffsetAlignment == offset_type_alignment) ? 1u : OffsetAlignment
72          >::type alignment_helper;
73    };
74 
75    //Note: using the address of a local variable to point to another address
76    //is not standard conforming and this can be optimized-away by the compiler.
77    //Non-inlining is a method to remain illegal but correct
78 
79    //Undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_XXX if your compiler can inline
80    //this code without breaking the library
81 
82    ////////////////////////////////////////////////////////////////////////
83    //
84    //                      offset_ptr_to_raw_pointer
85    //
86    ////////////////////////////////////////////////////////////////////////
87    #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
88    template <class OffsetType>
offset_ptr_to_raw_pointer(const volatile void * this_ptr,OffsetType offset)89    BOOST_INTERPROCESS_FORCEINLINE void * offset_ptr_to_raw_pointer(const volatile void *this_ptr, OffsetType offset)
90    {
91       typedef pointer_offset_caster<void*, OffsetType> caster_t;
92       #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
93          if(offset == 1){
94             return 0;
95          }
96          else{
97             return caster_t(caster_t(this_ptr).offset() + offset).pointer();
98          }
99       #else
100          OffsetType mask = offset == 1;
101          --mask;
102          OffsetType target_offset = caster_t(this_ptr).offset() + offset;
103          target_offset &= mask;
104          return caster_t(target_offset).pointer();
105       #endif
106    }
107 
108    ////////////////////////////////////////////////////////////////////////
109    //
110    //                      offset_ptr_to_offset
111    //
112    ////////////////////////////////////////////////////////////////////////
113    #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
114    template<class OffsetType>
offset_ptr_to_offset(const volatile void * ptr,const volatile void * this_ptr)115    BOOST_INTERPROCESS_FORCEINLINE OffsetType offset_ptr_to_offset(const volatile void *ptr, const volatile void *this_ptr)
116    {
117       typedef pointer_offset_caster<void*, OffsetType> caster_t;
118       #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
119          //offset == 1 && ptr != 0 is not legal for this pointer
120          if(!ptr){
121             return 1;
122          }
123          else{
124             OffsetType offset = caster_t(ptr).offset()- caster_t(this_ptr).offset();
125             BOOST_ASSERT(offset != 1);
126             return offset;
127          }
128       #else
129          //const OffsetType other = -OffsetType(ptr != 0);
130          //const OffsetType offset = (caster_t(ptr).offset() - caster_t(this_ptr).offset()) & other;
131          //return offset + OffsetType(!other);
132          //
133          OffsetType offset = caster_t(ptr).offset() - caster_t(this_ptr).offset();
134          --offset;
135          OffsetType mask = ptr == 0;
136          --mask;
137          offset &= mask;
138          return ++offset;
139       #endif
140    }
141 
142    ////////////////////////////////////////////////////////////////////////
143    //
144    //                      offset_ptr_to_offset_from_other
145    //
146    ////////////////////////////////////////////////////////////////////////
147    #define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
148    template<class OffsetType>
offset_ptr_to_offset_from_other(const volatile void * this_ptr,const volatile void * other_ptr,OffsetType other_offset)149    BOOST_INTERPROCESS_FORCEINLINE OffsetType offset_ptr_to_offset_from_other
150       (const volatile void *this_ptr, const volatile void *other_ptr, OffsetType other_offset)
151    {
152       typedef pointer_offset_caster<void*, OffsetType> caster_t;
153       #ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
154       if(other_offset == 1){
155          return 1;
156       }
157       else{
158          OffsetType offset = caster_t(other_ptr).offset() - caster_t(this_ptr).offset() + other_offset;
159          BOOST_ASSERT(offset != 1);
160          return offset;
161       }
162       #else
163       OffsetType mask = other_offset == 1;
164       --mask;
165       OffsetType offset = caster_t(other_ptr).offset() - caster_t(this_ptr).offset();
166       offset &= mask;
167       return offset + other_offset;
168 
169       //OffsetType mask = -OffsetType(other_offset != 1);
170       //OffsetType offset = caster_t(other_ptr).offset() - caster_t(this_ptr).offset();
171       //offset &= mask;
172       //return offset + other_offset;
173       #endif
174    }
175 
176    ////////////////////////////////////////////////////////////////////////
177    //
178    // Let's assume cast to void and cv cast don't change any target address
179    //
180    ////////////////////////////////////////////////////////////////////////
181    template<class From, class To>
182    struct offset_ptr_maintains_address
183    {
184       static const bool value =    ipcdetail::is_cv_same<From, To>::value
185                                 || ipcdetail::is_cv_same<void, To>::value
186                                 || ipcdetail::is_cv_same<char, To>::value
187                                 ;
188    };
189 
190    template<class From, class To, class Ret = void>
191    struct enable_if_convertible_equal_address
192       : enable_if_c< ::boost::is_convertible<From*, To*>::value
193                      && offset_ptr_maintains_address<From, To>::value
194                   , Ret>
195    {};
196 
197    template<class From, class To, class Ret = void>
198    struct enable_if_convertible_unequal_address
199       : enable_if_c< ::boost::is_convertible<From*, To*>::value
200                      && !offset_ptr_maintains_address<From, To>::value
201                    , Ret>
202    {};
203 
204 }  //namespace ipcdetail {
205 #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
206 
207 //!A smart pointer that stores the offset between between the pointer and the
208 //!the object it points. This allows offset allows special properties, since
209 //!the pointer is independent from the address of the pointee, if the
210 //!pointer and the pointee are still separated by the same offset. This feature
211 //!converts offset_ptr in a smart pointer that can be placed in shared memory and
212 //!memory mapped files mapped in different addresses in every process.
213 //!
214 //! \tparam PointedType The type of the pointee.
215 //! \tparam DifferenceType A signed integer type that can represent the arithmetic operations on the pointer
216 //! \tparam OffsetType An unsigned integer type that can represent the
217 //!   distance between two pointers reinterpret_cast-ed as unsigned integers. This type
218 //!   should be at least of the same size of std::uintptr_t. In some systems it's possible to communicate
219 //!   between 32 and 64 bit processes using 64 bit offsets.
220 //! \tparam OffsetAlignment Alignment of the OffsetType stored inside. In some systems might be necessary
221 //!   to align it to 64 bits in order to communicate 32 and 64 bit processes using 64 bit offsets.
222 //!
223 //!<b>Note</b>: offset_ptr uses implementation defined properties, present in most platforms, for
224 //!performance reasons:
225 //!   - Assumes that OffsetType representation of nullptr is (OffsetType)zero.
226 //!   - Assumes that incrementing a OffsetType obtained from a pointer is equivalent
227 //!     to incrementing the pointer and then converting it back to OffsetType.
228 template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment>
229 class offset_ptr
230 {
231    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
232    typedef offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment>   self_t;
unspecified_bool_type_func() const233    void unspecified_bool_type_func() const {}
234    typedef void (self_t::*unspecified_bool_type)() const;
235    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
236 
237    public:
238    typedef PointedType                       element_type;
239    typedef PointedType *                     pointer;
240    typedef typename ipcdetail::
241       add_reference<PointedType>::type       reference;
242    typedef typename ipcdetail::
243       remove_volatile<typename ipcdetail::
244          remove_const<PointedType>::type
245             >::type                          value_type;
246    typedef DifferenceType                    difference_type;
247    typedef std::random_access_iterator_tag   iterator_category;
248    typedef OffsetType                        offset_type;
249 
250    public:   //Public Functions
251 
252    //!Default constructor (null pointer).
253    //!Never throws.
offset_ptr()254    BOOST_INTERPROCESS_FORCEINLINE offset_ptr() BOOST_NOEXCEPT
255       : internal(1)
256    {}
257 
258    //!Constructor from raw pointer (allows "0" pointer conversion).
259    //!Never throws.
offset_ptr(pointer ptr)260    BOOST_INTERPROCESS_FORCEINLINE offset_ptr(pointer ptr) BOOST_NOEXCEPT
261       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(ptr, this))
262    {}
263 
264    //!Constructor from other pointer.
265    //!Never throws.
266    template <class T>
offset_ptr(T * ptr,typename ipcdetail::enable_if<::boost::is_convertible<T *,PointedType * >>::type * =0)267    BOOST_INTERPROCESS_FORCEINLINE offset_ptr( T *ptr
268              , typename ipcdetail::enable_if< ::boost::is_convertible<T*, PointedType*> >::type * = 0) BOOST_NOEXCEPT
269       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr), this))
270    {}
271 
272    //!Constructor from other offset_ptr
273    //!Never throws.
offset_ptr(const offset_ptr & ptr)274    BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr& ptr) BOOST_NOEXCEPT
275       : internal(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset))
276    {}
277 
278    //!Constructor from other offset_ptr. Only takes part in overload resolution
279    //!if T2* is convertible to PointedType*. Never throws.
280    template<class T2>
offset_ptr(const offset_ptr<T2,DifferenceType,OffsetType,OffsetAlignment> & ptr,typename ipcdetail::enable_if_convertible_equal_address<T2,PointedType>::type * =0)281    BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
282              #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
283              , typename ipcdetail::enable_if_convertible_equal_address<T2, PointedType>::type* = 0
284              #endif
285              ) BOOST_NOEXCEPT
286       : internal(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset()))
287    {}
288 
289    #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
290 
291    template<class T2>
offset_ptr(const offset_ptr<T2,DifferenceType,OffsetType,OffsetAlignment> & ptr,typename ipcdetail::enable_if_convertible_unequal_address<T2,PointedType>::type * =0)292    BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
293              , typename ipcdetail::enable_if_convertible_unequal_address<T2, PointedType>::type* = 0) BOOST_NOEXCEPT
294       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr.get()), this))
295    {}
296 
297    #endif
298 
299    //!Constructor from other offset_ptr. Only takes part in overload resolution
300    //!if PointedType* is constructible from T2* other than via a conversion (e.g. cast to a derived class). Never throws.
301    template<class T2>
offset_ptr(const offset_ptr<T2,DifferenceType,OffsetType,OffsetAlignment> & ptr,typename ipcdetail::enable_if_c<!::boost::is_convertible<T2 *,PointedType * >::value &&::boost::is_constructible<T2 *,PointedType * >::value>::type * =0)302    BOOST_INTERPROCESS_FORCEINLINE explicit offset_ptr(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
303              #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
304              , typename ipcdetail::enable_if_c<
305                 !::boost::is_convertible<T2*, PointedType*>::value && ::boost::is_constructible<T2*, PointedType*>::value
306              >::type * = 0
307              #endif
308              ) BOOST_NOEXCEPT
309       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr.get()), this))
310    {}
311 
312    //!Emulates static_cast operator.
313    //!Never throws.
314    template<class T2, class P2, class O2, std::size_t A2>
offset_ptr(const offset_ptr<T2,P2,O2,A2> & r,ipcdetail::static_cast_tag)315    BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::static_cast_tag) BOOST_NOEXCEPT
316       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(r.get()), this))
317    {}
318 
319    //!Emulates const_cast operator.
320    //!Never throws.
321    template<class T2, class P2, class O2, std::size_t A2>
offset_ptr(const offset_ptr<T2,P2,O2,A2> & r,ipcdetail::const_cast_tag)322    BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::const_cast_tag) BOOST_NOEXCEPT
323       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(const_cast<PointedType*>(r.get()), this))
324    {}
325 
326    //!Emulates dynamic_cast operator.
327    //!Never throws.
328    template<class T2, class P2, class O2, std::size_t A2>
offset_ptr(const offset_ptr<T2,P2,O2,A2> & r,ipcdetail::dynamic_cast_tag)329    BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::dynamic_cast_tag) BOOST_NOEXCEPT
330       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(dynamic_cast<PointedType*>(r.get()), this))
331    {}
332 
333    //!Emulates reinterpret_cast operator.
334    //!Never throws.
335    template<class T2, class P2, class O2, std::size_t A2>
offset_ptr(const offset_ptr<T2,P2,O2,A2> & r,ipcdetail::reinterpret_cast_tag)336    BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::reinterpret_cast_tag) BOOST_NOEXCEPT
337       : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(reinterpret_cast<PointedType*>(r.get()), this))
338    {}
339 
340    //!Obtains raw pointer from offset.
341    //!Never throws.
get() const342    BOOST_INTERPROCESS_FORCEINLINE pointer get() const BOOST_NOEXCEPT
343    {  return static_cast<pointer>(ipcdetail::offset_ptr_to_raw_pointer(this, this->internal.m_offset));   }
344 
get_offset() const345    BOOST_INTERPROCESS_FORCEINLINE offset_type get_offset() const BOOST_NOEXCEPT
346    {  return this->internal.m_offset;  }
347 
348    //!Pointer-like -> operator. It can return 0 pointer.
349    //!Never throws.
operator ->() const350    BOOST_INTERPROCESS_FORCEINLINE pointer operator->() const BOOST_NOEXCEPT
351    {  return this->get(); }
352 
353    //!Dereferencing operator, if it is a null offset_ptr behavior
354    //!   is undefined. Never throws.
operator *() const355    BOOST_INTERPROCESS_FORCEINLINE reference operator* () const BOOST_NOEXCEPT
356    {
357       pointer p = this->get();
358       reference r = *p;
359       return r;
360    }
361 
362    //!Indexing operator.
363    //!Never throws.
operator [](difference_type idx) const364    BOOST_INTERPROCESS_FORCEINLINE reference operator[](difference_type idx) const BOOST_NOEXCEPT
365    {  return this->get()[idx];  }
366 
367    //!Assignment from pointer (saves extra conversion).
368    //!Never throws.
operator =(pointer from)369    BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (pointer from) BOOST_NOEXCEPT
370    {
371       this->internal.m_offset = ipcdetail::offset_ptr_to_offset<OffsetType>(from, this);
372       return *this;
373    }
374 
375    //!Assignment from other offset_ptr.
376    //!Never throws.
operator =(const offset_ptr & ptr)377    BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (const offset_ptr & ptr) BOOST_NOEXCEPT
378    {
379       this->internal.m_offset = ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset);
380       return *this;
381    }
382 
383    //!Assignment from related offset_ptr. If pointers of pointee types
384    //!   are assignable, offset_ptrs will be assignable. Never throws.
385    template<class T2> BOOST_INTERPROCESS_FORCEINLINE
386    #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
387    typename ipcdetail::enable_if_c
388       < ::boost::is_convertible<T2*, PointedType*>::value, offset_ptr&>::type
389    #else
390    offset_ptr&
391    #endif
operator =(const offset_ptr<T2,DifferenceType,OffsetType,OffsetAlignment> & ptr)392       operator= (const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr) BOOST_NOEXCEPT
393    {
394       this->assign(ptr, ipcdetail::bool_<ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value>());
395       return *this;
396    }
397 
398    public:
399 
400    //!offset_ptr += difference_type.
401    //!Never throws.
operator +=(difference_type offset)402    BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator+= (difference_type offset) BOOST_NOEXCEPT
403    {  this->inc_offset(offset * sizeof (PointedType));   return *this;  }
404 
405    //!offset_ptr -= difference_type.
406    //!Never throws.
operator -=(difference_type offset)407    BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator-= (difference_type offset) BOOST_NOEXCEPT
408    {  this->dec_offset(offset * sizeof (PointedType));   return *this;  }
409 
410    //!++offset_ptr.
411    //!Never throws.
operator ++(void)412    BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator++ (void) BOOST_NOEXCEPT
413    {  this->inc_offset(sizeof (PointedType));   return *this;  }
414 
415    //!offset_ptr++.
416    //!Never throws.
operator ++(int)417    BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator++ (int) BOOST_NOEXCEPT
418    {
419       offset_ptr tmp(*this);
420       this->inc_offset(sizeof (PointedType));
421       return tmp;
422    }
423 
424    //!--offset_ptr.
425    //!Never throws.
operator --(void)426    BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator-- (void) BOOST_NOEXCEPT
427    {  this->dec_offset(sizeof (PointedType));   return *this;  }
428 
429    //!offset_ptr--.
430    //!Never throws.
operator --(int)431    BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator-- (int) BOOST_NOEXCEPT
432    {
433       offset_ptr tmp(*this);
434       this->dec_offset(sizeof (PointedType));
435       return tmp;
436    }
437 
438    //!safe bool conversion operator.
439    //!Never throws.
440    #if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
operator unspecified_bool_type() const441    BOOST_INTERPROCESS_FORCEINLINE operator unspecified_bool_type() const BOOST_NOEXCEPT
442    {  return this->internal.m_offset != 1? &self_t::unspecified_bool_type_func : 0;   }
443    #else
operator bool() const444    explicit operator bool() const BOOST_NOEXCEPT
445    {  return this->internal.m_offset != 1;  }
446    #endif
447 
448    //!Not operator. Not needed in theory, but improves portability.
449    //!Never throws
operator !() const450    BOOST_INTERPROCESS_FORCEINLINE bool operator! () const BOOST_NOEXCEPT
451    {  return this->internal.m_offset == 1;   }
452 
453    //!Compatibility with pointer_traits
454    //!
455    #if defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
456    template <class U>
457    struct rebind
458    {  typedef offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment> other;  };
459    #else
460    template <class U>
461    using rebind = offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment>;
462    #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
463    typedef offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment> other;
464    #endif //BOOST_INTERPROCESS_DOXYGEN_INVOKED
465    #endif
466 
467    //!Compatibility with pointer_traits
468    //!
pointer_to(reference r)469    BOOST_INTERPROCESS_FORCEINLINE static offset_ptr pointer_to(reference r) BOOST_NOEXCEPT
470    { return offset_ptr(&r); }
471 
472    //!difference_type + offset_ptr
473    //!operation
operator +(difference_type diff,offset_ptr right)474    BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(difference_type diff, offset_ptr right) BOOST_NOEXCEPT
475    {  right += diff;  return right;  }
476 
477    //!offset_ptr + difference_type
478    //!operation
operator +(offset_ptr left,difference_type diff)479    BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(offset_ptr left, difference_type diff) BOOST_NOEXCEPT
480    {  left += diff;  return left; }
481 
482    //!offset_ptr - diff
483    //!operation
operator -(offset_ptr left,difference_type diff)484    BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(offset_ptr left, difference_type diff) BOOST_NOEXCEPT
485    {  left -= diff;  return left; }
486 
487    //!offset_ptr - diff
488    //!operation
operator -(difference_type diff,offset_ptr right)489    BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(difference_type diff, offset_ptr right) BOOST_NOEXCEPT
490    {  right -= diff; return right; }
491 
492    //!offset_ptr - offset_ptr
493    //!operation
operator -(const offset_ptr & pt,const offset_ptr & pt2)494    BOOST_INTERPROCESS_FORCEINLINE friend difference_type operator-(const offset_ptr &pt, const offset_ptr &pt2) BOOST_NOEXCEPT
495    {  return difference_type(pt.get()- pt2.get());   }
496 
497    //Comparison
operator ==(const offset_ptr & pt1,const offset_ptr & pt2)498    BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
499    {  return pt1.get() == pt2.get();  }
500 
operator !=(const offset_ptr & pt1,const offset_ptr & pt2)501    BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
502    {  return pt1.get() != pt2.get();  }
503 
operator <(const offset_ptr & pt1,const offset_ptr & pt2)504    BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
505    {  return pt1.get() < pt2.get();  }
506 
operator <=(const offset_ptr & pt1,const offset_ptr & pt2)507    BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
508    {  return pt1.get() <= pt2.get();  }
509 
operator >(const offset_ptr & pt1,const offset_ptr & pt2)510    BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
511    {  return pt1.get() > pt2.get();  }
512 
operator >=(const offset_ptr & pt1,const offset_ptr & pt2)513    BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
514    {  return pt1.get() >= pt2.get();  }
515 
516    //Comparison to raw ptr to support literal 0
operator ==(pointer pt1,const offset_ptr & pt2)517    BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
518    {  return pt1 == pt2.get();  }
519 
operator !=(pointer pt1,const offset_ptr & pt2)520    BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
521    {  return pt1 != pt2.get();  }
522 
operator <(pointer pt1,const offset_ptr & pt2)523    BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
524    {  return pt1 < pt2.get();  }
525 
operator <=(pointer pt1,const offset_ptr & pt2)526    BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
527    {  return pt1 <= pt2.get();  }
528 
operator >(pointer pt1,const offset_ptr & pt2)529    BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
530    {  return pt1 > pt2.get();  }
531 
operator >=(pointer pt1,const offset_ptr & pt2)532    BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
533    {  return pt1 >= pt2.get();  }
534 
535    //Comparison
operator ==(const offset_ptr & pt1,pointer pt2)536    BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
537    {  return pt1.get() == pt2;  }
538 
operator !=(const offset_ptr & pt1,pointer pt2)539    BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
540    {  return pt1.get() != pt2;  }
541 
operator <(const offset_ptr & pt1,pointer pt2)542    BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
543    {  return pt1.get() < pt2;  }
544 
operator <=(const offset_ptr & pt1,pointer pt2)545    BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
546    {  return pt1.get() <= pt2;  }
547 
operator >(const offset_ptr & pt1,pointer pt2)548    BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
549    {  return pt1.get() > pt2;  }
550 
operator >=(const offset_ptr & pt1,pointer pt2)551    BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
552    {  return pt1.get() >= pt2;  }
553 
swap(offset_ptr & left,offset_ptr & right)554    BOOST_INTERPROCESS_FORCEINLINE friend void swap(offset_ptr &left, offset_ptr &right) BOOST_NOEXCEPT
555    {
556       pointer ptr = right.get();
557       right = left;
558       left = ptr;
559    }
560 
561    private:
562    template<class T2>
assign(const offset_ptr<T2,DifferenceType,OffsetType,OffsetAlignment> & ptr,ipcdetail::bool_<true>)563    BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr, ipcdetail::bool_<true>) BOOST_NOEXCEPT
564    {  //no need to pointer adjustment
565       this->internal.m_offset = ipcdetail::offset_ptr_to_offset_from_other<OffsetType>(this, &ptr, ptr.get_offset());
566    }
567 
568    template<class T2>
assign(const offset_ptr<T2,DifferenceType,OffsetType,OffsetAlignment> & ptr,ipcdetail::bool_<false>)569    BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr, ipcdetail::bool_<false>) BOOST_NOEXCEPT
570    {  //we must convert to raw before calculating the offset
571       this->internal.m_offset = ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr.get()), this);
572    }
573 
574    #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inc_offset(DifferenceType bytes)575    BOOST_INTERPROCESS_FORCEINLINE void inc_offset(DifferenceType bytes) BOOST_NOEXCEPT
576    {  internal.m_offset += bytes;   }
577 
dec_offset(DifferenceType bytes)578    BOOST_INTERPROCESS_FORCEINLINE void dec_offset(DifferenceType bytes) BOOST_NOEXCEPT
579    {  internal.m_offset -= bytes;   }
580 
581    ipcdetail::offset_ptr_internal<OffsetType, OffsetAlignment> internal;
582 
583    public:
priv_offset() const584    BOOST_INTERPROCESS_FORCEINLINE const OffsetType &priv_offset() const BOOST_NOEXCEPT
585    {  return internal.m_offset;   }
586 
priv_offset()587    BOOST_INTERPROCESS_FORCEINLINE       OffsetType &priv_offset() BOOST_NOEXCEPT
588    {  return internal.m_offset;   }
589 
590    #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
591 };
592 
593 //!operator<<
594 //!for offset ptr
595 template<class E, class T, class W, class X, class Y, std::size_t Z>
operator <<(std::basic_ostream<E,T> & os,offset_ptr<W,X,Y,Z> const & p)596 inline std::basic_ostream<E, T> & operator<<
597    (std::basic_ostream<E, T> & os, offset_ptr<W, X, Y, Z> const & p)
598 {  return os << p.get_offset();   }
599 
600 //!operator>>
601 //!for offset ptr
602 template<class E, class T, class W, class X, class Y, std::size_t Z>
operator >>(std::basic_istream<E,T> & is,offset_ptr<W,X,Y,Z> & p)603 inline std::basic_istream<E, T> & operator>>
604    (std::basic_istream<E, T> & is, offset_ptr<W, X, Y, Z> & p)
605 {  return is >> p.get_offset();  }
606 
607 //!Simulation of static_cast between pointers. Never throws.
608 template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
609 BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
static_pointer_cast(const boost::interprocess::offset_ptr<T2,P2,O2,A2> & r)610    static_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
611 {
612    return boost::interprocess::offset_ptr<T1, P1, O1, A1>
613             (r, boost::interprocess::ipcdetail::static_cast_tag());
614 }
615 
616 //!Simulation of const_cast between pointers. Never throws.
617 template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
618 BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
const_pointer_cast(const boost::interprocess::offset_ptr<T2,P2,O2,A2> & r)619    const_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
620 {
621    return boost::interprocess::offset_ptr<T1, P1, O1, A1>
622             (r, boost::interprocess::ipcdetail::const_cast_tag());
623 }
624 
625 //!Simulation of dynamic_cast between pointers. Never throws.
626 template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
627 BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
dynamic_pointer_cast(const boost::interprocess::offset_ptr<T2,P2,O2,A2> & r)628    dynamic_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
629 {
630    return boost::interprocess::offset_ptr<T1, P1, O1, A1>
631             (r, boost::interprocess::ipcdetail::dynamic_cast_tag());
632 }
633 
634 //!Simulation of reinterpret_cast between pointers. Never throws.
635 template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
636 BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
reinterpret_pointer_cast(const boost::interprocess::offset_ptr<T2,P2,O2,A2> & r)637    reinterpret_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
638 {
639    return boost::interprocess::offset_ptr<T1, P1, O1, A1>
640             (r, boost::interprocess::ipcdetail::reinterpret_cast_tag());
641 }
642 
643 }  //namespace interprocess {
644 
645 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
646 
647 ///has_trivial_destructor<> == true_type specialization for optimizations
648 template <class T, class P, class O, std::size_t A>
649 struct has_trivial_destructor< ::boost::interprocess::offset_ptr<T, P, O, A> >
650 {
651    static const bool value = true;
652 };
653 
654 namespace move_detail {
655 
656 ///has_trivial_destructor<> == true_type specialization for optimizations
657 template <class T, class P, class O, std::size_t A>
658 struct is_trivially_destructible< ::boost::interprocess::offset_ptr<T, P, O, A> >
659 {
660    static const bool value = true;
661 };
662 
663 }  //namespace move_detail {
664 
665 namespace interprocess {
666 
667 //!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr.
668 //!Never throws.
669 template <class T, class P, class O, std::size_t A>
to_raw_pointer(boost::interprocess::offset_ptr<T,P,O,A> const & p)670 BOOST_INTERPROCESS_FORCEINLINE T * to_raw_pointer(boost::interprocess::offset_ptr<T, P, O, A> const & p) BOOST_NOEXCEPT
671 {  return ipcdetail::to_raw_pointer(p);   }
672 
673 }  //namespace interprocess
674 
675 
676 #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
677 }  //namespace boost {
678 
679 #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
680 
681 namespace boost{
682 
683 //This is to support embedding a bit in the pointer
684 //for intrusive containers, saving space
685 namespace intrusive {
686 
687 //Predeclaration to avoid including header
688 template<class VoidPointer, std::size_t N>
689 struct max_pointer_plus_bits;
690 
691 template<std::size_t OffsetAlignment, class P, class O, std::size_t A>
692 struct max_pointer_plus_bits<boost::interprocess::offset_ptr<void, P, O, A>, OffsetAlignment>
693 {
694    //The offset ptr can embed one bit less than the alignment since it
695    //uses offset == 1 to store the null pointer.
696    static const std::size_t value = ::boost::interprocess::ipcdetail::ls_zeros<OffsetAlignment>::value - 1;
697 };
698 
699 //Predeclaration
700 template<class Pointer, std::size_t NumBits>
701 struct pointer_plus_bits;
702 
703 template<class T, class P, class O, std::size_t A, std::size_t NumBits>
704 struct pointer_plus_bits<boost::interprocess::offset_ptr<T, P, O, A>, NumBits>
705 {
706    typedef boost::interprocess::offset_ptr<T, P, O, A>      pointer;
707    //Bits are stored in the lower bits of the pointer except the LSB,
708    //because this bit is used to represent the null pointer.
709    static const O Mask = ((static_cast<O>(1) << NumBits) - static_cast<O>(1)) << 1;
710    BOOST_STATIC_ASSERT(0 ==(Mask&1));
711 
712    //We must ALWAYS take argument "n" by reference as a copy of a null pointer
713    //with a bit (e.g. offset == 3) would be incorrectly copied and interpreted as non-null.
714 
get_pointerboost::intrusive::pointer_plus_bits715    BOOST_INTERPROCESS_FORCEINLINE static pointer get_pointer(const pointer &n) BOOST_NOEXCEPT
716    {
717       pointer p;
718       O const tmp_off = n.priv_offset() & ~Mask;
719       p.priv_offset() = boost::interprocess::ipcdetail::offset_ptr_to_offset_from_other(&p, &n, tmp_off);
720       return p;
721    }
722 
set_pointerboost::intrusive::pointer_plus_bits723    BOOST_INTERPROCESS_FORCEINLINE static void set_pointer(pointer &n, const pointer &p) BOOST_NOEXCEPT
724    {
725       BOOST_ASSERT(0 == (get_bits)(p));
726       O const stored_bits = n.priv_offset() & Mask;
727       n = p;
728       n.priv_offset() |= stored_bits;
729    }
730 
get_bitsboost::intrusive::pointer_plus_bits731    BOOST_INTERPROCESS_FORCEINLINE static std::size_t get_bits(const pointer &n) BOOST_NOEXCEPT
732    {
733       return std::size_t((n.priv_offset() & Mask) >> 1u);
734    }
735 
set_bitsboost::intrusive::pointer_plus_bits736    BOOST_INTERPROCESS_FORCEINLINE static void set_bits(pointer &n, std::size_t const b) BOOST_NOEXCEPT
737    {
738       BOOST_ASSERT(b < (std::size_t(1) << NumBits));
739       O tmp = n.priv_offset();
740       tmp &= ~Mask;
741       tmp |= O(b << 1u);
742       n.priv_offset() = tmp;
743    }
744 };
745 
746 }  //namespace intrusive
747 
748 //Predeclaration
749 template<class T, class U>
750 struct pointer_to_other;
751 
752 //Backwards compatibility with pointer_to_other
753 template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment, class U>
754 struct pointer_to_other
755    < ::boost::interprocess::offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment>, U >
756 {
757    typedef ::boost::interprocess::offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment> type;
758 };
759 
760 }  //namespace boost{
761 #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
762 
763 #include <boost/interprocess/detail/config_end.hpp>
764 
765 #endif //#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP
766