• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2005-2012. 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_INTERSEGMENT_PTR_HPP
12 #define BOOST_INTERPROCESS_INTERSEGMENT_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 // interprocess
25 #include <boost/interprocess/interprocess_fwd.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 // interprocess/detail
32 #include <boost/interprocess/detail/multi_segment_services.hpp>
33 #include <boost/interprocess/detail/utilities.hpp>
34 #include <boost/interprocess/detail/math_functions.hpp>
35 #include <boost/interprocess/detail/cast_tags.hpp>
36 #include <boost/interprocess/detail/mpl.hpp>
37 // other boost
38 #include <boost/core/no_exceptions_support.hpp>
39 #include <boost/static_assert.hpp>  //BOOST_STATIC_ASSERT
40 #include <boost/integer/static_log2.hpp>
41 #include <boost/assert.hpp>   //BOOST_ASSERT
42 // std
43 #include <climits>   //CHAR_BIT
44 
45 //!\file
46 //!
47 namespace boost {
48 
49 //Predeclarations
50 template <class T>
51 struct has_trivial_constructor;
52 
53 template <class T>
54 struct has_trivial_destructor;
55 
56 namespace interprocess {
57 
58 template <class T>
59 struct is_multisegment_ptr;
60 
61 struct intersegment_base
62 {
63    typedef intersegment_base  self_t;
64    BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*)));
65    BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64));
66    static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64;
67    static const std::size_t ctrl_bits = 2;
68    static const std::size_t align_bits = 12;
69    static const std::size_t align      = std::size_t(1) << align_bits;
70    static const std::size_t max_segment_size_bits = size_t_bits - 2;
71    static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits;
72 
73    static const std::size_t begin_bits             = max_segment_size_bits - align_bits;
74    static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value;
75    static const std::size_t pow_size_bits =
76       (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ?
77       pow_size_bits_helper : pow_size_bits_helper + 1;
78    static const std::size_t frc_size_bits =
79       size_t_bits - ctrl_bits - begin_bits - pow_size_bits;
80 
81    BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits ));
82 
83    static const std::size_t relative_size_bits =
84       size_t_bits - max_segment_size_bits - ctrl_bits;
85 
86    static const std::size_t is_pointee_outside  = 0;
87    static const std::size_t is_in_stack         = 1;
88    static const std::size_t is_relative         = 2;
89    static const std::size_t is_segmented        = 3;
90    static const std::size_t is_max_mode         = 4;
91 
intersegment_baseboost::interprocess::intersegment_base92    intersegment_base()
93    {
94       this->set_mode(is_pointee_outside);
95       this->set_null();
96    }
97 
98    struct relative_addressing
99    {
100       std::size_t ctrl     :  2;
101       std::size_t pow      :  pow_size_bits;
102       std::size_t frc      :  frc_size_bits;
103       std::size_t beg      :  begin_bits;
104       std::ptrdiff_t off   :  sizeof(std::ptrdiff_t)*CHAR_BIT - 2;
105       std::ptrdiff_t bits  :  2;
106    };
107 
108    struct direct_addressing
109    {
110       std::size_t ctrl     :  2;
111       std::size_t dummy    :  sizeof(std::size_t)*CHAR_BIT - 2;
112       void * addr;
113    };
114 
115    struct segmented_addressing
116    {
117       std::size_t ctrl     :  2;
118       std::size_t segment  :  sizeof(std::size_t)*CHAR_BIT - 2;
119       std::size_t off      :  sizeof(std::size_t)*CHAR_BIT - 2;
120       std::size_t bits     :  2;
121    };
122 
123    union members_t{
124       relative_addressing  relative;
125       direct_addressing    direct;
126       segmented_addressing segmented;
127    } members;
128 
129    BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t));
130 
relative_calculate_begin_addrboost::interprocess::intersegment_base131    void *relative_calculate_begin_addr() const
132    {
133       const std::size_t mask = ~(align - 1);
134       std::size_t beg = this->members.relative.beg;
135       return reinterpret_cast<void*>((((std::size_t)this) & mask) - (beg << align_bits));
136    }
137 
relative_set_begin_from_baseboost::interprocess::intersegment_base138    void relative_set_begin_from_base(void *addr)
139    {
140       BOOST_ASSERT(addr < static_cast<void*>(this));
141       std::size_t off = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(addr);
142       members.relative.beg = off >> align_bits;
143    }
144 
145    //!Obtains the address pointed by the
146    //!object
relative_sizeboost::interprocess::intersegment_base147    std::size_t relative_size() const
148    {
149       std::size_t pow  = members.relative.pow;
150       std::size_t size = (std::size_t(1u) << pow);
151       BOOST_ASSERT(pow >= frc_size_bits);
152       size |= members.relative.frc << (pow - frc_size_bits);
153       return size;
154    }
155 
calculate_sizeboost::interprocess::intersegment_base156    static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc)
157    {
158       if(orig_size < align)
159          orig_size = align;
160       orig_size = ipcdetail::get_rounded_size_po2(orig_size, align);
161       pow = ipcdetail::floor_log2(orig_size);
162       std::size_t low_size = (std::size_t(1) << pow);
163       std::size_t diff = orig_size - low_size;
164       BOOST_ASSERT(pow >= frc_size_bits);
165       std::size_t rounded = ipcdetail::get_rounded_size_po2
166                               (diff, (std::size_t)(1u << (pow - frc_size_bits)));
167       if(rounded == low_size){
168          ++pow;
169          frc = 0;
170          rounded  = 0;
171       }
172       else{
173          frc = rounded >> (pow - frc_size_bits);
174       }
175       BOOST_ASSERT(((frc << (pow - frc_size_bits)) & (align-1))==0);
176       return low_size + rounded;
177    }
178 
get_modeboost::interprocess::intersegment_base179    std::size_t get_mode()const
180    {  return members.direct.ctrl;   }
181 
set_modeboost::interprocess::intersegment_base182    void set_mode(std::size_t mode)
183    {
184       BOOST_ASSERT(mode < is_max_mode);
185       members.direct.ctrl = mode;
186    }
187 
188    //!Returns true if object represents
189    //!null pointer
is_nullboost::interprocess::intersegment_base190    bool is_null() const
191    {
192       return   (this->get_mode() < is_relative) &&
193                !members.direct.dummy &&
194                !members.direct.addr;
195    }
196 
197    //!Sets the object to represent
198    //!the null pointer
set_nullboost::interprocess::intersegment_base199    void set_null()
200    {
201       if(this->get_mode() >= is_relative){
202          this->set_mode(is_pointee_outside);
203       }
204       members.direct.dummy = 0;
205       members.direct.addr  = 0;
206    }
207 
round_sizeboost::interprocess::intersegment_base208    static std::size_t round_size(std::size_t orig_size)
209    {
210       std::size_t pow, frc;
211       return calculate_size(orig_size, pow, frc);
212    }
213 };
214 
215 
216 
217 //!Configures intersegment_ptr with the capability to address:
218 //!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups
219 //!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group.
220 //!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment.
221 //!The mapping is implemented through flat_maps synchronized with mutexes.
222 template <class Mutex>
223 struct flat_map_intersegment
224    :  public intersegment_base
225 {
226    typedef flat_map_intersegment<Mutex>   self_t;
227 
set_from_pointerboost::interprocess::flat_map_intersegment228    void set_from_pointer(const volatile void *ptr)
229    {  this->set_from_pointer(const_cast<const void *>(ptr));  }
230 
231    //!Obtains the address pointed
232    //!by the object
to_raw_pointerboost::interprocess::flat_map_intersegment233    void *to_raw_pointer() const
234    {
235       if(is_null()){
236          return 0;
237       }
238       switch(this->get_mode()){
239          case is_relative:
240             return const_cast<char*>(reinterpret_cast<const char*>(this)) + members.relative.off;
241          break;
242          case is_segmented:
243             {
244             segment_info_t segment_info;
245             std::size_t offset;
246             void *this_base;
247             get_segment_info_and_offset(this, segment_info, offset, this_base);
248             char *base  = static_cast<char*>(segment_info.group->address_of(this->members.segmented.segment));
249             return base + this->members.segmented.off;
250             }
251          break;
252          case is_in_stack:
253          case is_pointee_outside:
254             return members.direct.addr;
255          break;
256          default:
257          return 0;
258          break;
259       }
260    }
261 
262    //!Calculates the distance between two basic_intersegment_ptr-s.
263    //!This only works with two basic_intersegment_ptr pointing
264    //!to the same segment. Otherwise undefined
diffboost::interprocess::flat_map_intersegment265    std::ptrdiff_t diff(const self_t &other) const
266    {  return static_cast<char*>(this->to_raw_pointer()) - static_cast<char*>(other.to_raw_pointer());   }
267 
268    //!Returns true if both point to
269    //!the same object
equalboost::interprocess::flat_map_intersegment270    bool equal(const self_t &y) const
271    {  return this->to_raw_pointer() == y.to_raw_pointer();  }
272 
273    //!Returns true if *this is less than other.
274    //!This only works with two basic_intersegment_ptr pointing
275    //!to the same segment group. Otherwise undefined. Never throws
lessboost::interprocess::flat_map_intersegment276    bool less(const self_t &y) const
277    {  return this->to_raw_pointer() < y.to_raw_pointer(); }
278 
swapboost::interprocess::flat_map_intersegment279    void swap(self_t &other)
280    {
281       void *ptr_this  = this->to_raw_pointer();
282       void *ptr_other = other.to_raw_pointer();
283       other.set_from_pointer(ptr_this);
284       this->set_from_pointer(ptr_other);
285    }
286 
287    //!Sets the object internals to represent the
288    //!address pointed by ptr
set_from_pointerboost::interprocess::flat_map_intersegment289    void set_from_pointer(const void *ptr)
290    {
291       if(!ptr){
292          this->set_null();
293          return;
294       }
295 
296       std::size_t mode = this->get_mode();
297       if(mode == is_in_stack){
298          members.direct.addr = const_cast<void*>(ptr);
299          return;
300       }
301       if(mode == is_relative){
302          char *beg_addr = static_cast<char*>(this->relative_calculate_begin_addr());
303          std::size_t seg_size = this->relative_size();
304          if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){
305             members.relative.off = static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this);
306             return;
307          }
308       }
309       std::size_t ptr_offset;
310       std::size_t this_offset;
311       segment_info_t ptr_info;
312       segment_info_t this_info;
313       void *ptr_base;
314       void *this_base;
315       get_segment_info_and_offset(this, this_info, this_offset, this_base);
316 
317       if(!this_info.group){
318          this->set_mode(is_in_stack);
319          this->members.direct.addr = const_cast<void*>(ptr);
320       }
321       else{
322          get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base);
323 
324          if(ptr_info.group != this_info.group){
325             this->set_mode(is_pointee_outside);
326             this->members.direct.addr =  const_cast<void*>(ptr);
327          }
328          else if(ptr_info.id == this_info.id){
329             this->set_mode(is_relative);
330             members.relative.off = (static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
331             this->relative_set_begin_from_base(this_base);
332             std::size_t pow, frc;
333             std::size_t s = calculate_size(this_info.size, pow, frc);
334             (void)s;
335             BOOST_ASSERT(this_info.size == s);
336             this->members.relative.pow = pow;
337             this->members.relative.frc = frc;
338          }
339          else{
340             this->set_mode(is_segmented);
341             this->members.segmented.segment = ptr_info.id;
342             this->members.segmented.off     = ptr_offset;
343          }
344       }
345    }
346 
347    //!Sets the object internals to represent the address pointed
348    //!by another flat_map_intersegment
set_from_otherboost::interprocess::flat_map_intersegment349    void set_from_other(const self_t &other)
350    {
351       this->set_from_pointer(other.to_raw_pointer());
352    }
353 
354    //!Increments internal
355    //!offset
inc_offsetboost::interprocess::flat_map_intersegment356    void inc_offset(std::ptrdiff_t bytes)
357    {
358       this->set_from_pointer(static_cast<char*>(this->to_raw_pointer()) + bytes);
359    }
360 
361    //!Decrements internal
362    //!offset
dec_offsetboost::interprocess::flat_map_intersegment363    void dec_offset(std::ptrdiff_t bytes)
364    {
365       this->set_from_pointer(static_cast<char*>(this->to_raw_pointer()) - bytes);
366    }
367 
368    //////////////////////////////////////
369    //////////////////////////////////////
370    //////////////////////////////////////
371 
flat_map_intersegmentboost::interprocess::flat_map_intersegment372    flat_map_intersegment()
373       :  intersegment_base()
374    {}
375 
~flat_map_intersegmentboost::interprocess::flat_map_intersegment376    ~flat_map_intersegment()
377    {}
378 
379    private:
380 
381    class segment_group_t
382    {
383       struct segment_data
384       {
385          void *addr;
386          std::size_t size;
387       };
388       vector<segment_data> m_segments;
389       multi_segment_services &m_ms_services;
390 
391       public:
segment_group_t(multi_segment_services & ms_services)392       segment_group_t(multi_segment_services &ms_services)
393          :  m_ms_services(ms_services)
394       {}
395 
push_back(void * addr,std::size_t size)396       void push_back(void *addr, std::size_t size)
397       {
398          segment_data d = { addr, size };
399          m_segments.push_back(d);
400       }
401 
pop_back()402       void pop_back()
403       {
404          BOOST_ASSERT(!m_segments.empty());
405          m_segments.erase(--m_segments.end());
406       }
407 
408 
address_of(std::size_t segment_id)409       void *address_of(std::size_t segment_id)
410       {
411          BOOST_ASSERT(segment_id < (std::size_t)m_segments.size());
412          return m_segments[segment_id].addr;
413       }
414 
clear_segments()415       void clear_segments()
416       {  m_segments.clear();  }
417 
get_size() const418       std::size_t get_size() const
419       {  return m_segments.size();  }
420 
get_multi_segment_services() const421       multi_segment_services &get_multi_segment_services() const
422       {  return m_ms_services;   }
423 
operator <boost::interprocess::flat_map_intersegment424       friend bool operator< (const segment_group_t&l, const segment_group_t &r)
425       {  return &l.m_ms_services < &r.m_ms_services;   }
426    };
427 
428    struct segment_info_t
429    {
430       std::size_t size;
431       std::size_t id;
432       segment_group_t *group;
segment_info_tboost::interprocess::flat_map_intersegment::segment_info_t433       segment_info_t()
434          :  size(0), id(0), group(0)
435       {}
436    };
437 
438    typedef set<segment_group_t>  segment_groups_t;
439 
440    typedef boost::interprocess::flat_map
441       <const void *
442       ,segment_info_t
443       ,std::less<const void *> >          ptr_to_segment_info_t;
444 
445    struct mappings_t : Mutex
446    {
447       //!Mutex to preserve integrity in multi-threaded
448       //!enviroments
449       typedef Mutex        mutex_type;
450       //!Maps base addresses and segment information
451       //!(size and segment group and id)*
452 
453       ptr_to_segment_info_t      m_ptr_to_segment_info;
454 
~mappings_tboost::interprocess::flat_map_intersegment::mappings_t455       ~mappings_t()
456       {
457          //Check that all mappings have been erased
458          BOOST_ASSERT(m_ptr_to_segment_info.empty());
459       }
460    };
461 
462    //Static members
463    static mappings_t       s_map;
464    static segment_groups_t s_groups;
465    public:
466 
467    typedef segment_group_t*      segment_group_id;
468 
469    //!Returns the segment and offset
470    //!of an address
get_segment_info_and_offsetboost::interprocess::flat_map_intersegment471    static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base)
472    {
473       //------------------------------------------------------------------
474       boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
475       //------------------------------------------------------------------
476       base = 0;
477       if(s_map.m_ptr_to_segment_info.empty()){
478          segment = segment_info_t();
479          offset  = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
480          return;
481       }
482       //Find the first base address greater than ptr
483       typename ptr_to_segment_info_t::iterator it
484          = s_map.m_ptr_to_segment_info.upper_bound(ptr);
485       if(it == s_map.m_ptr_to_segment_info.begin()){
486          segment = segment_info_t();
487          offset  = reinterpret_cast<const char*>(ptr) - static_cast<const char *>(0);
488       }
489       //Go to the previous one
490       --it;
491       char *      segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first));
492       std::size_t segment_size = it->second.size;
493 
494       if(segment_base <= reinterpret_cast<const char*>(ptr) &&
495          (segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){
496          segment = it->second;
497          offset  = reinterpret_cast<const char*>(ptr) - segment_base;
498          base = segment_base;
499       }
500       else{
501          segment = segment_info_t();
502          offset  = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
503       }
504    }
505 
506    //!Associates a segment defined by group/id with a base address and size.
507    //!Returns false if the group is not found or there is an error
insert_mappingboost::interprocess::flat_map_intersegment508    static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size)
509    {
510       //------------------------------------------------------------------
511       boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
512       //------------------------------------------------------------------
513 
514       typedef typename ptr_to_segment_info_t::value_type value_type;
515       typedef typename ptr_to_segment_info_t::iterator   iterator;
516       typedef std::pair<iterator, bool>                  it_b_t;
517 
518       segment_info_t info;
519       info.group = group_id;
520       info.size  = size;
521       info.id    = group_id->get_size();
522 
523       it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info));
524       BOOST_ASSERT(ret.second);
525 
526       value_eraser<ptr_to_segment_info_t> v_eraser(s_map.m_ptr_to_segment_info, ret.first);
527       group_id->push_back(ptr, size);
528       v_eraser.release();
529    }
530 
erase_last_mappingboost::interprocess::flat_map_intersegment531    static bool erase_last_mapping(segment_group_id group_id)
532    {
533       //------------------------------------------------------------------
534       boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
535       //------------------------------------------------------------------
536       if(!group_id->get_size()){
537          return false;
538       }
539       else{
540          void *addr = group_id->address_of(group_id->get_size()-1);
541          group_id->pop_back();
542          std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr);
543          (void)erased;
544          BOOST_ASSERT(erased);
545          return true;
546       }
547    }
548 
new_segment_groupboost::interprocess::flat_map_intersegment549    static segment_group_id new_segment_group(multi_segment_services *services)
550    {
551       {  //------------------------------------------------------------------
552          boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
553          //------------------------------------------------------------------
554          typedef typename segment_groups_t::iterator iterator;
555          std::pair<iterator, bool> ret =
556             s_groups.insert(segment_group_t(*services));
557          BOOST_ASSERT(ret.second);
558          return &*ret.first;
559       }
560    }
561 
delete_groupboost::interprocess::flat_map_intersegment562    static bool delete_group(segment_group_id id)
563    {
564       {  //------------------------------------------------------------------
565          boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
566          //------------------------------------------------------------------
567          bool success = 1u == s_groups.erase(segment_group_t(*id));
568          if(success){
569             typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it;
570             ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin());
571             while(it != s_map.m_ptr_to_segment_info.end()){
572                if(it->second.group == id){
573                   it = s_map.m_ptr_to_segment_info.erase(it);
574                }
575                else{
576                   ++it;
577                }
578             }
579          }
580          return success;
581       }
582    }
583 };
584 
585 //!Static map-segment_info associated with
586 //!flat_map_intersegment<>
587 template <class Mutex>
588 typename flat_map_intersegment<Mutex>::mappings_t
589    flat_map_intersegment<Mutex>::s_map;
590 
591 //!Static segment group container associated with
592 //!flat_map_intersegment<>
593 template <class Mutex>
594 typename flat_map_intersegment<Mutex>::segment_groups_t
595    flat_map_intersegment<Mutex>::s_groups;
596 
597 //!A smart pointer that can point to a pointee that resides in another memory
598 //!memory mapped or shared memory segment.
599 template <class T>
600 class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
601 {
602    typedef flat_map_intersegment<interprocess_mutex> PT;
603    typedef intersegment_ptr<T>                  self_t;
604    typedef PT                                      base_t;
605 
unspecified_bool_type_func() const606    void unspecified_bool_type_func() const {}
607    typedef void (self_t::*unspecified_bool_type)() const;
608 
609    public:
610    typedef T *                                     pointer;
611    typedef typename ipcdetail::add_reference<T>::type reference;
612    typedef T                                       value_type;
613    typedef std::ptrdiff_t                          difference_type;
614    typedef std::random_access_iterator_tag         iterator_category;
615 
616    public:   //Public Functions
617 
618    //!Constructor from raw pointer (allows "0" pointer conversion).
619    //!Never throws.
intersegment_ptr(pointer ptr=0)620    intersegment_ptr(pointer ptr = 0)
621    {  base_t::set_from_pointer(ptr);   }
622 
623    //!Constructor from other pointer.
624    //!Never throws.
625    template <class U>
intersegment_ptr(U * ptr)626    intersegment_ptr(U *ptr){  base_t::set_from_pointer(pointer(ptr)); }
627 
628    //!Constructor from other intersegment_ptr
629    //!Never throws
intersegment_ptr(const intersegment_ptr & ptr)630    intersegment_ptr(const intersegment_ptr& ptr)
631    {  base_t::set_from_other(ptr);   }
632 
633    //!Constructor from other intersegment_ptr. If pointers of pointee types are
634    //!convertible, intersegment_ptrs will be convertibles. Never throws.
635    template<class T2>
intersegment_ptr(const intersegment_ptr<T2> & ptr)636    intersegment_ptr(const intersegment_ptr<T2> &ptr)
637    {  pointer p(ptr.get());   (void)p; base_t::set_from_other(ptr); }
638 
639    //!Emulates static_cast operator.
640    //!Never throws.
641    template<class U>
intersegment_ptr(const intersegment_ptr<U> & r,ipcdetail::static_cast_tag)642    intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::static_cast_tag)
643    {  base_t::set_from_pointer(static_cast<T*>(r.get())); }
644 
645    //!Emulates const_cast operator.
646    //!Never throws.
647    template<class U>
intersegment_ptr(const intersegment_ptr<U> & r,ipcdetail::const_cast_tag)648    intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::const_cast_tag)
649    {  base_t::set_from_pointer(const_cast<T*>(r.get())); }
650 
651    //!Emulates dynamic_cast operator.
652    //!Never throws.
653    template<class U>
intersegment_ptr(const intersegment_ptr<U> & r,ipcdetail::dynamic_cast_tag)654    intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::dynamic_cast_tag)
655    {  base_t::set_from_pointer(dynamic_cast<T*>(r.get())); }
656 
657    //!Emulates reinterpret_cast operator.
658    //!Never throws.
659    template<class U>
intersegment_ptr(const intersegment_ptr<U> & r,ipcdetail::reinterpret_cast_tag)660    intersegment_ptr(const intersegment_ptr<U> &r, ipcdetail::reinterpret_cast_tag)
661    {  base_t::set_from_pointer(reinterpret_cast<T*>(r.get())); }
662 
663    //!Obtains raw pointer from offset.
664    //!Never throws.
get() const665    pointer get()const
666    {  return static_cast<pointer>(base_t::to_raw_pointer());   }
667 
668    //!Pointer-like -> operator. It can return 0 pointer.
669    //!Never throws.
operator ->() const670    pointer operator->() const
671    {  return self_t::get(); }
672 
673    //!Dereferencing operator, if it is a null intersegment_ptr behavior
674    //!is undefined. Never throws.
operator *() const675    reference operator* () const
676    {  return *(self_t::get());   }
677 
678    //!Indexing operator.
679    //!Never throws.
operator [](std::ptrdiff_t idx) const680    reference operator[](std::ptrdiff_t idx) const
681    {  return self_t::get()[idx];  }
682 
683    //!Assignment from pointer (saves extra conversion).
684    //!Never throws.
operator =(pointer from)685    intersegment_ptr& operator= (pointer from)
686    {  base_t::set_from_pointer(from); return *this;  }
687 
688    //!Assignment from other intersegment_ptr.
689    //!Never throws.
operator =(const intersegment_ptr & ptr)690    intersegment_ptr& operator= (const intersegment_ptr &ptr)
691    {  base_t::set_from_other(ptr);  return *this;  }
692 
693    //!Assignment from related intersegment_ptr. If pointers of pointee types
694    //!are assignable, intersegment_ptrs will be assignable. Never throws.
695    template <class T2>
operator =(const intersegment_ptr<T2> & ptr)696    intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr)
697    {
698       pointer p(ptr.get());   (void)p;
699       base_t::set_from_other(ptr); return *this;
700    }
701 
702    //!intersegment_ptr + std::ptrdiff_t.
703    //!Never throws.
operator +(std::ptrdiff_t idx) const704    intersegment_ptr operator+ (std::ptrdiff_t idx) const
705    {
706       intersegment_ptr result (*this);
707       result.inc_offset(idx*sizeof(T));
708       return result;
709    }
710 
711    //!intersegment_ptr - std::ptrdiff_t.
712    //!Never throws.
operator -(std::ptrdiff_t idx) const713    intersegment_ptr operator- (std::ptrdiff_t idx) const
714    {
715       intersegment_ptr result (*this);
716       result.dec_offset(idx*sizeof(T));
717       return result;
718    }
719 
720    //!intersegment_ptr += std::ptrdiff_t.
721    //!Never throws.
operator +=(std::ptrdiff_t offset)722    intersegment_ptr &operator+= (std::ptrdiff_t offset)
723    {  base_t::inc_offset(offset*sizeof(T));  return *this;  }
724 
725    //!intersegment_ptr -= std::ptrdiff_t.
726    //!Never throws.
operator -=(std::ptrdiff_t offset)727    intersegment_ptr &operator-= (std::ptrdiff_t offset)
728    {  base_t::dec_offset(offset*sizeof(T));  return *this;  }
729 
730    //!++intersegment_ptr.
731    //!Never throws.
operator ++(void)732    intersegment_ptr& operator++ (void)
733    {  base_t::inc_offset(sizeof(T));   return *this;  }
734 
735    //!intersegment_ptr++.
736    //!Never throws.
operator ++(int)737    intersegment_ptr operator++ (int)
738    {  intersegment_ptr temp(*this); ++*this; return temp; }
739 
740    //!--intersegment_ptr.
741    //!Never throws.
operator --(void)742    intersegment_ptr& operator-- (void)
743    {  base_t::dec_offset(sizeof(T));   return *this;  }
744 
745    //!intersegment_ptr--.
746    //!Never throws.
operator --(int)747    intersegment_ptr operator-- (int)
748    {  intersegment_ptr temp(*this); --*this; return temp; }
749 
750    //!Safe bool conversion operator.
751    //!Never throws.
operator unspecified_bool_type() const752    operator unspecified_bool_type() const
753    {  return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func;   }
754 
755    //!Not operator. Not needed in theory, but improves portability.
756    //!Never throws.
operator !() const757    bool operator! () const
758    {  return base_t::is_null();   }
759 
760    //!Swaps two intersegment_ptr-s. More efficient than standard swap.
761    //!Never throws.
swap(intersegment_ptr & other)762    void swap(intersegment_ptr &other)
763    {  base_t::swap(other);   }
764 
765    //!Calculates the distance between two intersegment_ptr-s.
766    //!This only works with two basic_intersegment_ptr pointing
767    //!to the same segment. Otherwise undefined
768    template <class T2>
_diff(const intersegment_ptr<T2> & other) const769    std::ptrdiff_t _diff(const intersegment_ptr<T2> &other) const
770    {  return base_t::diff(other);   }
771 
772    //!Returns true if both point to the
773    //!same object
774    template <class T2>
_equal(const intersegment_ptr<T2> & other) const775    bool _equal(const intersegment_ptr<T2>&other) const
776    {  return base_t::equal(other);   }
777 
778    //!Returns true if *this is less than other.
779    //!This only works with two basic_intersegment_ptr pointing
780    //!to the same segment group. Otherwise undefined. Never throws
781    template <class T2>
_less(const intersegment_ptr<T2> & other) const782    bool _less(const intersegment_ptr<T2> &other) const
783    {  return base_t::less(other);   }
784 };
785 
786 //!Compares the equality of two intersegment_ptr-s.
787 //!Never throws.
788 template <class T1, class T2> inline
operator ==(const intersegment_ptr<T1> & left,const intersegment_ptr<T2> & right)789 bool operator ==(const intersegment_ptr<T1> &left,
790                  const intersegment_ptr<T2> &right)
791 {
792    //Make sure both pointers can be compared
793    bool e = typename intersegment_ptr<T1>::pointer(0) ==
794             typename intersegment_ptr<T2>::pointer(0);
795    (void)e;
796    return left._equal(right);
797 }
798 
799 //!Returns true if *this is less than other.
800 //!This only works with two basic_intersegment_ptr pointing
801 //!to the same segment group. Otherwise undefined. Never throws
802 template <class T1, class T2> inline
operator <(const intersegment_ptr<T1> & left,const intersegment_ptr<T2> & right)803 bool operator <(const intersegment_ptr<T1> &left,
804                 const intersegment_ptr<T2> &right)
805 {
806    //Make sure both pointers can be compared
807    bool e = typename intersegment_ptr<T1>::pointer(0) <
808             typename intersegment_ptr<T2>::pointer(0);
809    (void)e;
810    return left._less(right);
811 }
812 
813 template<class T1, class T2> inline
operator !=(const intersegment_ptr<T1> & pt1,const intersegment_ptr<T2> & pt2)814 bool operator!= (const intersegment_ptr<T1> &pt1,
815                  const intersegment_ptr<T2> &pt2)
816 {  return !(pt1 ==pt2);  }
817 
818 //!intersegment_ptr<T1> <= intersegment_ptr<T2>.
819 //!Never throws.
820 template<class T1, class T2> inline
operator <=(const intersegment_ptr<T1> & pt1,const intersegment_ptr<T2> & pt2)821 bool operator<= (const intersegment_ptr<T1> &pt1,
822                  const intersegment_ptr<T2> &pt2)
823 {  return !(pt1 > pt2);  }
824 
825 //!intersegment_ptr<T1> > intersegment_ptr<T2>.
826 //!Never throws.
827 template<class T1, class T2> inline
operator >(const intersegment_ptr<T1> & pt1,const intersegment_ptr<T2> & pt2)828 bool operator> (const intersegment_ptr<T1> &pt1,
829                        const intersegment_ptr<T2> &pt2)
830 {  return (pt2 < pt1);  }
831 
832 //!intersegment_ptr<T1> >= intersegment_ptr<T2>.
833 //!Never throws.
834 template<class T1, class T2> inline
operator >=(const intersegment_ptr<T1> & pt1,const intersegment_ptr<T2> & pt2)835 bool operator>= (const intersegment_ptr<T1> &pt1,
836                  const intersegment_ptr<T2> &pt2)
837 {  return !(pt1 < pt2);  }
838 
839 //!operator<<
840 template<class E, class T, class U> inline
operator <<(std::basic_ostream<E,T> & os,const intersegment_ptr<U> & p)841 std::basic_ostream<E, T> & operator<<
842    (std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p)
843 {  return os << p.get();   }
844 
845 //!operator>>
846 template<class E, class T, class U> inline
operator >>(std::basic_istream<E,T> & os,intersegment_ptr<U> & p)847 std::basic_istream<E, T> & operator>>
848    (std::basic_istream<E, T> & os, intersegment_ptr<U> & p)
849 {  U * tmp; return os >> tmp; p = tmp;   }
850 
851 //!std::ptrdiff_t + intersegment_ptr.
852 //!The result is another pointer of the same segment
853 template<class T> inline
operator +(std::ptrdiff_t diff,const intersegment_ptr<T> & right)854 intersegment_ptr<T> operator+
855    (std::ptrdiff_t diff, const intersegment_ptr<T>& right)
856 {  return right + diff;  }
857 
858 //!intersegment_ptr - intersegment_ptr.
859 //!This only works with two intersegment_ptr-s that point to the
860 //!same segment
861 template <class T, class T2> inline
operator -(const intersegment_ptr<T> & pt,const intersegment_ptr<T2> & pt2)862 std::ptrdiff_t operator- (const intersegment_ptr<T> &pt,
863                           const intersegment_ptr<T2> &pt2)
864 {  return pt._diff(pt2)/sizeof(T);  }
865 
866 //! swap specialization
867 template<class T> inline
swap(boost::interprocess::intersegment_ptr<T> & pt,boost::interprocess::intersegment_ptr<T> & pt2)868 void swap (boost::interprocess::intersegment_ptr<T> &pt,
869            boost::interprocess::intersegment_ptr<T> &pt2)
870 {  pt.swap(pt2);  }
871 
872 //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
873 //!Never throws.
874 template<class T> inline
to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)875 T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
876 {  return p.get();   }
877 
878 //!Simulation of static_cast between pointers.
879 //!Never throws.
880 template<class T, class U> inline
static_pointer_cast(const boost::interprocess::intersegment_ptr<U> & r)881 boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
882 {  return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::static_cast_tag());  }
883 
884 //!Simulation of const_cast between pointers.
885 //!Never throws.
886 template<class T, class U> inline
const_pointer_cast(const boost::interprocess::intersegment_ptr<U> & r)887 boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
888 {  return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::const_cast_tag());  }
889 
890 //!Simulation of dynamic_cast between pointers.
891 //!Never throws.
892 template<class T, class U> inline
dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> & r)893 boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
894 {  return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::dynamic_cast_tag());  }
895 
896 //!Simulation of reinterpret_cast between pointers.
897 //!Never throws.
898 template<class T, class U> inline
reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> & r)899 boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
900 {  return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::ipcdetail::reinterpret_cast_tag());  }
901 
902 //!Trait class to detect if an smart pointer has
903 //!multi-segment addressing capabilities.
904 template <class T>
905 struct is_multisegment_ptr
906    <boost::interprocess::intersegment_ptr<T> >
907 {
908    static const bool value = true;
909 };
910 
911 }  //namespace interprocess {
912 
913 #if defined(_MSC_VER) && (_MSC_VER < 1400)
914 //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr.
915 //!Never throws.
916 template<class T> inline
to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)917 T * to_raw_pointer(boost::interprocess::intersegment_ptr<T> const & p)
918 {  return p.get();   }
919 #endif
920 
921 //!has_trivial_constructor<> == true_type specialization
922 //!for optimizations
923 template <class T>
924 struct has_trivial_constructor
925    < boost::interprocess::intersegment_ptr<T> >
926    : public true_type{};
927 
928 //!has_trivial_destructor<> == true_type specialization
929 //!for optimizations
930 template <class T>
931 struct has_trivial_destructor
932    < boost::interprocess::intersegment_ptr<T> >
933    : public true_type{};
934 
935 }  //namespace boost {
936 
937 #if 0
938 
939 //bits
940 //-> is_segmented
941 //-> is_relative
942 //-> is_in_stack
943 //-> is_pointee_outside
944 
945 //Data
946 
947 
948 
949 
950 //segmented:
951 //
952 // std::size_t ctrl    : CTRL_BITS;
953 // std::size_t segment : MAX_SEGMENT_BITS;
954 // std::size_t offset;
955 
956 //RELATIVE_SIZE_BITS =  SIZE_T_BITS -
957 //                      MAX_SEGMENT_BITS -
958 //                      CTRL_BITS                  10    10
959 //MAX_SEGMENT_SIZE   = SIZE_T_BITS - ALIGN_BITS    20    52
960 
961 //SIZE_T_BITS - 1 - ALIGN_BITS                     19    51
962 //POW_SIZE_BITS = upper_log2
963 // (SIZE_T_BITS - 1 - ALIGN_BITS)                  5     6
964 //FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS
965 //  MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS     6     5
966 
967 //relative:
968 //
969 // std::size_t ctrl     : CTRL_BITS;               2     2
970 // std::size_t size_pow : POW_SIZE_BITS            5     6
971 // std::size_t size_frc : FRC_SIZE_BITS;           6     5
972 // std::size_t start    : MAX_SEGMENT_SIZE_ALIGNBITS;19    51
973 // std::ptrdiff_t distance : SIZE_T_BITS;          32    64
974 
975 //direct:
976 //
977 // std::size_t ctrl     : CTRL_BITS;               2     2
978 // std::size_t dummy    : SIZE_T_BITS - CTRL_BITS  30    62
979 // void *addr           : SIZE_T_BITS;             32    64
980 
981 //32 bits systems:
982 //Page alignment: 2**12
983 //
984 
985 //!Obtains the address pointed by the
986 //!object
987 void *to_raw_pointer() const
988 {
989    if(this->is_pointee_outside() || this->is_in_stack()){
990       return raw_address();
991    }
992    else if(this->is_relative()){
993       return (const_cast<char*>(reinterpret_cast<const char*>(this))) + this->relative_pointee_offset();
994    }
995    else{
996       group_manager *m     = get_segment_group_manager(addr);
997       char *base  = static_cast<char*>(m->get_id_address(this->segmented_id()));
998       return base + this->segmented_offset();
999    }
1000 }
1001 
1002 void set_from_pointer(const void *ptr)
1003 {
1004    if(!ptr){
1005       this->set_pointee_outside();
1006       this->raw_address(ptr);
1007    }
1008    else if(this->is_in_stack()){
1009       this->raw_address(ptr);
1010    }
1011    else if(this->is_relative() &&
1012             (  (ptr >= this->relative_start())
1013             &&(ptr <  this->relative_start() + this->relative_size()))
1014             ){
1015       this->relative_offset(ptr - this);
1016    }
1017    else{
1018       segment_info_t ptr_info  = get_id_from_addr(ptr);
1019       segment_info_t this_info = get_id_from_addr(this);
1020       if(ptr_info.segment_group != this_info.segment_group){
1021          if(!ptr_info.segment_group){
1022             this->set_in_stack();
1023          }
1024          else{
1025             this->set_pointee_outside();
1026          }
1027       }
1028       else if(ptr_info.segment_id == this_info.segment_id){
1029          set_relative();
1030          this->relative_size  (ptr_info.size);
1031          this->relative_offset(static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
1032          this->relative_start (ptr_info.base);
1033       }
1034    }
1035 }
1036 
1037 void set_from_other(const self_t &other)
1038 {  this->set_from_pointer(other.to_raw_pointer()); }
1039 
1040 #endif
1041 
1042 #include <boost/interprocess/detail/config_end.hpp>
1043 
1044 #endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
1045