Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/interprocess for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP Chris@16: #define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: # Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@101: // interprocess Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include //vector Chris@16: #include //set Chris@101: // interprocess/detail Chris@101: #include Chris@101: #include Chris@101: #include Chris@101: #include Chris@16: #include Chris@101: // other boost Chris@101: #include Chris@16: #include //BOOST_STATIC_ASSERT Chris@16: #include Chris@16: #include //BOOST_ASSERT Chris@101: // std Chris@101: #include //CHAR_BIT Chris@16: Chris@16: //!\file Chris@16: //! Chris@16: namespace boost { Chris@16: Chris@16: //Predeclarations Chris@16: template Chris@16: struct has_trivial_constructor; Chris@16: Chris@16: template Chris@16: struct has_trivial_destructor; Chris@16: Chris@16: namespace interprocess { Chris@16: Chris@16: template Chris@16: struct is_multisegment_ptr; Chris@16: Chris@16: struct intersegment_base Chris@16: { Chris@16: typedef intersegment_base self_t; Chris@16: BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*))); Chris@16: BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64)); Chris@16: static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64; Chris@16: static const std::size_t ctrl_bits = 2; Chris@16: static const std::size_t align_bits = 12; Chris@16: static const std::size_t align = std::size_t(1) << align_bits; Chris@16: static const std::size_t max_segment_size_bits = size_t_bits - 2; Chris@16: static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits; Chris@16: Chris@16: static const std::size_t begin_bits = max_segment_size_bits - align_bits; Chris@16: static const std::size_t pow_size_bits_helper = static_log2::value; Chris@16: static const std::size_t pow_size_bits = Chris@16: (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ? Chris@16: pow_size_bits_helper : pow_size_bits_helper + 1; Chris@16: static const std::size_t frc_size_bits = Chris@16: size_t_bits - ctrl_bits - begin_bits - pow_size_bits; Chris@16: Chris@16: BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits )); Chris@16: Chris@16: static const std::size_t relative_size_bits = Chris@16: size_t_bits - max_segment_size_bits - ctrl_bits; Chris@16: Chris@16: static const std::size_t is_pointee_outside = 0; Chris@16: static const std::size_t is_in_stack = 1; Chris@16: static const std::size_t is_relative = 2; Chris@16: static const std::size_t is_segmented = 3; Chris@16: static const std::size_t is_max_mode = 4; Chris@16: Chris@16: intersegment_base() Chris@16: { Chris@16: this->set_mode(is_pointee_outside); Chris@16: this->set_null(); Chris@16: } Chris@16: Chris@16: struct relative_addressing Chris@16: { Chris@16: std::size_t ctrl : 2; Chris@16: std::size_t pow : pow_size_bits; Chris@16: std::size_t frc : frc_size_bits; Chris@16: std::size_t beg : begin_bits; Chris@16: std::ptrdiff_t off : sizeof(std::ptrdiff_t)*CHAR_BIT - 2; Chris@16: std::ptrdiff_t bits : 2; Chris@16: }; Chris@16: Chris@16: struct direct_addressing Chris@16: { Chris@16: std::size_t ctrl : 2; Chris@16: std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2; Chris@16: void * addr; Chris@16: }; Chris@16: Chris@16: struct segmented_addressing Chris@16: { Chris@16: std::size_t ctrl : 2; Chris@16: std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2; Chris@16: std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2; Chris@16: std::size_t bits : 2; Chris@16: }; Chris@16: Chris@16: union members_t{ Chris@16: relative_addressing relative; Chris@16: direct_addressing direct; Chris@16: segmented_addressing segmented; Chris@16: } members; Chris@16: Chris@16: BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t)); Chris@16: Chris@16: void *relative_calculate_begin_addr() const Chris@16: { Chris@16: const std::size_t mask = ~(align - 1); Chris@16: std::size_t beg = this->members.relative.beg; Chris@16: return reinterpret_cast((((std::size_t)this) & mask) - (beg << align_bits)); Chris@16: } Chris@16: Chris@16: void relative_set_begin_from_base(void *addr) Chris@16: { Chris@16: BOOST_ASSERT(addr < static_cast(this)); Chris@16: std::size_t off = reinterpret_cast(this) - reinterpret_cast(addr); Chris@16: members.relative.beg = off >> align_bits; Chris@16: } Chris@16: Chris@16: //!Obtains the address pointed by the Chris@16: //!object Chris@16: std::size_t relative_size() const Chris@16: { Chris@16: std::size_t pow = members.relative.pow; Chris@16: std::size_t size = (std::size_t(1u) << pow); Chris@16: BOOST_ASSERT(pow >= frc_size_bits); Chris@16: size |= members.relative.frc << (pow - frc_size_bits); Chris@16: return size; Chris@16: } Chris@16: Chris@16: static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc) Chris@16: { Chris@16: if(orig_size < align) Chris@16: orig_size = align; Chris@16: orig_size = ipcdetail::get_rounded_size_po2(orig_size, align); Chris@16: pow = ipcdetail::floor_log2(orig_size); Chris@16: std::size_t low_size = (std::size_t(1) << pow); Chris@16: std::size_t diff = orig_size - low_size; Chris@16: BOOST_ASSERT(pow >= frc_size_bits); Chris@16: std::size_t rounded = ipcdetail::get_rounded_size_po2 Chris@16: (diff, (std::size_t)(1u << (pow - frc_size_bits))); Chris@16: if(rounded == low_size){ Chris@16: ++pow; Chris@16: frc = 0; Chris@16: rounded = 0; Chris@16: } Chris@16: else{ Chris@16: frc = rounded >> (pow - frc_size_bits); Chris@16: } Chris@16: BOOST_ASSERT(((frc << (pow - frc_size_bits)) & (align-1))==0); Chris@16: return low_size + rounded; Chris@16: } Chris@16: Chris@16: std::size_t get_mode()const Chris@16: { return members.direct.ctrl; } Chris@16: Chris@16: void set_mode(std::size_t mode) Chris@16: { Chris@16: BOOST_ASSERT(mode < is_max_mode); Chris@16: members.direct.ctrl = mode; Chris@16: } Chris@16: Chris@16: //!Returns true if object represents Chris@16: //!null pointer Chris@16: bool is_null() const Chris@16: { Chris@16: return (this->get_mode() < is_relative) && Chris@16: !members.direct.dummy && Chris@16: !members.direct.addr; Chris@16: } Chris@16: Chris@16: //!Sets the object to represent Chris@16: //!the null pointer Chris@16: void set_null() Chris@16: { Chris@16: if(this->get_mode() >= is_relative){ Chris@16: this->set_mode(is_pointee_outside); Chris@16: } Chris@16: members.direct.dummy = 0; Chris@16: members.direct.addr = 0; Chris@16: } Chris@16: Chris@16: static std::size_t round_size(std::size_t orig_size) Chris@16: { Chris@16: std::size_t pow, frc; Chris@16: return calculate_size(orig_size, pow, frc); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: //!Configures intersegment_ptr with the capability to address: Chris@16: //!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups Chris@16: //!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group. Chris@16: //!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment. Chris@16: //!The mapping is implemented through flat_maps synchronized with mutexes. Chris@16: template Chris@16: struct flat_map_intersegment Chris@16: : public intersegment_base Chris@16: { Chris@16: typedef flat_map_intersegment self_t; Chris@16: Chris@16: void set_from_pointer(const volatile void *ptr) Chris@16: { this->set_from_pointer(const_cast(ptr)); } Chris@16: Chris@16: //!Obtains the address pointed Chris@16: //!by the object Chris@16: void *to_raw_pointer() const Chris@16: { Chris@16: if(is_null()){ Chris@16: return 0; Chris@16: } Chris@16: switch(this->get_mode()){ Chris@16: case is_relative: Chris@16: return const_cast(reinterpret_cast(this)) + members.relative.off; Chris@16: break; Chris@16: case is_segmented: Chris@16: { Chris@16: segment_info_t segment_info; Chris@16: std::size_t offset; Chris@16: void *this_base; Chris@16: get_segment_info_and_offset(this, segment_info, offset, this_base); Chris@16: char *base = static_cast(segment_info.group->address_of(this->members.segmented.segment)); Chris@16: return base + this->members.segmented.off; Chris@16: } Chris@16: break; Chris@16: case is_in_stack: Chris@16: case is_pointee_outside: Chris@16: return members.direct.addr; Chris@16: break; Chris@16: default: Chris@16: return 0; Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: //!Calculates the distance between two basic_intersegment_ptr-s. Chris@16: //!This only works with two basic_intersegment_ptr pointing Chris@16: //!to the same segment. Otherwise undefined Chris@16: std::ptrdiff_t diff(const self_t &other) const Chris@16: { return static_cast(this->to_raw_pointer()) - static_cast(other.to_raw_pointer()); } Chris@16: Chris@16: //!Returns true if both point to Chris@16: //!the same object Chris@16: bool equal(const self_t &y) const Chris@16: { return this->to_raw_pointer() == y.to_raw_pointer(); } Chris@16: Chris@16: //!Returns true if *this is less than other. Chris@16: //!This only works with two basic_intersegment_ptr pointing Chris@16: //!to the same segment group. Otherwise undefined. Never throws Chris@16: bool less(const self_t &y) const Chris@16: { return this->to_raw_pointer() < y.to_raw_pointer(); } Chris@16: Chris@16: void swap(self_t &other) Chris@16: { Chris@16: void *ptr_this = this->to_raw_pointer(); Chris@16: void *ptr_other = other.to_raw_pointer(); Chris@16: other.set_from_pointer(ptr_this); Chris@16: this->set_from_pointer(ptr_other); Chris@16: } Chris@16: Chris@16: //!Sets the object internals to represent the Chris@16: //!address pointed by ptr Chris@16: void set_from_pointer(const void *ptr) Chris@16: { Chris@16: if(!ptr){ Chris@16: this->set_null(); Chris@16: return; Chris@16: } Chris@16: Chris@16: std::size_t mode = this->get_mode(); Chris@16: if(mode == is_in_stack){ Chris@16: members.direct.addr = const_cast(ptr); Chris@16: return; Chris@16: } Chris@16: if(mode == is_relative){ Chris@16: char *beg_addr = static_cast(this->relative_calculate_begin_addr()); Chris@16: std::size_t seg_size = this->relative_size(); Chris@16: if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){ Chris@16: members.relative.off = static_cast(ptr) - reinterpret_cast(this); Chris@16: return; Chris@16: } Chris@16: } Chris@16: std::size_t ptr_offset; Chris@16: std::size_t this_offset; Chris@16: segment_info_t ptr_info; Chris@16: segment_info_t this_info; Chris@16: void *ptr_base; Chris@16: void *this_base; Chris@16: get_segment_info_and_offset(this, this_info, this_offset, this_base); Chris@16: Chris@16: if(!this_info.group){ Chris@16: this->set_mode(is_in_stack); Chris@16: this->members.direct.addr = const_cast(ptr); Chris@16: } Chris@16: else{ Chris@16: get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base); Chris@16: Chris@16: if(ptr_info.group != this_info.group){ Chris@16: this->set_mode(is_pointee_outside); Chris@16: this->members.direct.addr = const_cast(ptr); Chris@16: } Chris@16: else if(ptr_info.id == this_info.id){ Chris@16: this->set_mode(is_relative); Chris@16: members.relative.off = (static_cast(ptr) - reinterpret_cast(this)); Chris@16: this->relative_set_begin_from_base(this_base); Chris@16: std::size_t pow, frc; Chris@16: std::size_t s = calculate_size(this_info.size, pow, frc); Chris@16: (void)s; Chris@16: BOOST_ASSERT(this_info.size == s); Chris@16: this->members.relative.pow = pow; Chris@16: this->members.relative.frc = frc; Chris@16: } Chris@16: else{ Chris@16: this->set_mode(is_segmented); Chris@16: this->members.segmented.segment = ptr_info.id; Chris@16: this->members.segmented.off = ptr_offset; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: //!Sets the object internals to represent the address pointed Chris@16: //!by another flat_map_intersegment Chris@16: void set_from_other(const self_t &other) Chris@16: { Chris@16: this->set_from_pointer(other.to_raw_pointer()); Chris@16: } Chris@16: Chris@16: //!Increments internal Chris@16: //!offset Chris@16: void inc_offset(std::ptrdiff_t bytes) Chris@16: { Chris@16: this->set_from_pointer(static_cast(this->to_raw_pointer()) + bytes); Chris@16: } Chris@16: Chris@16: //!Decrements internal Chris@16: //!offset Chris@16: void dec_offset(std::ptrdiff_t bytes) Chris@16: { Chris@16: this->set_from_pointer(static_cast(this->to_raw_pointer()) - bytes); Chris@16: } Chris@16: Chris@16: ////////////////////////////////////// Chris@16: ////////////////////////////////////// Chris@16: ////////////////////////////////////// Chris@16: Chris@16: flat_map_intersegment() Chris@16: : intersegment_base() Chris@16: {} Chris@16: Chris@16: ~flat_map_intersegment() Chris@16: {} Chris@16: Chris@16: private: Chris@16: Chris@16: class segment_group_t Chris@16: { Chris@16: struct segment_data Chris@16: { Chris@16: void *addr; Chris@16: std::size_t size; Chris@16: }; Chris@16: vector m_segments; Chris@16: multi_segment_services &m_ms_services; Chris@16: Chris@16: public: Chris@16: segment_group_t(multi_segment_services &ms_services) Chris@16: : m_ms_services(ms_services) Chris@16: {} Chris@16: Chris@16: void push_back(void *addr, std::size_t size) Chris@16: { Chris@16: segment_data d = { addr, size }; Chris@16: m_segments.push_back(d); Chris@16: } Chris@16: Chris@16: void pop_back() Chris@16: { Chris@16: BOOST_ASSERT(!m_segments.empty()); Chris@16: m_segments.erase(--m_segments.end()); Chris@16: } Chris@16: Chris@16: Chris@16: void *address_of(std::size_t segment_id) Chris@16: { Chris@16: BOOST_ASSERT(segment_id < (std::size_t)m_segments.size()); Chris@16: return m_segments[segment_id].addr; Chris@16: } Chris@16: Chris@16: void clear_segments() Chris@16: { m_segments.clear(); } Chris@16: Chris@16: std::size_t get_size() const Chris@16: { return m_segments.size(); } Chris@16: Chris@16: multi_segment_services &get_multi_segment_services() const Chris@16: { return m_ms_services; } Chris@16: Chris@16: friend bool operator< (const segment_group_t&l, const segment_group_t &r) Chris@16: { return &l.m_ms_services < &r.m_ms_services; } Chris@16: }; Chris@16: Chris@16: struct segment_info_t Chris@16: { Chris@16: std::size_t size; Chris@16: std::size_t id; Chris@16: segment_group_t *group; Chris@16: segment_info_t() Chris@16: : size(0), id(0), group(0) Chris@16: {} Chris@16: }; Chris@16: Chris@16: typedef set segment_groups_t; Chris@16: Chris@16: typedef boost::interprocess::flat_map Chris@16: > ptr_to_segment_info_t; Chris@16: Chris@16: struct mappings_t : Mutex Chris@16: { Chris@16: //!Mutex to preserve integrity in multi-threaded Chris@16: //!enviroments Chris@16: typedef Mutex mutex_type; Chris@16: //!Maps base addresses and segment information Chris@16: //!(size and segment group and id)* Chris@16: Chris@16: ptr_to_segment_info_t m_ptr_to_segment_info; Chris@16: Chris@16: ~mappings_t() Chris@16: { Chris@16: //Check that all mappings have been erased Chris@16: BOOST_ASSERT(m_ptr_to_segment_info.empty()); Chris@16: } Chris@16: }; Chris@16: Chris@16: //Static members Chris@16: static mappings_t s_map; Chris@16: static segment_groups_t s_groups; Chris@16: public: Chris@16: Chris@16: typedef segment_group_t* segment_group_id; Chris@16: Chris@16: //!Returns the segment and offset Chris@16: //!of an address Chris@16: static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base) Chris@16: { Chris@16: //------------------------------------------------------------------ Chris@16: boost::interprocess::scoped_lock lock(s_map); Chris@16: //------------------------------------------------------------------ Chris@16: base = 0; Chris@16: if(s_map.m_ptr_to_segment_info.empty()){ Chris@16: segment = segment_info_t(); Chris@16: offset = reinterpret_cast(ptr) - static_cast(0); Chris@16: return; Chris@16: } Chris@16: //Find the first base address greater than ptr Chris@16: typename ptr_to_segment_info_t::iterator it Chris@16: = s_map.m_ptr_to_segment_info.upper_bound(ptr); Chris@16: if(it == s_map.m_ptr_to_segment_info.begin()){ Chris@16: segment = segment_info_t(); Chris@16: offset = reinterpret_cast(ptr) - static_cast(0); Chris@16: } Chris@16: //Go to the previous one Chris@16: --it; Chris@16: char * segment_base = const_cast(reinterpret_cast(it->first)); Chris@16: std::size_t segment_size = it->second.size; Chris@16: Chris@16: if(segment_base <= reinterpret_cast(ptr) && Chris@16: (segment_base + segment_size) >= reinterpret_cast(ptr)){ Chris@16: segment = it->second; Chris@16: offset = reinterpret_cast(ptr) - segment_base; Chris@16: base = segment_base; Chris@16: } Chris@16: else{ Chris@16: segment = segment_info_t(); Chris@16: offset = reinterpret_cast(ptr) - static_cast(0); Chris@16: } Chris@16: } Chris@16: Chris@16: //!Associates a segment defined by group/id with a base address and size. Chris@16: //!Returns false if the group is not found or there is an error Chris@16: static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size) Chris@16: { Chris@16: //------------------------------------------------------------------ Chris@16: boost::interprocess::scoped_lock lock(s_map); Chris@16: //------------------------------------------------------------------ Chris@16: Chris@16: typedef typename ptr_to_segment_info_t::value_type value_type; Chris@16: typedef typename ptr_to_segment_info_t::iterator iterator; Chris@16: typedef std::pair it_b_t; Chris@16: Chris@16: segment_info_t info; Chris@16: info.group = group_id; Chris@16: info.size = size; Chris@16: info.id = group_id->get_size(); Chris@16: Chris@16: it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info)); Chris@16: BOOST_ASSERT(ret.second); Chris@16: Chris@16: value_eraser v_eraser(s_map.m_ptr_to_segment_info, ret.first); Chris@16: group_id->push_back(ptr, size); Chris@16: v_eraser.release(); Chris@16: } Chris@16: Chris@16: static bool erase_last_mapping(segment_group_id group_id) Chris@16: { Chris@16: //------------------------------------------------------------------ Chris@16: boost::interprocess::scoped_lock lock(s_map); Chris@16: //------------------------------------------------------------------ Chris@16: if(!group_id->get_size()){ Chris@16: return false; Chris@16: } Chris@16: else{ Chris@16: void *addr = group_id->address_of(group_id->get_size()-1); Chris@16: group_id->pop_back(); Chris@16: std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr); Chris@16: (void)erased; Chris@16: BOOST_ASSERT(erased); Chris@16: return true; Chris@16: } Chris@16: } Chris@16: Chris@16: static segment_group_id new_segment_group(multi_segment_services *services) Chris@16: { Chris@16: { //------------------------------------------------------------------ Chris@16: boost::interprocess::scoped_lock lock(s_map); Chris@16: //------------------------------------------------------------------ Chris@16: typedef typename segment_groups_t::iterator iterator; Chris@16: std::pair ret = Chris@16: s_groups.insert(segment_group_t(*services)); Chris@16: BOOST_ASSERT(ret.second); Chris@16: return &*ret.first; Chris@16: } Chris@16: } Chris@16: Chris@16: static bool delete_group(segment_group_id id) Chris@16: { Chris@16: { //------------------------------------------------------------------ Chris@16: boost::interprocess::scoped_lock lock(s_map); Chris@16: //------------------------------------------------------------------ Chris@16: bool success = 1u == s_groups.erase(segment_group_t(*id)); Chris@16: if(success){ Chris@16: typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it; Chris@16: ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin()); Chris@16: while(it != s_map.m_ptr_to_segment_info.end()){ Chris@16: if(it->second.group == id){ Chris@16: it = s_map.m_ptr_to_segment_info.erase(it); Chris@16: } Chris@16: else{ Chris@16: ++it; Chris@16: } Chris@16: } Chris@16: } Chris@16: return success; Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: //!Static map-segment_info associated with Chris@16: //!flat_map_intersegment<> Chris@16: template Chris@16: typename flat_map_intersegment::mappings_t Chris@16: flat_map_intersegment::s_map; Chris@16: Chris@16: //!Static segment group container associated with Chris@16: //!flat_map_intersegment<> Chris@16: template Chris@16: typename flat_map_intersegment::segment_groups_t Chris@16: flat_map_intersegment::s_groups; Chris@16: Chris@16: //!A smart pointer that can point to a pointee that resides in another memory Chris@16: //!memory mapped or shared memory segment. Chris@16: template Chris@16: class intersegment_ptr : public flat_map_intersegment Chris@16: { Chris@16: typedef flat_map_intersegment PT; Chris@16: typedef intersegment_ptr self_t; Chris@16: typedef PT base_t; Chris@16: Chris@16: void unspecified_bool_type_func() const {} Chris@16: typedef void (self_t::*unspecified_bool_type)() const; Chris@16: Chris@16: public: Chris@16: typedef T * pointer; Chris@16: typedef typename ipcdetail::add_reference::type reference; Chris@16: typedef T value_type; Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: typedef std::random_access_iterator_tag iterator_category; Chris@16: Chris@16: public: //Public Functions Chris@16: Chris@16: //!Constructor from raw pointer (allows "0" pointer conversion). Chris@16: //!Never throws. Chris@16: intersegment_ptr(pointer ptr = 0) Chris@16: { base_t::set_from_pointer(ptr); } Chris@16: Chris@16: //!Constructor from other pointer. Chris@16: //!Never throws. Chris@16: template Chris@16: intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); } Chris@16: Chris@16: //!Constructor from other intersegment_ptr Chris@16: //!Never throws Chris@16: intersegment_ptr(const intersegment_ptr& ptr) Chris@16: { base_t::set_from_other(ptr); } Chris@16: Chris@16: //!Constructor from other intersegment_ptr. If pointers of pointee types are Chris@16: //!convertible, intersegment_ptrs will be convertibles. Never throws. Chris@16: template Chris@16: intersegment_ptr(const intersegment_ptr &ptr) Chris@16: { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } Chris@16: Chris@16: //!Emulates static_cast operator. Chris@16: //!Never throws. Chris@16: template Chris@16: intersegment_ptr(const intersegment_ptr &r, ipcdetail::static_cast_tag) Chris@16: { base_t::set_from_pointer(static_cast(r.get())); } Chris@16: Chris@16: //!Emulates const_cast operator. Chris@16: //!Never throws. Chris@16: template Chris@16: intersegment_ptr(const intersegment_ptr &r, ipcdetail::const_cast_tag) Chris@16: { base_t::set_from_pointer(const_cast(r.get())); } Chris@16: Chris@16: //!Emulates dynamic_cast operator. Chris@16: //!Never throws. Chris@16: template Chris@16: intersegment_ptr(const intersegment_ptr &r, ipcdetail::dynamic_cast_tag) Chris@16: { base_t::set_from_pointer(dynamic_cast(r.get())); } Chris@16: Chris@16: //!Emulates reinterpret_cast operator. Chris@16: //!Never throws. Chris@16: template Chris@16: intersegment_ptr(const intersegment_ptr &r, ipcdetail::reinterpret_cast_tag) Chris@16: { base_t::set_from_pointer(reinterpret_cast(r.get())); } Chris@16: Chris@16: //!Obtains raw pointer from offset. Chris@16: //!Never throws. Chris@16: pointer get()const Chris@16: { return static_cast(base_t::to_raw_pointer()); } Chris@16: Chris@16: //!Pointer-like -> operator. It can return 0 pointer. Chris@16: //!Never throws. Chris@16: pointer operator->() const Chris@16: { return self_t::get(); } Chris@16: Chris@16: //!Dereferencing operator, if it is a null intersegment_ptr behavior Chris@16: //!is undefined. Never throws. Chris@16: reference operator* () const Chris@16: { return *(self_t::get()); } Chris@16: Chris@16: //!Indexing operator. Chris@16: //!Never throws. Chris@16: reference operator[](std::ptrdiff_t idx) const Chris@16: { return self_t::get()[idx]; } Chris@16: Chris@16: //!Assignment from pointer (saves extra conversion). Chris@16: //!Never throws. Chris@16: intersegment_ptr& operator= (pointer from) Chris@16: { base_t::set_from_pointer(from); return *this; } Chris@16: Chris@16: //!Assignment from other intersegment_ptr. Chris@16: //!Never throws. Chris@16: intersegment_ptr& operator= (const intersegment_ptr &ptr) Chris@16: { base_t::set_from_other(ptr); return *this; } Chris@16: Chris@16: //!Assignment from related intersegment_ptr. If pointers of pointee types Chris@16: //!are assignable, intersegment_ptrs will be assignable. Never throws. Chris@16: template Chris@16: intersegment_ptr& operator= (const intersegment_ptr & ptr) Chris@16: { Chris@16: pointer p(ptr.get()); (void)p; Chris@16: base_t::set_from_other(ptr); return *this; Chris@16: } Chris@16: Chris@16: //!intersegment_ptr + std::ptrdiff_t. Chris@16: //!Never throws. Chris@16: intersegment_ptr operator+ (std::ptrdiff_t idx) const Chris@16: { Chris@16: intersegment_ptr result (*this); Chris@16: result.inc_offset(idx*sizeof(T)); Chris@16: return result; Chris@16: } Chris@16: Chris@16: //!intersegment_ptr - std::ptrdiff_t. Chris@16: //!Never throws. Chris@16: intersegment_ptr operator- (std::ptrdiff_t idx) const Chris@16: { Chris@16: intersegment_ptr result (*this); Chris@16: result.dec_offset(idx*sizeof(T)); Chris@16: return result; Chris@16: } Chris@16: Chris@16: //!intersegment_ptr += std::ptrdiff_t. Chris@16: //!Never throws. Chris@16: intersegment_ptr &operator+= (std::ptrdiff_t offset) Chris@16: { base_t::inc_offset(offset*sizeof(T)); return *this; } Chris@16: Chris@16: //!intersegment_ptr -= std::ptrdiff_t. Chris@16: //!Never throws. Chris@16: intersegment_ptr &operator-= (std::ptrdiff_t offset) Chris@16: { base_t::dec_offset(offset*sizeof(T)); return *this; } Chris@16: Chris@16: //!++intersegment_ptr. Chris@16: //!Never throws. Chris@16: intersegment_ptr& operator++ (void) Chris@16: { base_t::inc_offset(sizeof(T)); return *this; } Chris@16: Chris@16: //!intersegment_ptr++. Chris@16: //!Never throws. Chris@16: intersegment_ptr operator++ (int) Chris@16: { intersegment_ptr temp(*this); ++*this; return temp; } Chris@16: Chris@16: //!--intersegment_ptr. Chris@16: //!Never throws. Chris@16: intersegment_ptr& operator-- (void) Chris@16: { base_t::dec_offset(sizeof(T)); return *this; } Chris@16: Chris@16: //!intersegment_ptr--. Chris@16: //!Never throws. Chris@16: intersegment_ptr operator-- (int) Chris@16: { intersegment_ptr temp(*this); --*this; return temp; } Chris@16: Chris@16: //!Safe bool conversion operator. Chris@16: //!Never throws. Chris@16: operator unspecified_bool_type() const Chris@16: { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; } Chris@16: Chris@16: //!Not operator. Not needed in theory, but improves portability. Chris@16: //!Never throws. Chris@16: bool operator! () const Chris@16: { return base_t::is_null(); } Chris@16: Chris@101: //!Swaps two intersegment_ptr-s. More efficient than standard swap. Chris@16: //!Never throws. Chris@16: void swap(intersegment_ptr &other) Chris@16: { base_t::swap(other); } Chris@16: Chris@16: //!Calculates the distance between two intersegment_ptr-s. Chris@16: //!This only works with two basic_intersegment_ptr pointing Chris@16: //!to the same segment. Otherwise undefined Chris@16: template Chris@16: std::ptrdiff_t _diff(const intersegment_ptr &other) const Chris@16: { return base_t::diff(other); } Chris@16: Chris@16: //!Returns true if both point to the Chris@16: //!same object Chris@16: template Chris@16: bool _equal(const intersegment_ptr&other) const Chris@16: { return base_t::equal(other); } Chris@16: Chris@16: //!Returns true if *this is less than other. Chris@16: //!This only works with two basic_intersegment_ptr pointing Chris@16: //!to the same segment group. Otherwise undefined. Never throws Chris@16: template Chris@16: bool _less(const intersegment_ptr &other) const Chris@16: { return base_t::less(other); } Chris@16: }; Chris@16: Chris@16: //!Compares the equality of two intersegment_ptr-s. Chris@16: //!Never throws. Chris@16: template inline Chris@16: bool operator ==(const intersegment_ptr &left, Chris@16: const intersegment_ptr &right) Chris@16: { Chris@16: //Make sure both pointers can be compared Chris@16: bool e = typename intersegment_ptr::pointer(0) == Chris@16: typename intersegment_ptr::pointer(0); Chris@16: (void)e; Chris@16: return left._equal(right); Chris@16: } Chris@16: Chris@16: //!Returns true if *this is less than other. Chris@16: //!This only works with two basic_intersegment_ptr pointing Chris@16: //!to the same segment group. Otherwise undefined. Never throws Chris@16: template inline Chris@16: bool operator <(const intersegment_ptr &left, Chris@16: const intersegment_ptr &right) Chris@16: { Chris@16: //Make sure both pointers can be compared Chris@16: bool e = typename intersegment_ptr::pointer(0) < Chris@16: typename intersegment_ptr::pointer(0); Chris@16: (void)e; Chris@16: return left._less(right); Chris@16: } Chris@16: Chris@16: template inline Chris@16: bool operator!= (const intersegment_ptr &pt1, Chris@16: const intersegment_ptr &pt2) Chris@16: { return !(pt1 ==pt2); } Chris@16: Chris@16: //!intersegment_ptr <= intersegment_ptr. Chris@16: //!Never throws. Chris@16: template inline Chris@16: bool operator<= (const intersegment_ptr &pt1, Chris@16: const intersegment_ptr &pt2) Chris@16: { return !(pt1 > pt2); } Chris@16: Chris@16: //!intersegment_ptr > intersegment_ptr. Chris@16: //!Never throws. Chris@16: template inline Chris@16: bool operator> (const intersegment_ptr &pt1, Chris@16: const intersegment_ptr &pt2) Chris@16: { return (pt2 < pt1); } Chris@16: Chris@16: //!intersegment_ptr >= intersegment_ptr. Chris@16: //!Never throws. Chris@16: template inline Chris@16: bool operator>= (const intersegment_ptr &pt1, Chris@16: const intersegment_ptr &pt2) Chris@16: { return !(pt1 < pt2); } Chris@16: Chris@16: //!operator<< Chris@16: template inline Chris@16: std::basic_ostream & operator<< Chris@16: (std::basic_ostream & os, const intersegment_ptr & p) Chris@16: { return os << p.get(); } Chris@16: Chris@16: //!operator>> Chris@16: template inline Chris@16: std::basic_istream & operator>> Chris@16: (std::basic_istream & os, intersegment_ptr & p) Chris@16: { U * tmp; return os >> tmp; p = tmp; } Chris@16: Chris@16: //!std::ptrdiff_t + intersegment_ptr. Chris@16: //!The result is another pointer of the same segment Chris@16: template inline Chris@16: intersegment_ptr operator+ Chris@16: (std::ptrdiff_t diff, const intersegment_ptr& right) Chris@16: { return right + diff; } Chris@16: Chris@16: //!intersegment_ptr - intersegment_ptr. Chris@16: //!This only works with two intersegment_ptr-s that point to the Chris@16: //!same segment Chris@16: template inline Chris@16: std::ptrdiff_t operator- (const intersegment_ptr &pt, Chris@16: const intersegment_ptr &pt2) Chris@16: { return pt._diff(pt2)/sizeof(T); } Chris@16: Chris@16: //! swap specialization Chris@16: template inline Chris@16: void swap (boost::interprocess::intersegment_ptr &pt, Chris@16: boost::interprocess::intersegment_ptr &pt2) Chris@16: { pt.swap(pt2); } Chris@16: Chris@16: //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. Chris@16: //!Never throws. Chris@16: template inline Chris@16: T * to_raw_pointer(boost::interprocess::intersegment_ptr const & p) Chris@16: { return p.get(); } Chris@16: Chris@16: //!Simulation of static_cast between pointers. Chris@16: //!Never throws. Chris@16: template inline Chris@16: boost::interprocess::intersegment_ptr static_pointer_cast(const boost::interprocess::intersegment_ptr &r) Chris@16: { return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::static_cast_tag()); } Chris@16: Chris@16: //!Simulation of const_cast between pointers. Chris@16: //!Never throws. Chris@16: template inline Chris@16: boost::interprocess::intersegment_ptr const_pointer_cast(const boost::interprocess::intersegment_ptr &r) Chris@16: { return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::const_cast_tag()); } Chris@16: Chris@16: //!Simulation of dynamic_cast between pointers. Chris@16: //!Never throws. Chris@16: template inline Chris@16: boost::interprocess::intersegment_ptr dynamic_pointer_cast(const boost::interprocess::intersegment_ptr &r) Chris@16: { return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::dynamic_cast_tag()); } Chris@16: Chris@16: //!Simulation of reinterpret_cast between pointers. Chris@16: //!Never throws. Chris@16: template inline Chris@16: boost::interprocess::intersegment_ptr reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr &r) Chris@16: { return boost::interprocess::intersegment_ptr(r, boost::interprocess::ipcdetail::reinterpret_cast_tag()); } Chris@16: Chris@16: //!Trait class to detect if an smart pointer has Chris@16: //!multi-segment addressing capabilities. Chris@16: template Chris@16: struct is_multisegment_ptr Chris@16: > Chris@16: { Chris@16: static const bool value = true; Chris@16: }; Chris@16: Chris@16: } //namespace interprocess { Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER < 1400) Chris@16: //!to_raw_pointer() enables boost::mem_fn to recognize intersegment_ptr. Chris@16: //!Never throws. Chris@16: template inline Chris@16: T * to_raw_pointer(boost::interprocess::intersegment_ptr const & p) Chris@16: { return p.get(); } Chris@16: #endif Chris@16: Chris@16: //!has_trivial_constructor<> == true_type specialization Chris@16: //!for optimizations Chris@16: template Chris@16: struct has_trivial_constructor Chris@16: < boost::interprocess::intersegment_ptr > Chris@16: : public true_type{}; Chris@16: Chris@16: //!has_trivial_destructor<> == true_type specialization Chris@16: //!for optimizations Chris@16: template Chris@16: struct has_trivial_destructor Chris@16: < boost::interprocess::intersegment_ptr > Chris@16: : public true_type{}; Chris@16: Chris@16: } //namespace boost { Chris@16: Chris@16: #if 0 Chris@16: Chris@16: //bits Chris@16: //-> is_segmented Chris@16: //-> is_relative Chris@16: //-> is_in_stack Chris@16: //-> is_pointee_outside Chris@16: Chris@16: //Data Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: //segmented: Chris@16: // Chris@16: // std::size_t ctrl : CTRL_BITS; Chris@16: // std::size_t segment : MAX_SEGMENT_BITS; Chris@16: // std::size_t offset; Chris@16: Chris@16: //RELATIVE_SIZE_BITS = SIZE_T_BITS - Chris@16: // MAX_SEGMENT_BITS - Chris@16: // CTRL_BITS 10 10 Chris@16: //MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52 Chris@16: Chris@16: //SIZE_T_BITS - 1 - ALIGN_BITS 19 51 Chris@16: //POW_SIZE_BITS = upper_log2 Chris@16: // (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6 Chris@16: //FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS Chris@16: // MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5 Chris@16: Chris@16: //relative: Chris@16: // Chris@16: // std::size_t ctrl : CTRL_BITS; 2 2 Chris@16: // std::size_t size_pow : POW_SIZE_BITS 5 6 Chris@16: // std::size_t size_frc : FRC_SIZE_BITS; 6 5 Chris@16: // std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51 Chris@16: // std::ptrdiff_t distance : SIZE_T_BITS; 32 64 Chris@16: Chris@16: //direct: Chris@16: // Chris@16: // std::size_t ctrl : CTRL_BITS; 2 2 Chris@16: // std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62 Chris@16: // void *addr : SIZE_T_BITS; 32 64 Chris@16: Chris@16: //32 bits systems: Chris@16: //Page alignment: 2**12 Chris@16: // Chris@16: Chris@16: //!Obtains the address pointed by the Chris@16: //!object Chris@16: void *to_raw_pointer() const Chris@16: { Chris@16: if(this->is_pointee_outside() || this->is_in_stack()){ Chris@16: return raw_address(); Chris@16: } Chris@16: else if(this->is_relative()){ Chris@16: return (const_cast(reinterpret_cast(this))) + this->relative_pointee_offset(); Chris@16: } Chris@16: else{ Chris@16: group_manager *m = get_segment_group_manager(addr); Chris@16: char *base = static_cast(m->get_id_address(this->segmented_id())); Chris@16: return base + this->segmented_offset(); Chris@16: } Chris@16: } Chris@16: Chris@16: void set_from_pointer(const void *ptr) Chris@16: { Chris@16: if(!ptr){ Chris@16: this->set_pointee_outside(); Chris@16: this->raw_address(ptr); Chris@16: } Chris@16: else if(this->is_in_stack()){ Chris@16: this->raw_address(ptr); Chris@16: } Chris@16: else if(this->is_relative() && Chris@16: ( (ptr >= this->relative_start()) Chris@16: &&(ptr < this->relative_start() + this->relative_size())) Chris@16: ){ Chris@16: this->relative_offset(ptr - this); Chris@16: } Chris@16: else{ Chris@16: segment_info_t ptr_info = get_id_from_addr(ptr); Chris@16: segment_info_t this_info = get_id_from_addr(this); Chris@16: if(ptr_info.segment_group != this_info.segment_group){ Chris@16: if(!ptr_info.segment_group){ Chris@16: this->set_in_stack(); Chris@16: } Chris@16: else{ Chris@16: this->set_pointee_outside(); Chris@16: } Chris@16: } Chris@16: else if(ptr_info.segment_id == this_info.segment_id){ Chris@16: set_relative(); Chris@16: this->relative_size (ptr_info.size); Chris@16: this->relative_offset(static_cast(ptr) - reinterpret_cast(this)); Chris@16: this->relative_start (ptr_info.base); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: void set_from_other(const self_t &other) Chris@16: { this->set_from_pointer(other.to_raw_pointer()); } Chris@16: Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP