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