fix doc example typo
[boost.git] / boost / interprocess / detail / intersegment_ptr.hpp
blob1537fca700c90bac622222d4ed775ea62398b277
1 //////////////////////////////////////////////////////////////////////////////
2 //
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)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
12 #define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
14 #if (defined _MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif
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/math_functions.hpp>
24 #include <boost/interprocess/detail/cast_tags.hpp>
25 #include <boost/assert.hpp>
26 #include <boost/interprocess/sync/scoped_lock.hpp>
27 #include <boost/interprocess/sync/interprocess_mutex.hpp>
28 #include <boost/interprocess/containers/flat_map.hpp>
29 #include <boost/interprocess/containers/vector.hpp> //vector
30 #include <boost/interprocess/containers/set.hpp> //set
31 #include <boost/detail/no_exceptions_support.hpp>
32 #include <boost/interprocess/detail/mpl.hpp>
33 #include <climits>
34 #include <iterator>
35 #include <boost/static_assert.hpp> //BOOST_STATIC_ASSERT
36 #include <climits> //CHAR_BIT
37 #include <boost/integer/static_log2.hpp>
38 #include <cassert> //assert
39 #include <boost/interprocess/detail/multi_segment_services.hpp>
41 //!\file
42 //!
43 namespace boost {
45 //Predeclarations
46 template <class T>
47 struct has_trivial_constructor;
49 template <class T>
50 struct has_trivial_destructor;
52 namespace interprocess {
54 template <class T>
55 struct is_multisegment_ptr;
57 struct intersegment_base
59 typedef intersegment_base self_t;
60 BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*)));
61 BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64));
62 static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64;
63 static const std::size_t ctrl_bits = 2;
64 static const std::size_t align_bits = 12;
65 static const std::size_t align = std::size_t(1) << align_bits;
66 static const std::size_t max_segment_size_bits = size_t_bits - 2;
67 static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits;
69 static const std::size_t begin_bits = max_segment_size_bits - align_bits;
70 static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value;
71 static const std::size_t pow_size_bits =
72 (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ?
73 pow_size_bits_helper : pow_size_bits_helper + 1;
74 static const std::size_t frc_size_bits =
75 size_t_bits - ctrl_bits - begin_bits - pow_size_bits;
77 BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits ));
79 static const std::size_t relative_size_bits =
80 size_t_bits - max_segment_size_bits - ctrl_bits;
82 static const std::size_t is_pointee_outside = 0;
83 static const std::size_t is_in_stack = 1;
84 static const std::size_t is_relative = 2;
85 static const std::size_t is_segmented = 3;
86 static const std::size_t is_max_mode = 4;
88 intersegment_base()
90 this->set_mode(is_pointee_outside);
91 this->set_null();
94 struct relative_addressing
96 std::size_t ctrl : 2;
97 std::size_t pow : pow_size_bits;
98 std::size_t frc : frc_size_bits;
99 std::size_t beg : begin_bits;
100 std::ptrdiff_t off : sizeof(ptrdiff_t)*CHAR_BIT - 2;
101 std::ptrdiff_t bits : 2;
104 struct direct_addressing
106 std::size_t ctrl : 2;
107 std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2;
108 void * addr;
111 struct segmented_addressing
113 std::size_t ctrl : 2;
114 std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2;
115 std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2;
116 std::size_t bits : 2;
119 union members_t{
120 relative_addressing relative;
121 direct_addressing direct;
122 segmented_addressing segmented;
123 } members;
125 BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t));
127 void *relative_calculate_begin_addr() const
129 const std::size_t mask = ~(align - 1);
130 std::size_t beg = this->members.relative.beg;
131 return reinterpret_cast<void*>((((std::size_t)this) & mask) - (beg << align_bits));
134 void relative_set_begin_from_base(void *addr)
136 assert(addr < static_cast<void*>(this));
137 std::size_t off = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(addr);
138 members.relative.beg = off >> align_bits;
141 //!Obtains the address pointed by the
142 //!object
143 std::size_t relative_size() const
145 std::size_t pow = members.relative.pow;
146 std::size_t size = (std::size_t(1u) << pow);
147 assert(pow >= frc_size_bits);
148 size |= members.relative.frc << (pow - frc_size_bits);
149 return size;
152 static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc)
154 if(orig_size < align)
155 orig_size = align;
156 orig_size = detail::get_rounded_size_po2(orig_size, align);
157 pow = detail::floor_log2(orig_size);
158 std::size_t low_size = (std::size_t(1) << pow);
159 std::size_t diff = orig_size - low_size;
160 assert(pow >= frc_size_bits);
161 std::size_t rounded = detail::get_rounded_size_po2
162 (diff, (1u << (pow - frc_size_bits)));
163 if(rounded == low_size){
164 ++pow;
165 frc = 0;
166 rounded = 0;
168 else{
169 frc = rounded >> (pow - frc_size_bits);
171 assert(((frc << (pow - frc_size_bits)) & (align-1))==0);
172 return low_size + rounded;
175 std::size_t get_mode()const
176 { return members.direct.ctrl; }
178 void set_mode(std::size_t mode)
180 assert(mode < is_max_mode);
181 members.direct.ctrl = mode;
184 //!Returns true if object represents
185 //!null pointer
186 bool is_null() const
188 return (this->get_mode() < is_relative) &&
189 !members.direct.dummy &&
190 !members.direct.addr;
193 //!Sets the object to represent
194 //!the null pointer
195 void set_null()
197 if(this->get_mode() >= is_relative){
198 this->set_mode(is_pointee_outside);
200 members.direct.dummy = 0;
201 members.direct.addr = 0;
204 static std::size_t round_size(std::size_t orig_size)
206 std::size_t pow, frc;
207 return calculate_size(orig_size, pow, frc);
213 //!Configures intersegment_ptr with the capability to address:
214 //!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups
215 //!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group.
216 //!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment.
217 //!The mapping is implemented through flat_maps synchronized with mutexes.
218 template <class Mutex>
219 struct flat_map_intersegment
220 : public intersegment_base
222 typedef flat_map_intersegment<Mutex> self_t;
224 void set_from_pointer(const volatile void *ptr)
225 { this->set_from_pointer(const_cast<const void *>(ptr)); }
227 //!Obtains the address pointed
228 //!by the object
229 void *get_pointer() const
231 if(is_null()){
232 return 0;
234 switch(this->get_mode()){
235 case is_relative:
236 return const_cast<char*>(reinterpret_cast<const char*>(this)) + members.relative.off;
237 break;
238 case is_segmented:
240 segment_info_t segment_info;
241 std::size_t offset;
242 void *this_base;
243 get_segment_info_and_offset(this, segment_info, offset, this_base);
244 char *base = static_cast<char*>(segment_info.group->address_of(this->members.segmented.segment));
245 return base + this->members.segmented.off;
247 break;
248 case is_in_stack:
249 case is_pointee_outside:
250 return members.direct.addr;
251 break;
252 default:
253 return 0;
254 break;
258 //!Calculates the distance between two basic_intersegment_ptr-s.
259 //!This only works with two basic_intersegment_ptr pointing
260 //!to the same segment. Otherwise undefined
261 std::ptrdiff_t diff(const self_t &other) const
262 { return static_cast<char*>(this->get_pointer()) - static_cast<char*>(other.get_pointer()); }
264 //!Returns true if both point to
265 //!the same object
266 bool equal(const self_t &y) const
267 { return this->get_pointer() == y.get_pointer(); }
269 //!Returns true if *this is less than other.
270 //!This only works with two basic_intersegment_ptr pointing
271 //!to the same segment group. Otherwise undefined. Never throws
272 bool less(const self_t &y) const
273 { return this->get_pointer() < y.get_pointer(); }
275 void swap(self_t &other)
277 void *ptr_this = this->get_pointer();
278 void *ptr_other = other.get_pointer();
279 other.set_from_pointer(ptr_this);
280 this->set_from_pointer(ptr_other);
283 //!Sets the object internals to represent the
284 //!address pointed by ptr
285 void set_from_pointer(const void *ptr)
287 if(!ptr){
288 this->set_null();
289 return;
292 std::size_t mode = this->get_mode();
293 if(mode == is_in_stack){
294 members.direct.addr = const_cast<void*>(ptr);
295 return;
297 if(mode == is_relative){
298 char *beg_addr = static_cast<char*>(this->relative_calculate_begin_addr());
299 std::size_t seg_size = this->relative_size();
300 if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){
301 members.relative.off = static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this);
302 return;
305 std::size_t ptr_offset;
306 std::size_t this_offset;
307 segment_info_t ptr_info;
308 segment_info_t this_info;
309 void *ptr_base;
310 void *this_base;
311 get_segment_info_and_offset(this, this_info, this_offset, this_base);
313 if(!this_info.group){
314 this->set_mode(is_in_stack);
315 this->members.direct.addr = const_cast<void*>(ptr);
317 else{
318 get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base);
320 if(ptr_info.group != this_info.group){
321 this->set_mode(is_pointee_outside);
322 this->members.direct.addr = const_cast<void*>(ptr);
324 else if(ptr_info.id == this_info.id){
325 this->set_mode(is_relative);
326 members.relative.off = (static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
327 this->relative_set_begin_from_base(this_base);
328 std::size_t pow, frc;
329 std::size_t s = calculate_size(this_info.size, pow, frc);
330 (void)s;
331 assert(this_info.size == s);
332 this->members.relative.pow = pow;
333 this->members.relative.frc = frc;
335 else{
336 this->set_mode(is_segmented);
337 this->members.segmented.segment = ptr_info.id;
338 this->members.segmented.off = ptr_offset;
343 //!Sets the object internals to represent the address pointed
344 //!by another flat_map_intersegment
345 void set_from_other(const self_t &other)
347 this->set_from_pointer(other.get_pointer());
350 //!Increments internal
351 //!offset
352 void inc_offset(std::ptrdiff_t bytes)
354 this->set_from_pointer(static_cast<char*>(this->get_pointer()) + bytes);
357 //!Decrements internal
358 //!offset
359 void dec_offset(std::ptrdiff_t bytes)
361 this->set_from_pointer(static_cast<char*>(this->get_pointer()) - bytes);
364 //////////////////////////////////////
365 //////////////////////////////////////
366 //////////////////////////////////////
368 flat_map_intersegment()
369 : intersegment_base()
372 ~flat_map_intersegment()
375 private:
377 class segment_group_t
379 struct segment_data
381 void *addr;
382 std::size_t size;
384 vector<segment_data> m_segments;
385 multi_segment_services &m_ms_services;
387 public:
388 segment_group_t(multi_segment_services &ms_services)
389 : m_ms_services(ms_services)
392 void push_back(void *addr, std::size_t size)
394 segment_data d = { addr, size };
395 m_segments.push_back(d);
398 void pop_back()
400 assert(!m_segments.empty());
401 m_segments.erase(--m_segments.end());
405 void *address_of(std::size_t segment_id)
407 assert(segment_id < (std::size_t)m_segments.size());
408 return m_segments[segment_id].addr;
411 void clear_segments()
412 { m_segments.clear(); }
414 std::size_t get_size() const
415 { return m_segments.size(); }
417 multi_segment_services &get_multi_segment_services() const
418 { return m_ms_services; }
420 friend bool operator< (const segment_group_t&l, const segment_group_t &r)
421 { return &l.m_ms_services < &r.m_ms_services; }
424 struct segment_info_t
426 std::size_t size;
427 std::size_t id;
428 segment_group_t *group;
429 segment_info_t()
430 : size(0), id(0), group(0)
434 typedef set<segment_group_t> segment_groups_t;
436 typedef boost::interprocess::flat_map
437 <const void *
438 ,segment_info_t
439 ,std::less<const void *> > ptr_to_segment_info_t;
441 struct mappings_t : Mutex
443 //!Mutex to preserve integrity in multi-threaded
444 //!enviroments
445 typedef Mutex mutex_type;
446 //!Maps base addresses and segment information
447 //!(size and segment group and id)*
449 ptr_to_segment_info_t m_ptr_to_segment_info;
451 ~mappings_t()
453 //Check that all mappings have been erased
454 assert(m_ptr_to_segment_info.empty());
458 //Static members
459 static mappings_t s_map;
460 static segment_groups_t s_groups;
461 public:
463 typedef segment_group_t* segment_group_id;
465 //!Returns the segment and offset
466 //!of an address
467 static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base)
469 //------------------------------------------------------------------
470 boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
471 //------------------------------------------------------------------
472 base = 0;
473 if(s_map.m_ptr_to_segment_info.empty()){
474 segment = segment_info_t();
475 offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
476 return;
478 //Find the first base address greater than ptr
479 typename ptr_to_segment_info_t::iterator it
480 = s_map.m_ptr_to_segment_info.upper_bound(ptr);
481 if(it == s_map.m_ptr_to_segment_info.begin()){
482 segment = segment_info_t();
483 offset = reinterpret_cast<const char*>(ptr) - static_cast<const char *>(0);
485 //Go to the previous one
486 --it;
487 char * segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first));
488 std::size_t segment_size = it->second.size;
490 if(segment_base <= reinterpret_cast<const char*>(ptr) &&
491 (segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){
492 segment = it->second;
493 offset = reinterpret_cast<const char*>(ptr) - segment_base;
494 base = segment_base;
496 else{
497 segment = segment_info_t();
498 offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
502 //!Associates a segment defined by group/id with a base address and size.
503 //!Returns false if the group is not found or there is an error
504 static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size)
506 //------------------------------------------------------------------
507 boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
508 //------------------------------------------------------------------
510 typedef typename ptr_to_segment_info_t::value_type value_type;
511 typedef typename ptr_to_segment_info_t::iterator iterator;
512 typedef std::pair<iterator, bool> it_b_t;
514 segment_info_t info;
515 info.group = group_id;
516 info.size = size;
517 info.id = group_id->get_size();
519 it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info));
520 assert(ret.second);
522 value_eraser<ptr_to_segment_info_t> v_eraser(s_map.m_ptr_to_segment_info, ret.first);
523 group_id->push_back(ptr, size);
524 v_eraser.release();
527 static bool erase_last_mapping(segment_group_id group_id)
529 //------------------------------------------------------------------
530 boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
531 //------------------------------------------------------------------
532 if(!group_id->get_size()){
533 return false;
535 else{
536 void *addr = group_id->address_of(group_id->get_size()-1);
537 group_id->pop_back();
538 std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr);
539 (void)erased;
540 assert(erased);
541 return true;
545 static segment_group_id new_segment_group(multi_segment_services *services)
547 { //------------------------------------------------------------------
548 boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
549 //------------------------------------------------------------------
550 typedef typename segment_groups_t::iterator iterator;
551 std::pair<iterator, bool> ret =
552 s_groups.insert(segment_group_t(*services));
553 assert(ret.second);
554 return &*ret.first;
558 static bool delete_group(segment_group_id id)
560 { //------------------------------------------------------------------
561 boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
562 //------------------------------------------------------------------
563 bool success = 1u == s_groups.erase(segment_group_t(*id));
564 if(success){
565 typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it;
566 ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin());
567 while(it != s_map.m_ptr_to_segment_info.end()){
568 if(it->second.group == id){
569 it = s_map.m_ptr_to_segment_info.erase(it);
571 else{
572 ++it;
576 return success;
581 //!Static map-segment_info associated with
582 //!flat_map_intersegment<>
583 template <class Mutex>
584 typename flat_map_intersegment<Mutex>::mappings_t
585 flat_map_intersegment<Mutex>::s_map;
587 //!Static segment group container associated with
588 //!flat_map_intersegment<>
589 template <class Mutex>
590 typename flat_map_intersegment<Mutex>::segment_groups_t
591 flat_map_intersegment<Mutex>::s_groups;
593 //!A smart pointer that can point to a pointee that resides in another memory
594 //!memory mapped or shared memory segment.
595 template <class T>
596 class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
598 typedef flat_map_intersegment<interprocess_mutex> PT;
599 typedef intersegment_ptr<T> self_t;
600 typedef PT base_t;
602 void unspecified_bool_type_func() const {}
603 typedef void (self_t::*unspecified_bool_type)() const;
605 public:
606 typedef T * pointer;
607 typedef typename detail::add_reference<T>::type reference;
608 typedef T value_type;
609 typedef std::ptrdiff_t difference_type;
610 typedef std::random_access_iterator_tag iterator_category;
612 public: //Public Functions
614 //!Constructor from raw pointer (allows "0" pointer conversion).
615 //!Never throws.
616 intersegment_ptr(pointer ptr = 0)
617 { base_t::set_from_pointer(ptr); }
619 //!Constructor from other pointer.
620 //!Never throws.
621 template <class U>
622 intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); }
624 //!Constructor from other intersegment_ptr
625 //!Never throws
626 intersegment_ptr(const intersegment_ptr& ptr)
627 { base_t::set_from_other(ptr); }
629 //!Constructor from other intersegment_ptr. If pointers of pointee types are
630 //!convertible, intersegment_ptrs will be convertibles. Never throws.
631 template<class T2>
632 intersegment_ptr(const intersegment_ptr<T2> &ptr)
633 { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); }
635 //!Emulates static_cast operator.
636 //!Never throws.
637 template<class U>
638 intersegment_ptr(const intersegment_ptr<U> &r, detail::static_cast_tag)
639 { base_t::set_from_pointer(static_cast<T*>(r.get())); }
641 //!Emulates const_cast operator.
642 //!Never throws.
643 template<class U>
644 intersegment_ptr(const intersegment_ptr<U> &r, detail::const_cast_tag)
645 { base_t::set_from_pointer(const_cast<T*>(r.get())); }
647 //!Emulates dynamic_cast operator.
648 //!Never throws.
649 template<class U>
650 intersegment_ptr(const intersegment_ptr<U> &r, detail::dynamic_cast_tag)
651 { base_t::set_from_pointer(dynamic_cast<T*>(r.get())); }
653 //!Emulates reinterpret_cast operator.
654 //!Never throws.
655 template<class U>
656 intersegment_ptr(const intersegment_ptr<U> &r, detail::reinterpret_cast_tag)
657 { base_t::set_from_pointer(reinterpret_cast<T*>(r.get())); }
659 //!Obtains raw pointer from offset.
660 //!Never throws.
661 pointer get()const
662 { return static_cast<pointer>(base_t::get_pointer()); }
664 //!Pointer-like -> operator. It can return 0 pointer.
665 //!Never throws.
666 pointer operator->() const
667 { return self_t::get(); }
669 //!Dereferencing operator, if it is a null intersegment_ptr behavior
670 //!is undefined. Never throws.
671 reference operator* () const
672 { return *(self_t::get()); }
674 //!Indexing operator.
675 //!Never throws.
676 reference operator[](std::ptrdiff_t idx) const
677 { return self_t::get()[idx]; }
679 //!Assignment from pointer (saves extra conversion).
680 //!Never throws.
681 intersegment_ptr& operator= (pointer from)
682 { base_t::set_from_pointer(from); return *this; }
684 //!Assignment from other intersegment_ptr.
685 //!Never throws.
686 intersegment_ptr& operator= (const intersegment_ptr &ptr)
687 { base_t::set_from_other(ptr); return *this; }
689 //!Assignment from related intersegment_ptr. If pointers of pointee types
690 //!are assignable, intersegment_ptrs will be assignable. Never throws.
691 template <class T2>
692 intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr)
694 pointer p(ptr.get()); (void)p;
695 base_t::set_from_other(ptr); return *this;
698 //!intersegment_ptr + std::ptrdiff_t.
699 //!Never throws.
700 intersegment_ptr operator+ (std::ptrdiff_t idx) const
702 intersegment_ptr result (*this);
703 result.inc_offset(idx*sizeof(T));
704 return result;
707 //!intersegment_ptr - std::ptrdiff_t.
708 //!Never throws.
709 intersegment_ptr operator- (std::ptrdiff_t idx) const
711 intersegment_ptr result (*this);
712 result.dec_offset(idx*sizeof(T));
713 return result;
716 //!intersegment_ptr += std::ptrdiff_t.
717 //!Never throws.
718 intersegment_ptr &operator+= (std::ptrdiff_t offset)
719 { base_t::inc_offset(offset*sizeof(T)); return *this; }
721 //!intersegment_ptr -= std::ptrdiff_t.
722 //!Never throws.
723 intersegment_ptr &operator-= (std::ptrdiff_t offset)
724 { base_t::dec_offset(offset*sizeof(T)); return *this; }
726 //!++intersegment_ptr.
727 //!Never throws.
728 intersegment_ptr& operator++ (void)
729 { base_t::inc_offset(sizeof(T)); return *this; }
731 //!intersegment_ptr++.
732 //!Never throws.
733 intersegment_ptr operator++ (int)
734 { intersegment_ptr temp(*this); ++*this; return temp; }
736 //!--intersegment_ptr.
737 //!Never throws.
738 intersegment_ptr& operator-- (void)
739 { base_t::dec_offset(sizeof(T)); return *this; }
741 //!intersegment_ptr--.
742 //!Never throws.
743 intersegment_ptr operator-- (int)
744 { intersegment_ptr temp(*this); --*this; return temp; }
746 //!Safe bool conversion operator.
747 //!Never throws.
748 operator unspecified_bool_type() const
749 { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; }
751 //!Not operator. Not needed in theory, but improves portability.
752 //!Never throws.
753 bool operator! () const
754 { return base_t::is_null(); }
756 //!Swaps two intersegment_ptr-s. More efficient than std::swap.
757 //!Never throws.
758 void swap(intersegment_ptr &other)
759 { base_t::swap(other); }
761 //!Calculates the distance between two intersegment_ptr-s.
762 //!This only works with two basic_intersegment_ptr pointing
763 //!to the same segment. Otherwise undefined
764 template <class T2>
765 ptrdiff_t _diff(const intersegment_ptr<T2> &other) const
766 { return base_t::diff(other); }
768 //!Returns true if both point to the
769 //!same object
770 template <class T2>
771 bool _equal(const intersegment_ptr<T2>&other) const
772 { return base_t::equal(other); }
774 //!Returns true if *this is less than other.
775 //!This only works with two basic_intersegment_ptr pointing
776 //!to the same segment group. Otherwise undefined. Never throws
777 template <class T2>
778 bool _less(const intersegment_ptr<T2> &other) const
779 { return base_t::less(other); }
782 //!Compares the equality of two intersegment_ptr-s.
783 //!Never throws.
784 template <class T1, class T2> inline
785 bool operator ==(const intersegment_ptr<T1> &left,
786 const intersegment_ptr<T2> &right)
788 //Make sure both pointers can be compared
789 bool e = typename intersegment_ptr<T1>::pointer(0) ==
790 typename intersegment_ptr<T2>::pointer(0);
791 (void)e;
792 return left._equal(right);
795 //!Returns true if *this is less than other.
796 //!This only works with two basic_intersegment_ptr pointing
797 //!to the same segment group. Otherwise undefined. Never throws
798 template <class T1, class T2> inline
799 bool operator <(const intersegment_ptr<T1> &left,
800 const intersegment_ptr<T2> &right)
802 //Make sure both pointers can be compared
803 bool e = typename intersegment_ptr<T1>::pointer(0) <
804 typename intersegment_ptr<T2>::pointer(0);
805 (void)e;
806 return left._less(right);
809 template<class T1, class T2> inline
810 bool operator!= (const intersegment_ptr<T1> &pt1,
811 const intersegment_ptr<T2> &pt2)
812 { return !(pt1 ==pt2); }
814 //!intersegment_ptr<T1> <= intersegment_ptr<T2>.
815 //!Never throws.
816 template<class T1, class T2> inline
817 bool operator<= (const intersegment_ptr<T1> &pt1,
818 const intersegment_ptr<T2> &pt2)
819 { return !(pt1 > pt2); }
821 //!intersegment_ptr<T1> > intersegment_ptr<T2>.
822 //!Never throws.
823 template<class T1, class T2> inline
824 bool operator> (const intersegment_ptr<T1> &pt1,
825 const intersegment_ptr<T2> &pt2)
826 { return (pt2 < pt1); }
828 //!intersegment_ptr<T1> >= intersegment_ptr<T2>.
829 //!Never throws.
830 template<class T1, class T2> inline
831 bool operator>= (const intersegment_ptr<T1> &pt1,
832 const intersegment_ptr<T2> &pt2)
833 { return !(pt1 < pt2); }
835 //!operator<<
836 template<class E, class T, class U> inline
837 std::basic_ostream<E, T> & operator<<
838 (std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p)
839 { return os << p.get(); }
841 //!operator>>
842 template<class E, class T, class U> inline
843 std::basic_istream<E, T> & operator>>
844 (std::basic_istream<E, T> & os, intersegment_ptr<U> & p)
845 { U * tmp; return os >> tmp; p = tmp; }
847 //!std::ptrdiff_t + intersegment_ptr.
848 //!The result is another pointer of the same segment
849 template<class T> inline
850 intersegment_ptr<T> operator+
851 (std::ptrdiff_t diff, const intersegment_ptr<T>& right)
852 { return right + diff; }
854 //!intersegment_ptr - intersegment_ptr.
855 //!This only works with two intersegment_ptr-s that point to the
856 //!same segment
857 template <class T, class T2> inline
858 std::ptrdiff_t operator- (const intersegment_ptr<T> &pt,
859 const intersegment_ptr<T2> &pt2)
860 { return pt._diff(pt2)/sizeof(T); }
862 //! swap specialization
863 template<class T> inline
864 void swap (boost::interprocess::intersegment_ptr<T> &pt,
865 boost::interprocess::intersegment_ptr<T> &pt2)
866 { pt.swap(pt2); }
868 //!get_pointer() enables boost::mem_fn to recognize intersegment_ptr.
869 //!Never throws.
870 template<class T> inline
871 T * get_pointer(boost::interprocess::intersegment_ptr<T> const & p)
872 { return p.get(); }
874 //!Simulation of static_cast between pointers.
875 //!Never throws.
876 template<class T, class U> inline
877 boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
878 { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::static_cast_tag()); }
880 //!Simulation of const_cast between pointers.
881 //!Never throws.
882 template<class T, class U> inline
883 boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
884 { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::const_cast_tag()); }
886 //!Simulation of dynamic_cast between pointers.
887 //!Never throws.
888 template<class T, class U> inline
889 boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
890 { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::dynamic_cast_tag()); }
892 //!Simulation of reinterpret_cast between pointers.
893 //!Never throws.
894 template<class T, class U> inline
895 boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
896 { return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::reinterpret_cast_tag()); }
898 //!Trait class to detect if an smart pointer has
899 //!multi-segment addressing capabilities.
900 template <class T>
901 struct is_multisegment_ptr
902 <boost::interprocess::intersegment_ptr<T> >
904 static const bool value = true;
907 } //namespace interprocess {
909 #if defined(_MSC_VER) && (_MSC_VER < 1400)
910 //!get_pointer() enables boost::mem_fn to recognize intersegment_ptr.
911 //!Never throws.
912 template<class T> inline
913 T * get_pointer(boost::interprocess::intersegment_ptr<T> const & p)
914 { return p.get(); }
915 #endif
917 //!has_trivial_constructor<> == true_type specialization
918 //!for optimizations
919 template <class T>
920 struct has_trivial_constructor
921 < boost::interprocess::intersegment_ptr<T> >
922 : public true_type{};
924 //!has_trivial_destructor<> == true_type specialization
925 //!for optimizations
926 template <class T>
927 struct has_trivial_destructor
928 < boost::interprocess::intersegment_ptr<T> >
929 : public true_type{};
931 } //namespace boost {
933 #include <boost/interprocess/detail/config_end.hpp>
935 #if 0
937 //bits
938 //-> is_segmented
939 //-> is_relative
940 //-> is_in_stack
941 //-> is_pointee_outside
943 //Data
948 //segmented:
950 // std::size_t ctrl : CTRL_BITS;
951 // std::size_t segment : MAX_SEGMENT_BITS;
952 // std::size_t offset;
954 //RELATIVE_SIZE_BITS = SIZE_T_BITS -
955 // MAX_SEGMENT_BITS -
956 // CTRL_BITS 10 10
957 //MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52
959 //SIZE_T_BITS - 1 - ALIGN_BITS 19 51
960 //POW_SIZE_BITS = upper_log2
961 // (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6
962 //FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS
963 // MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5
965 //relative:
967 // std::size_t ctrl : CTRL_BITS; 2 2
968 // std::size_t size_pow : POW_SIZE_BITS 5 6
969 // std::size_t size_frc : FRC_SIZE_BITS; 6 5
970 // std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51
971 // std::ptrdiff_t distance : SIZE_T_BITS; 32 64
973 //direct:
975 // std::size_t ctrl : CTRL_BITS; 2 2
976 // std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62
977 // void *addr : SIZE_T_BITS; 32 64
979 //32 bits systems:
980 //Page alignment: 2**12
983 //!Obtains the address pointed by the
984 //!object
985 void *get_pointer() const
987 if(this->is_pointee_outside() || this->is_in_stack()){
988 return raw_address();
990 else if(this->is_relative()){
991 return (const_cast<char*>(reinterpret_cast<const char*>(this))) + this->relative_pointee_offset();
993 else{
994 group_manager *m = get_segment_group_manager(addr);
995 char *base = static_cast<char*>(m->get_id_address(this->segmented_id()));
996 return base + this->segmented_offset();
1000 void set_from_pointer(const void *ptr)
1002 if(!ptr){
1003 this->set_pointee_outside();
1004 this->raw_address(ptr);
1006 else if(this->is_in_stack()){
1007 this->raw_address(ptr);
1009 else if(this->is_relative() &&
1010 ( (ptr >= this->relative_start())
1011 &&(ptr < this->relative_start() + this->relative_size()))
1013 this->relative_offset(ptr - this);
1015 else{
1016 segment_info_t ptr_info = get_id_from_addr(ptr);
1017 segment_info_t this_info = get_id_from_addr(this);
1018 if(ptr_info.segment_group != this_info.segment_group){
1019 if(!ptr_info.segment_group){
1020 this->set_in_stack();
1022 else{
1023 this->set_pointee_outside();
1026 else if(ptr_info.segment_id == this_info.segment_id){
1027 set_relative();
1028 this->relative_size (ptr_info.size);
1029 this->relative_offset(static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
1030 this->relative_start (ptr_info.base);
1035 void set_from_other(const self_t &other)
1036 { this->set_from_pointer(other.get_pointer()); }
1038 #endif
1040 #endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP