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