]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/interprocess/include/boost/interprocess/detail/intersegment_ptr.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / interprocess / include / boost / interprocess / detail / intersegment_ptr.hpp
CommitLineData
7c673cae
FG
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//!
47namespace boost {
48
49//Predeclarations
50template <class T>
51struct has_trivial_constructor;
52
53template <class T>
54struct has_trivial_destructor;
55
56namespace interprocess {
57
58template <class T>
59struct is_multisegment_ptr;
60
61struct 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
92 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
131 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
138 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
147 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
156 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
179 std::size_t get_mode()const
180 { return members.direct.ctrl; }
181
182 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
190 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
199 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
208 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.
222template <class Mutex>
223struct flat_map_intersegment
224 : public intersegment_base
225{
226 typedef flat_map_intersegment<Mutex> self_t;
227
228 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
233 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
265 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
270 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
276 bool less(const self_t &y) const
277 { return this->to_raw_pointer() < y.to_raw_pointer(); }
278
279 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
289 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
349 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
356 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
363 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
372 flat_map_intersegment()
373 : intersegment_base()
374 {}
375
376 ~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:
392 segment_group_t(multi_segment_services &ms_services)
393 : m_ms_services(ms_services)
394 {}
395
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
402 void pop_back()
403 {
404 BOOST_ASSERT(!m_segments.empty());
405 m_segments.erase(--m_segments.end());
406 }
407
408
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
415 void clear_segments()
416 { m_segments.clear(); }
417
418 std::size_t get_size() const
419 { return m_segments.size(); }
420
421 multi_segment_services &get_multi_segment_services() const
422 { return m_ms_services; }
423
424 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;
433 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
455 ~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
471 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
508 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
531 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
549 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
562 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<>
587template <class Mutex>
588typename 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<>
593template <class Mutex>
594typename 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.
599template <class T>
600class 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
606 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.
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>
626 intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); }
627
628 //!Constructor from other intersegment_ptr
629 //!Never throws
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>
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>
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>
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>
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>
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.
665 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.
670 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.
675 reference operator* () const
676 { return *(self_t::get()); }
677
678 //!Indexing operator.
679 //!Never throws.
680 reference operator[](std::ptrdiff_t idx) const
681 { return self_t::get()[idx]; }
682
683 //!Assignment from pointer (saves extra conversion).
684 //!Never throws.
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.
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>
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.
704 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.
713 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.
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.
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.
732 intersegment_ptr& operator++ (void)
733 { base_t::inc_offset(sizeof(T)); return *this; }
734
735 //!intersegment_ptr++.
736 //!Never throws.
737 intersegment_ptr operator++ (int)
738 { intersegment_ptr temp(*this); ++*this; return temp; }
739
740 //!--intersegment_ptr.
741 //!Never throws.
742 intersegment_ptr& operator-- (void)
743 { base_t::dec_offset(sizeof(T)); return *this; }
744
745 //!intersegment_ptr--.
746 //!Never throws.
747 intersegment_ptr operator-- (int)
748 { intersegment_ptr temp(*this); --*this; return temp; }
749
750 //!Safe bool conversion operator.
751 //!Never throws.
752 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.
757 bool operator! () const
758 { return base_t::is_null(); }
759
760 //!Swaps two intersegment_ptr-s. More efficient than standard swap.
761 //!Never throws.
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>
769 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>
775 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>
782 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.
788template <class T1, class T2> inline
789bool 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
802template <class T1, class T2> inline
803bool 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
813template<class T1, class T2> inline
814bool 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.
820template<class T1, class T2> inline
821bool 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.
827template<class T1, class T2> inline
828bool 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.
834template<class T1, class T2> inline
835bool operator>= (const intersegment_ptr<T1> &pt1,
836 const intersegment_ptr<T2> &pt2)
837{ return !(pt1 < pt2); }
838
839//!operator<<
840template<class E, class T, class U> inline
841std::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>>
846template<class E, class T, class U> inline
847std::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
853template<class T> inline
854intersegment_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
861template <class T, class T2> inline
862std::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
867template<class T> inline
868void 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.
874template<class T> inline
875T * 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.
880template<class T, class U> inline
881boost::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.
886template<class T, class U> inline
887boost::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.
892template<class T, class U> inline
893boost::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.
898template<class T, class U> inline
899boost::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.
904template <class T>
905struct 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.
916template<class T> inline
917T * 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
923template <class T>
924struct has_trivial_constructor
925 < boost::interprocess::intersegment_ptr<T> >
926 : public true_type{};
927
928//!has_trivial_destructor<> == true_type specialization
929//!for optimizations
930template <class T>
931struct 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
987void *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
1002void 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
1037void 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