1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2005-2008. 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)
7 // See http://www.boost.org/libs/interprocess for documentation.
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_OFFSET_PTR_HPP
12 #define BOOST_OFFSET_PTR_HPP
14 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/interprocess/detail/config_begin.hpp>
19 #include <boost/interprocess/detail/workaround.hpp>
21 #include <boost/interprocess/interprocess_fwd.hpp>
22 #include <boost/interprocess/detail/utilities.hpp>
23 #include <boost/interprocess/detail/cast_tags.hpp>
24 #include <boost/interprocess/detail/mpl.hpp>
25 #include <boost/assert.hpp>
31 //!Describes a smart pointer that stores the offset between this pointer and
32 //!target pointee, called offset_ptr.
38 struct has_trivial_constructor
;
41 struct has_trivial_destructor
;
43 namespace interprocess
{
45 //!A smart pointer that stores the offset between between the pointer and the
46 //!the object it points. This allows offset allows special properties, since
47 //!the pointer is independent from the address address of the pointee, if the
48 //!pointer and the pointee are still separated by the same offset. This feature
49 //!converts offset_ptr in a smart pointer that can be placed in shared memory and
50 //!memory mapped files mapped in different addresses in every process.
51 template <class PointedType
>
55 typedef offset_ptr
<PointedType
> self_t
;
57 void unspecified_bool_type_func() const {}
58 typedef void (self_t::*unspecified_bool_type
)() const;
60 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
61 __declspec(noinline
) //this workaround is needed for msvc-8.0 and msvc-9.0
63 void set_offset(const volatile void *ptr
)
64 { set_offset(const_cast<const void*>(ptr
)); }
66 void set_offset(const void *ptr
)
68 const char *p
= static_cast<const char*>(ptr
);
69 //offset == 1 && ptr != 0 is not legal for this pointer
74 m_offset
= p
- reinterpret_cast<const char*>(this);
75 BOOST_ASSERT(m_offset
!= 1);
79 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
80 __declspec(noinline
) //this workaround is needed for msvc-8.0 and msvc-9.0
82 void* get_pointer() const
83 { return (m_offset
== 1) ? 0 : (const_cast<char*>(reinterpret_cast<const char*>(this)) + m_offset
); }
85 void inc_offset(std::ptrdiff_t bytes
)
86 { m_offset
+= bytes
; }
88 void dec_offset(std::ptrdiff_t bytes
)
89 { m_offset
-= bytes
; }
91 std::ptrdiff_t m_offset
; //Distance between this object and pointed address
95 typedef PointedType
* pointer
;
96 typedef typename
detail::
97 add_reference
<PointedType
>::type reference
;
98 typedef PointedType value_type
;
99 typedef std::ptrdiff_t difference_type
;
100 typedef std::random_access_iterator_tag iterator_category
;
102 public: //Public Functions
104 //!Constructor from raw pointer (allows "0" pointer conversion).
106 offset_ptr(pointer ptr
= 0) { this->set_offset(ptr
); }
108 //!Constructor from other pointer.
112 { pointer
p (ptr
); (void)p
; this->set_offset(p
); }
114 //!Constructor from other offset_ptr
116 offset_ptr(const offset_ptr
& ptr
)
117 { this->set_offset(ptr
.get()); }
119 //!Constructor from other offset_ptr. If pointers of pointee types are
120 //!convertible, offset_ptrs will be convertibles. Never throws.
122 offset_ptr(const offset_ptr
<T2
> &ptr
)
123 { pointer
p(ptr
.get()); (void)p
; this->set_offset(p
); }
125 //!Emulates static_cast operator.
128 offset_ptr(const offset_ptr
<Y
> & r
, detail::static_cast_tag
)
129 { this->set_offset(static_cast<PointedType
*>(r
.get())); }
131 //!Emulates const_cast operator.
134 offset_ptr(const offset_ptr
<Y
> & r
, detail::const_cast_tag
)
135 { this->set_offset(const_cast<PointedType
*>(r
.get())); }
137 //!Emulates dynamic_cast operator.
140 offset_ptr(const offset_ptr
<Y
> & r
, detail::dynamic_cast_tag
)
141 { this->set_offset(dynamic_cast<PointedType
*>(r
.get())); }
143 //!Emulates reinterpret_cast operator.
146 offset_ptr(const offset_ptr
<Y
> & r
, detail::reinterpret_cast_tag
)
147 { this->set_offset(reinterpret_cast<PointedType
*>(r
.get())); }
149 //!Obtains raw pointer from offset.
152 { return static_cast<pointer
>(this->get_pointer()); }
154 std::ptrdiff_t get_offset()
157 //!Pointer-like -> operator. It can return 0 pointer.
159 pointer
operator->() const
160 { return this->get(); }
162 //!Dereferencing operator, if it is a null offset_ptr behavior
163 //! is undefined. Never throws.
164 reference
operator* () const
166 pointer p
= this->get();
171 //!Indexing operator.
173 reference
operator[](std::ptrdiff_t idx
) const
174 { return this->get()[idx
]; }
176 //!Assignment from pointer (saves extra conversion).
178 offset_ptr
& operator= (pointer from
)
179 { this->set_offset(from
); return *this; }
181 //!Assignment from other offset_ptr.
183 offset_ptr
& operator= (const offset_ptr
& pt
)
184 { pointer
p(pt
.get()); (void)p
; this->set_offset(p
); return *this; }
186 //!Assignment from related offset_ptr. If pointers of pointee types
187 //! are assignable, offset_ptrs will be assignable. Never throws.
189 offset_ptr
& operator= (const offset_ptr
<T2
> & pt
)
190 { pointer
p(pt
.get()); this->set_offset(p
); return *this; }
192 //!offset_ptr + std::ptrdiff_t.
194 offset_ptr
operator+ (std::ptrdiff_t offset
) const
195 { return offset_ptr(this->get()+offset
); }
197 //!offset_ptr - std::ptrdiff_t.
199 offset_ptr
operator- (std::ptrdiff_t offset
) const
200 { return offset_ptr(this->get()-offset
); }
202 //!offset_ptr += std::ptrdiff_t.
204 offset_ptr
&operator+= (std::ptrdiff_t offset
)
205 { this->inc_offset(offset
* sizeof (PointedType
)); return *this; }
207 //!offset_ptr -= std::ptrdiff_t.
209 offset_ptr
&operator-= (std::ptrdiff_t offset
)
210 { this->dec_offset(offset
* sizeof (PointedType
)); return *this; }
214 offset_ptr
& operator++ (void)
215 { this->inc_offset(sizeof (PointedType
)); return *this; }
219 offset_ptr
operator++ (int)
220 { offset_ptr
temp(*this); ++*this; return temp
; }
224 offset_ptr
& operator-- (void)
225 { this->dec_offset(sizeof (PointedType
)); return *this; }
229 offset_ptr
operator-- (int)
230 { offset_ptr
temp(*this); --*this; return temp
; }
232 //!safe bool conversion operator.
234 operator unspecified_bool_type() const
235 { return this->get()? &self_t::unspecified_bool_type_func
: 0; }
237 //!Not operator. Not needed in theory, but improves portability.
239 bool operator! () const
240 { return this->get() == 0; }
242 friend void swap (offset_ptr &pt, offset_ptr &pt2)
244 value_type *ptr = pt.get();
251 //!offset_ptr<T1> == offset_ptr<T2>.
253 template<class T1
, class T2
>
254 inline bool operator== (const offset_ptr
<T1
> &pt1
,
255 const offset_ptr
<T2
> &pt2
)
256 { return pt1
.get() == pt2
.get(); }
258 //!offset_ptr<T1> != offset_ptr<T2>.
260 template<class T1
, class T2
>
261 inline bool operator!= (const offset_ptr
<T1
> &pt1
,
262 const offset_ptr
<T2
> &pt2
)
263 { return pt1
.get() != pt2
.get(); }
265 //!offset_ptr<T1> < offset_ptr<T2>.
267 template<class T1
, class T2
>
268 inline bool operator< (const offset_ptr
<T1
> &pt1
,
269 const offset_ptr
<T2
> &pt2
)
270 { return pt1
.get() < pt2
.get(); }
272 //!offset_ptr<T1> <= offset_ptr<T2>.
274 template<class T1
, class T2
>
275 inline bool operator<= (const offset_ptr
<T1
> &pt1
,
276 const offset_ptr
<T2
> &pt2
)
277 { return pt1
.get() <= pt2
.get(); }
279 //!offset_ptr<T1> > offset_ptr<T2>.
281 template<class T1
, class T2
>
282 inline bool operator> (const offset_ptr
<T1
> &pt1
,
283 const offset_ptr
<T2
> &pt2
)
284 { return pt1
.get() > pt2
.get(); }
286 //!offset_ptr<T1> >= offset_ptr<T2>.
288 template<class T1
, class T2
>
289 inline bool operator>= (const offset_ptr
<T1
> &pt1
,
290 const offset_ptr
<T2
> &pt2
)
291 { return pt1
.get() >= pt2
.get(); }
295 template<class E
, class T
, class Y
>
296 inline std::basic_ostream
<E
, T
> & operator<<
297 (std::basic_ostream
<E
, T
> & os
, offset_ptr
<Y
> const & p
)
298 { return os
<< p
.get_offset(); }
302 template<class E
, class T
, class Y
>
303 inline std::basic_istream
<E
, T
> & operator>>
304 (std::basic_istream
<E
, T
> & is
, offset_ptr
<Y
> & p
)
305 { return is
>> p
.get_offset(); }
307 //!std::ptrdiff_t + offset_ptr
310 inline offset_ptr
<T
> operator+(std::ptrdiff_t diff
, const offset_ptr
<T
>& right
)
311 { return right
+ diff
; }
313 //!offset_ptr - offset_ptr
315 template<class T
, class T2
>
316 inline std::ptrdiff_t operator- (const offset_ptr
<T
> &pt
, const offset_ptr
<T2
> &pt2
)
317 { return pt
.get()- pt2
.get(); }
319 //!swap specialization
322 inline void swap (boost::interprocess::offset_ptr
<T
> &pt
,
323 boost::interprocess::offset_ptr
<T
> &pt2
)
325 typename offset_ptr
<T
>::value_type
*ptr
= pt
.get();
330 //!Simulation of static_cast between pointers. Never throws.
331 template<class T
, class U
>
332 inline boost::interprocess::offset_ptr
<T
>
333 static_pointer_cast(boost::interprocess::offset_ptr
<U
> const & r
)
335 return boost::interprocess::offset_ptr
<T
>
336 (r
, boost::interprocess::detail::static_cast_tag());
339 //!Simulation of const_cast between pointers. Never throws.
340 template<class T
, class U
>
341 inline boost::interprocess::offset_ptr
<T
>
342 const_pointer_cast(boost::interprocess::offset_ptr
<U
> const & r
)
344 return boost::interprocess::offset_ptr
<T
>
345 (r
, boost::interprocess::detail::const_cast_tag());
348 //!Simulation of dynamic_cast between pointers. Never throws.
349 template<class T
, class U
>
350 inline boost::interprocess::offset_ptr
<T
>
351 dynamic_pointer_cast(boost::interprocess::offset_ptr
<U
> const & r
)
353 return boost::interprocess::offset_ptr
<T
>
354 (r
, boost::interprocess::detail::dynamic_cast_tag());
357 //!Simulation of reinterpret_cast between pointers. Never throws.
358 template<class T
, class U
>
359 inline boost::interprocess::offset_ptr
<T
>
360 reinterpret_pointer_cast(boost::interprocess::offset_ptr
<U
> const & r
)
362 return boost::interprocess::offset_ptr
<T
>
363 (r
, boost::interprocess::detail::reinterpret_cast_tag());
366 } //namespace interprocess {
370 //!has_trivial_constructor<> == true_type specialization for optimizations
372 struct has_trivial_constructor
< boost::interprocess::offset_ptr
<T
> >
374 enum { value
= true };
377 ///has_trivial_destructor<> == true_type specialization for optimizations
379 struct has_trivial_destructor
< boost::interprocess::offset_ptr
<T
> >
381 enum { value
= true };
384 //#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
385 namespace interprocess
{
387 //!get_pointer() enables boost::mem_fn to recognize offset_ptr.
390 inline T
* get_pointer(boost::interprocess::offset_ptr
<T
> const & p
)
392 //#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
393 } //namespace interprocess
397 } //namespace boost {
403 //This is to support embedding a bit in the pointer
404 //for intrusive containers, saving space
405 namespace intrusive
{
407 //Predeclaration to avoid including header
408 template<class VoidPointer
, std::size_t N
>
409 struct max_pointer_plus_bits
;
411 template<std::size_t Alignment
>
412 struct max_pointer_plus_bits
<boost::interprocess::offset_ptr
<void>, Alignment
>
414 //The offset ptr can embed one bit less than the alignment since it
415 //uses offset == 1 to store the null pointer.
416 static const std::size_t value
= ::boost::interprocess::detail::ls_zeros
<Alignment
>::value
- 1;
420 template<class Pointer
, std::size_t NumBits
>
421 struct pointer_plus_bits
;
423 template<class T
, std::size_t NumBits
>
424 struct pointer_plus_bits
<boost::interprocess::offset_ptr
<T
>, NumBits
>
426 typedef boost::interprocess::offset_ptr
<T
> pointer
;
427 //Bits are stored in the lower bits of the pointer except the LSB,
428 //because this bit is used to represent the null pointer.
429 static const std::size_t Mask
= ((std::size_t(1) << NumBits
)-1)<<1u;
431 static pointer
get_pointer(const pointer
&n
)
432 { return reinterpret_cast<T
*>(std::size_t(n
.get()) & ~std::size_t(Mask
)); }
434 static void set_pointer(pointer
&n
, pointer p
)
436 std::size_t pint
= std::size_t(p
.get());
437 assert(0 == (std::size_t(pint
) & Mask
));
438 n
= reinterpret_cast<T
*>(pint
| (std::size_t(n
.get()) & std::size_t(Mask
)));
441 static std::size_t get_bits(const pointer
&n
)
442 { return(std::size_t(n
.get()) & std::size_t(Mask
)) >> 1u; }
444 static void set_bits(pointer
&n
, std::size_t b
)
446 assert(b
< (std::size_t(1) << NumBits
));
447 n
= reinterpret_cast<T
*>(std::size_t(get_pointer(n
).get()) | (b
<< 1u));
451 } //namespace intrusive
455 #include <boost/interprocess/detail/config_end.hpp>
457 #endif //#ifndef BOOST_OFFSET_PTR_HPP