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