blob: f3e468f3ed1aca3d9f383406fee23fd4ae557f53 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
//
// (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