////////////////////////////////////////////////////////////////////////////// | |
// | |
// (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 | |