no message

[SVN r34285]
This commit is contained in:
Ion Gaztañaga
2006-06-12 17:23:18 +00:00
commit ae47bde018
113 changed files with 38998 additions and 0 deletions

96
.gitattributes vendored Normal file
View File

@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

View File

@@ -0,0 +1,875 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_INTERSEGMENT_PTR_HPP
#define BOOST_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/cast_tags.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <limits.h>
/*!\file
*/
namespace boost {
namespace interprocess {
/*!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
{
typedef flat_map_intersegment<Mutex> self_t;
typedef std::size_t offset_t;
typedef std::size_t segment_t;
/*!Returns true if object represents null pointer*/
bool is_null() const
{ return m_offset == ~offset_t(0); }
/*!Sets the object to represent the null pointer*/
void set_null()
{ m_offset = ~offset_t(0); }
/*!Sets the object internals to represent the address pointed by ptr*/
void set_from_pointer(const void *ptr)
{
if(!ptr){
set_null();
}
else{
segment_t id1, id2;
offset_t offset1, offset2;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(ptr, id1, offset1);
get_segment_and_offset(this, id2, offset2);
}
m_distance = id1 - id2;
m_offset = offset1;
}
}
/*!Sets the object internals to represent the address pointed
by another flat_map_intersegment*/
void set_from_other(const self_t &other)
{
if(other.is_null()){
set_null();
}
else{
segment_t id1, id2;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
offset_t off;
get_segment_and_offset(&other, id1, off);
get_segment_and_offset(this, id2, off);
}
m_distance = id1 + other.m_distance - id2;
m_offset = other.m_offset;
}
}
/*!Obtains the address pointed by the object*/
void *get_pointer() const
{
segment_t id1;
offset_t off;
void * base_addr = 0;
if(is_null()){
return base_addr;
}
else{
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(this, id1, off);
segment_t target_segment = segment_t(id1+m_distance);
base_addr = get_base_address(target_segment);
}
return detail::char_ptr_cast(base_addr) + m_offset;
}
}
/*!Swaps two objects efficiently*/
void swap(self_t &other)
{
//This specialized swap avoids some costly operations
segment_t id1, id2, id;
offset_t off;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(&other, id1, off);
get_segment_and_offset(this, id2, off);
}
//Swap offset value
off = m_offset; m_offset = other.m_offset; other.m_offset = off;
//Calculate new segment distance. Let overflow do its work
id = m_distance;
m_distance = id1 + other.m_distance - id2;
other.m_distance = id2 + id - id1;
}
/*!Increments internal offset*/
void inc_offset(offset_t bytes)
{ m_offset += bytes; }
/*!Decrements internal offset*/
void dec_offset(offset_t bytes)
{ m_offset -= bytes; }
/*!Calculates the distance between two basic_intersegment_ptr-s.
This only works with two basic_intersegment_ptr pointing
to the same segment. Otherwise undefined*/
offset_t diff(const self_t &other) const
{ return m_offset - other.m_offset; }
/*!Returns true if both point to the same object*/
bool equal(const self_t &y) const
{
if(m_offset != y.m_offset){
return false;
}
else{
segment_t id1, id2;
offset_t off;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(this, id1, off);
get_segment_and_offset(&y, id2, off);
}
return segment_t(id1 + m_distance) == segment_t(id2 + y.m_distance);
}
}
/*!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
{
segment_t id1, id2;
offset_t off;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(this, id1, off);
get_segment_and_offset(&y, id2, off);
}
id1 = segment_t(id1 + m_distance);
id2 = segment_t(id2 + y.m_distance);
return (id1 < id2) || (id1 == id2 && m_offset < y.m_offset);
}
//--------------------------------------------------------------------------
static void get_group_and_id(void *addr, std::size_t &group, std::size_t &id)
{
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(addr, group, id);
}
group = group >> s_shift;
}
/*!Returns the polymorphic multi-segment creator associated with a
segment-group. Returns 0 if not found or an error occurs.*/
static void* find_group_data(std::size_t group)
{
typedef typename mappings_t::group_to_data_t::iterator it_t;
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
it_t it(s_map.group_to_data.find(group));
if(it == s_map.group_to_data.end()){
return 0;
}
return it->second;
}
/*!Reserves a segment-group, installs the associated polymorphic
segment-creator, and the segment passed as (base, size) as
the segment id = 0 of the new group. Returns the group that will
be associated with this segment. Returns 0 if there are no available
groups or an error occurs.*/
static std::size_t new_group(void *group_data)
{
typedef typename mappings_t::group_to_data_t::iterator it_t;
typedef typename mappings_t::group_to_data_t::value_type value_type;
typedef std::pair<it_t, bool> insert_ret;
std::size_t group = 0;
BOOST_TRY{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
//Check if there are too many groups
if(s_map.group_to_data.size() >= (s_max_value - 1) ){
return 0;
}
//Check if there are no registered groups or the first one
//is not group 1, assign id 1 to the new group.
else if(s_map.group_to_data.empty() ||
s_map.group_to_data.begin()->first != 1){
group = 1;
}
//If not, take a not used number
else{
it_t it1(s_map.group_to_data.begin()),
it2(it1),
itend(s_map.group_to_data.end());
for(++it2; it2 != itend; ++it1, ++it2){
if(it2->first - it1->first > 1){
break;
}
}
group = it1->first+1;
}
insert_ret ret =
s_map.group_to_data.insert(value_type(group, group_data));
//This insertion must succeed
assert(ret.second);
if(!ret.second) return false;
return group;
}
BOOST_CATCH(const std::bad_alloc &){}
BOOST_CATCH_END
return 0;
}
/*!Erases the mapping between a group and the associated polymorphic pointer.
Returns false if the group is not found or there is an error*/
static bool delete_group(std::size_t group)
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
typedef typename mappings_t::segment_to_ptr_t::iterator it_t;
//Find the range of the group
it_t first_of_group(s_map.segment_to_ptr.lower_bound(group << s_shift));
it_t one_past_group(s_map.segment_to_ptr.lower_bound((group+1)<< s_shift));
//Erase all info related to the group
for(it_t it(first_of_group); it != one_past_group; ++it){
//Erase entry from addr-segment
if(!s_map.ptr_to_segment.erase(it->second)){
//This can't be possible since both indexes should be synchronized
assert(false);
return false;
}
}
//Erase all info from groups
s_map.segment_to_ptr.erase(first_of_group, one_past_group);
//Erase the group info
bool ret = s_map.group_to_data.erase(group) == 1;
assert(ret);
if(!ret) return false;
//Erase all mappings of this group
return true;
}
/*!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 bool insert_mapping(std::size_t group, std::size_t id,
void *base_address, std::size_t size)
{
//Check limits
if(group > s_max_value || id > s_max_value){
return false;
}
BOOST_TRY{
typedef typename mappings_t::ptr_to_segment_t::value_type ptr_to_segment_val_t;
typedef typename mappings_t::segment_to_ptr_t::value_type segment_to_ptr_val_t;
typedef typename mappings_t::ptr_to_segment_t::iterator ptr_to_segment_it_t;
typedef typename mappings_t::segment_to_ptr_t::iterator segment_to_ptr_it_t;
typedef std::pair<ptr_to_segment_it_t, bool> ptr_to_segment_ret_t;
typedef std::pair<segment_to_ptr_it_t, bool> segment_to_ptr_ret_t;
//Compose segment identification
segment_t segment = (group << s_shift) | id;
typename mappings_t:: segment_info_t segment_info;
segment_info.segment = segment;
segment_info.size = size;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
//This can throw
ptr_to_segment_ret_t ptr_to_segment_ret =
s_map.ptr_to_segment.insert(ptr_to_segment_val_t(base_address, segment_info));
if(!ptr_to_segment_ret.second)
return false;
//Node eraser will erase the node if an exception occurs
detail::value_eraser<typename mappings_t::ptr_to_segment_t>
value_eraser(s_map.ptr_to_segment, ptr_to_segment_ret.first);
//This can throw
segment_to_ptr_ret_t segment_to_ptr_ret =
s_map.segment_to_ptr.insert(segment_to_ptr_val_t(segment, base_address));
if(!segment_to_ptr_ret.second){
//This should never occur, since both maps must have
//the same elements indexed by different key
assert(!segment_to_ptr_ret.second);
return false;
}
//Insertion ok, release value_eraser
value_eraser.release();
return true;
}
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
}
static bool erase_mapping(void *base_address)
{
typedef typename mappings_t::ptr_to_segment_t::iterator ptr_to_segment_it_t;
typedef typename mappings_t::segment_to_ptr_t::iterator segment_to_ptr_it_t;
{ //------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
ptr_to_segment_it_t ptr_to_segment_it = s_map.ptr_to_segment.find(base_address);
if(ptr_to_segment_it == s_map.ptr_to_segment.end()){
//This group/id is not an valid entry
assert(ptr_to_segment_it == s_map.ptr_to_segment.end());
return false;
}
//Obtain segment
segment_t segment = ptr_to_segment_it->second.segment;
//Erase node from map
s_map.ptr_to_segment.erase(ptr_to_segment_it);
//Erase entry in the second map
if(!s_map.segment_to_ptr.erase(segment)){
//This can't be possible since both indexes should be synchronized
assert(false);
return false;
}
}
return true;
}
static bool erase_mapping(std::size_t group, std::size_t id)
{
//Check limits
if(group > s_max_value || id > s_max_value){
return false;
}
typedef typename mappings_t::ptr_to_segment_t::iterator ptr_to_segment_it_t;
typedef typename mappings_t::segment_to_ptr_t::iterator segment_to_ptr_it_t;
//Compose segment identification
segment_t segment = (group << s_shift) | id;
{ //------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
segment_to_ptr_it_t segment_to_ptr_it = s_map.segment_to_ptr.find(segment);
if(segment_to_ptr_it == s_map.segment_to_ptr.end()){
//This group/id is not an valid entry
assert(segment_to_ptr_it != s_map.segment_to_ptr.end());
return false;
}
//Obtain address
void *address = segment_to_ptr_it->second;
//Erase node from map
s_map.segment_to_ptr.erase(segment_to_ptr_it);
//Erase entry in the second map
if(!s_map.ptr_to_segment.erase(address)){
//This can't be possible since both indexes should be synchronized
assert(false);
return false;
}
}
return true;
}
private:
/*!Half of the bits are for group id and the
other half for the index inside the group
unsigned group : sizeof(std::size_t)/2;
unsigned index : sizeof(std::size_t)/2;*/
segment_t m_distance;
offset_t m_offset;
struct mappings_t : Mutex
{
struct segment_info_t
{
std::size_t size;
segment_t segment;
};
/*!Mutex to preserve integrity in multi-threaded enviroments*/
typedef Mutex mutex_t;
/*!Maps base addresses and segment information
(size and segment group and id)*/
typedef boost::interprocess::flat_map
<const void *
,segment_info_t
,std::less<const void *> > ptr_to_segment_t;
/*!Maps segment group/id with base addresses*/
typedef boost::interprocess::flat_map
<segment_t, void *> segment_to_ptr_t;
/*!Maps segment group with a polymorphic multi-segment creator
that knows how to create new segments*/
typedef boost::interprocess::flat_map
<segment_t, void*> group_to_data_t;
ptr_to_segment_t ptr_to_segment;
segment_to_ptr_t segment_to_ptr;
group_to_data_t group_to_data;
~mappings_t()
{
//Check that all mappings have been erased
assert(ptr_to_segment.empty());
assert(segment_to_ptr.empty());
assert(group_to_data.empty());
}
};
//Static members
static mappings_t s_map;
static const std::size_t s_shift = sizeof(std::size_t)*CHAR_BIT/2;
static const std::size_t s_max_value = std::size_t(1) << s_shift;
private:
/*!Returns the segment and offset of an address*/
static void get_segment_and_offset(const void *ptr, segment_t &segment, offset_t &offset)
{
if(s_map.ptr_to_segment.empty()){
segment = 0;
offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast();
}
//Find the first base address greater than ptr
typename mappings_t::ptr_to_segment_t::iterator it
= s_map.ptr_to_segment.upper_bound(ptr);
if(it == s_map.ptr_to_segment.begin()){
segment = 0;
offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast();
}
//Go to the previous one
--it;
char * segment_base = detail::char_ptr_cast(it->first);
std::size_t segment_size = it->second.size;
if(segment_base <= detail::char_ptr_cast(ptr) &&
(segment_base + segment_size) >= detail::char_ptr_cast(ptr)){
segment = it->second.segment;
offset = detail::char_ptr_cast(ptr) - segment_base;
}
else{
segment = 0;
offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast();
}
}
/*!Returns the base address of a segment*/
static void *get_base_address(segment_t segment)
{
typename mappings_t::segment_to_ptr_t::iterator it
= s_map.segment_to_ptr.find(segment);
if(it == s_map.segment_to_ptr.end()){
return 0;
}
else{
return it->second;
}
}
};
/*!Static map-group associated with flat_map_intersegment<>*/
template <class Mutex>
typename flat_map_intersegment<Mutex>::mappings_t
flat_map_intersegment<Mutex>::s_map;
/*!Static constant that shows the number of bits to shift to obtain the
group part of segment_t type*/
template <class Mutex>
const std::size_t flat_map_intersegment<Mutex>::s_shift;
/*!Static constant that shows the number of bits to shift to obtain the
group part of segment_t type*/
template <class Mutex>
const std::size_t flat_map_intersegment<Mutex>::s_max_value;
/*!
A smart pointer that can point to a pointee that resides in another memory
memory mapped or shared memory segment.
*/
template <class T/*, class PT*/>
class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //: public PT
{
typedef flat_map_intersegment<interprocess_mutex> PT;
typedef boost::interprocess::workaround::random_it<T> random_it_t;
// typedef intersegment_ptr<T, PT> self_t;
typedef intersegment_ptr<T> self_t;
typedef PT base_t;
typedef typename random_it_t::const_pointer const_pointer_t;
typedef typename random_it_t::const_reference const_reference_t;
void unspecified_bool_type_func() const {}
typedef void (self_t::*unspecified_bool_type)() const;
public:
typedef typename random_it_t::pointer pointer;
typedef typename random_it_t::reference reference;
typedef typename random_it_t::value_type value_type;
typedef typename random_it_t::difference_type difference_type;
typedef typename random_it_t::iterator_category 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 */
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/*, PT*/> &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/*, PT*/> &r, detail::static_cast_tag)
//{ base_t::set_from_pointer(static_cast<T*>(r.get())); }
{
if(r.is_null()){
base_t::set_from_pointer(0);
}
else{
//Some dirty tricks to safe segment operations.
//Calculate pointer adjustment and adjust offset.
pointer ptr = reinterpret_cast<pointer>(this);
std::ptrdiff_t difference = detail::char_ptr_cast(static_cast<T*>(ptr)) -
detail::char_ptr_cast(ptr);
base_t::set_from_other(r);
base_t::inc_offset(difference*sizeof(T));
}
}
/*!Emulates const_cast operator. Never throws.*/
template<class U>
intersegment_ptr(const intersegment_ptr<U/*, PT*/> &r, detail::const_cast_tag)
{ base_t::set_from_pointer(const_cast<T*>(r.get())); }
/*
{
//Make sure const conversion is correct
pointer p = const_cast<pointer>((U*)0); (void)p;
base_t::set_from_other(r);
}*/
/*!Emulates dynamic_cast operator. Never throws.*/
template<class U>
intersegment_ptr(const intersegment_ptr<U/*, PT*/> &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/*, PT*/> &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 (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/*, PT*/> & 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>
bool _diff(const intersegment_ptr<T2/*, PT*/> &other) const
{ return base_t::less(other); }
/*!Returns true if both point to the same object*/
template <class T2>
bool _equal(const intersegment_ptr<T2/*, PT*/> &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/*, PT*/> &other) const
{ return base_t::less(other); }
};
/*!Compares the equality of two intersegment_ptr-s.
Never throws.*/
template <class T1, class T2/*, class PT1*/> inline
bool operator ==(const intersegment_ptr<T1/*, PT1*/> &left,
const intersegment_ptr<T2/*, PT1*/> &right)
{
//Make sure both pointers can be compared
bool e = typename intersegment_ptr<T1/*, PT1*/>::pointer(0) ==
typename intersegment_ptr<T2/*, PT1*/>::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/*, class PT1*/> inline
bool operator <(const intersegment_ptr<T1/*, PT1*/> &left,
const intersegment_ptr<T2/*, PT1*/> &right)
{
//Make sure both pointers can be compared
bool e = typename intersegment_ptr<T1/*, PT1*/>::pointer(0) <
typename intersegment_ptr<T2/*, PT1*/>::pointer(0);
(void)e;
return left._less(right);
}
template<class T1, class T2/*, class PT*/> inline
bool operator!= (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return !(pt1 ==pt2); }
/*!intersegment_ptr<T1> <= intersegment_ptr<T2, PT>. Never throws.*/
template<class T1, class T2/*, class PT*/> inline
bool operator<= (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return !(pt1 > pt2); }
/*!intersegment_ptr<T1> > intersegment_ptr<T2, PT>. Never throws.*/
template<class T1, class T2/*, class PT*/> inline
bool operator> (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return (pt2 < pt1); }
/*!intersegment_ptr<T1> >= intersegment_ptr<T2, PT>. Never throws.*/
template<class T1, class T2/*, class PT*/> inline
bool operator>= (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return !(pt1 < pt2); }
/*!operator<< */
template<class E, class T, class U/*, class PT*/> inline
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, const intersegment_ptr<U/*, PT*/> & p)
{ return os << p.get(); }
/*!operator>> */
template<class E, class T, class U/*, class PT*/> inline
std::basic_istream<E, T> & operator>>
(std::basic_istream<E, T> & os, intersegment_ptr<U/*, PT*/> & 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/*, class PT*/> inline
intersegment_ptr<T/*, PT*/> operator+
(std::ptrdiff_t diff, const intersegment_ptr<T/*, PT*/>& 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/*, class PT*/> inline
std::ptrdiff_t operator- (const intersegment_ptr<T/*, PT*/> &pt,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return pt._diff(pt2); }
/*! swap specialization */
template<class T/*, class PT*/> inline
void swap (boost::interprocess::intersegment_ptr<T/*, PT*/> &pt,
boost::interprocess::intersegment_ptr<T/*, PT*/> &pt2)
{ pt.swap(pt2); }
/*!get_pointer() enables boost::mem_fn to recognize intersegment_ptr.
Never throws.*/
template<class T/*, class PT*/> inline
T * get_pointer(boost::interprocess::intersegment_ptr<T/*, PT*/> const & p)
{ return p.get(); }
/*!Simulation of static_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> static_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::static_cast_tag()); }
/*!Simulation of const_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> const_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::const_cast_tag()); }
/*!Simulation of dynamic_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::dynamic_cast_tag()); }
/*!Simulation of reinterpret_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::reinterpret_cast_tag()); }
/*!Trait class to detect if an smart pointer has
multi-segment addressing capabilities.*/
template <class T/*, class PT*/>
struct is_multisegment_ptr
<boost::interprocess::intersegment_ptr<T/*, PT*/> >
{
enum { value = true };
};
} //namespace interprocess {
/*!has_trivial_constructor<> == true_type specialization for optimizations*/
template <class T/*, class PT*/>
struct has_trivial_constructor
< boost::interprocess::intersegment_ptr<T/*, PT*/> >
: public true_type{};
/*!has_trivial_destructor<> == true_type specialization for optimizations*/
template <class T/*, class PT*/>
struct has_trivial_destructor
< boost::interprocess::intersegment_ptr<T/*, PT*/> >
: public true_type{};
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERSEGMENT_PTR_HPP

View File

@@ -0,0 +1,376 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MANAGED_MULTI_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_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/detail/managed_memory_impl.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
#include <boost/detail/no_exceptions_support.hpp>
//#include <boost/interprocess/detail/multi_segment_services.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/shared_memory.hpp>
#include <list>
#include <new>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/streams/vectorstream.hpp>
#include <memory>
/*!\file
Describes a named shared memory object allocation user class.
*/
namespace boost {
namespace interprocess {
/*!A basic shared memory named object creation class. Initializes the
shared memory segment. Inherits all basic functionality from
basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>*/
template
<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_multi_shared_memory
: public detail::basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType>
{
typedef basic_managed_multi_shared_memory
<CharType, MemoryAlgorithm, IndexType> self_t;
typedef typename self_t::void_pointer void_pointer;
////////////////////////////////////////////////////////////////////////
//
// Some internal helper structs/functors
//
////////////////////////////////////////////////////////////////////////
/*!This class defines an operator() that creates a shared memory
of the requested size. The rest of the parameters are
passed in the constructor. The class a template parameter
to be used with create_from_file/create_from_istream functions
of basic_named_object classes*/
/*
class segment_creator
{
public:
segment_creator(shared_memory &shmem,
const char *mem_name,
const void *addr)
: m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
void *operator()(std::size_t size)
{
if(!m_shmem.create(m_mem_name, size, m_addr))
return 0;
return m_shmem.get_address();
}
private:
shared_memory &m_shmem;
const char *m_mem_name;
const void *m_addr;
};
*/
class group_services
{
public:
typedef std::pair<void *, std::size_t> result_type;
typedef basic_managed_multi_shared_memory frontend_t;
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
group_services(frontend_t *const frontend)
: mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
virtual std::pair<void *, std::size_t> create_new_segment(std::size_t alloc_size)
{
//We should allocate an extra byte so that the
//[base_addr + alloc_size] byte belongs to this segment
alloc_size += 1;
//If requested size is less than minimum, update that
alloc_size = (m_min_segment_size > alloc_size) ?
m_min_segment_size : alloc_size;
if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
alloc_size, 0)){
shmem_list_t::value_type &p_shm = *mp_frontend->m_shmem_list.rbegin();
return result_type(p_shm->get_address(), p_shm->get_size()-1);
}
return result_type(0, 0);
}
virtual ~group_services(){}
void set_group(std::size_t group)
{ m_group = group; }
std::size_t get_group() const
{ return m_group; }
void set_min_segment_size(std::size_t min_segment_size)
{ m_min_segment_size = min_segment_size; }
std::size_t get_min_segment_size() const
{ return m_min_segment_size; }
private:
frontend_t * const mp_frontend;
std::size_t m_group;
std::size_t m_min_segment_size;
};
/*!Functor to execute atomically when opening or creating a shared memory
segment.*/
struct create_open_func
{
enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
create_open_func(self_t * const frontend,
type_t type, std::size_t segment_number)
: mp_frontend(frontend), m_type(type), m_segment_number(segment_number){}
bool operator()(const mapped_region &region, bool created) const
{
if(((m_type == DoOpen) && created) ||
((m_type == DoCreate) && !created))
return false;
void *addr = region.get_address();
std::size_t size = region.get_size();
std::size_t group = mp_frontend->m_group_services.get_group();
bool mapped = false;
bool impl_done = false;
//Associate this newly created segment as the
//segment id = 0 of this group
if((mapped = void_pointer::insert_mapping(group, m_segment_number, addr, size))){
//Check if this is the master segment
if(!m_segment_number){
//Create or open the Interprocess machinery
if(impl_done = created ?
mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size)){
return true;
}
}
else{
return true;
}
}
//This is the cleanup part
//---------------
if(impl_done){
mp_frontend->close_impl();
}
if(mapped){
bool ret = void_pointer::erase_mapping(group, 0);
assert(ret);(void)ret;
}
return false;
}
self_t * const mp_frontend;
type_t m_type;
std::size_t m_segment_number;
};
/*!Functor to execute atomically when closing a shared memory segment.*/
struct close_func
{
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
close_func(self_t * const frontend)
: mp_frontend(frontend){}
void operator()(const mapped_region &region, bool last) const
{
if(last) mp_frontend->destroy_impl();
else mp_frontend->close_impl();
}
self_t * const mp_frontend;
};
typedef detail::basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType> base_t;
//Friend declarations
friend struct basic_managed_multi_shared_memory::create_open_func;
friend struct basic_managed_multi_shared_memory::close_func;
friend class basic_managed_multi_shared_memory::group_services;
typedef std::list<shared_memory*> shmem_list_t;
basic_managed_multi_shared_memory *get_this_pointer()
{ return this; }
public:
basic_managed_multi_shared_memory(detail::create_only_t,
const char *name,
std::size_t size)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoCreate,name, size);
}
basic_managed_multi_shared_memory(detail::open_or_create_t,
const char *name,
std::size_t size)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpenOrCreate, name, size);
}
basic_managed_multi_shared_memory(detail::open_only_t,
const char *name)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpen, name, 0);
}
~basic_managed_multi_shared_memory()
{ this->priv_close(); }
private:
bool priv_open_or_create(typename create_open_func::type_t type,
const char *name,
std::size_t size)
{
if(!m_shmem_list.empty())
return false;
std::size_t group = 0;
BOOST_TRY{
m_root_name = name;
//Insert multi segment services and get a group identifier
group = void_pointer::new_group(static_cast<void*>(&m_group_services));
m_group_services.set_group(group);
m_group_services.set_min_segment_size(size);
if(group){
if(this->priv_new_segment(type, size, 0)){
return true;
}
}
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
if(group){
void_pointer::delete_group(group);
}
return false;
}
bool priv_new_segment(typename create_open_func::type_t type,
std::size_t size,
const void *addr)
{
BOOST_TRY{
//Get the number of groups of this multi_segment group
std::size_t segment_id = m_shmem_list.size();
//Format the name of the shared memory: append segment number.
boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
formatter.seekp(std::ios::beg);
//Pre-reserve string size
std::size_t str_size = m_root_name.length()+10;
if(formatter.vector().size() < str_size){
//This can throw.
formatter.reserve(str_size);
}
//Format segment's name
formatter << m_root_name
<< static_cast<unsigned int>(segment_id) << std::ends;
//This functor will be executed when constructing
create_open_func func(this, type, segment_id);
const char *name = formatter.vector().c_str();
//This can throw.
std::auto_ptr<shared_memory> shm;
switch(type){
case create_open_func::DoCreate:
shm.reset(new shared_memory(create_only, name, size
,memory_mapping::rw_mode, addr, func));
break;
case create_open_func::DoOpen:
shm.reset(new shared_memory(open_only, name
,memory_mapping::rw_mode, addr, func));
break;
case create_open_func::DoOpenOrCreate:
shm.reset(new shared_memory( boost::interprocess::open_or_create
, name, size, memory_mapping::rw_mode
, addr, func));
break;
default:
return false;
break;
}
//This can throw.
m_shmem_list.push_back(shm.get());
//Anti-exception rollback
detail::value_eraser<shmem_list_t>
value_eraser(m_shmem_list, --m_shmem_list.end());
shm.release();
value_eraser.release();
return true;
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
return false;
}
/*!Frees resources. Never throws.*/
void priv_close()
{
if(!m_shmem_list.empty()){
bool ret;
//Obtain group identifier
std::size_t group = m_group_services.get_group();
//Erase main segment and its resources
shmem_list_t::iterator itbeg = m_shmem_list.begin(),
itend = m_shmem_list.end(),
it = itbeg;
//(*itbeg)->close_with_func(close_func(this));
//Delete group. All mappings are erased too.
ret = void_pointer::delete_group(group);
assert(ret);
//Now destroy all shared_memory segments so they
//are unmapped from the process
for(it = itbeg; it != itend; ++it) delete *it;
m_shmem_list.clear();
}
}
private:
shmem_list_t m_shmem_list;
group_services m_group_services;
std::string m_root_name;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_TYPE_COMMAND_HPP
#define BOOST_INTERPROCESS_TYPE_COMMAND_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
enum allocation_type_v
{
// constants for allocation commands
allocate_new_v = 0x01,
expand_fwd_v = 0x02,
expand_bwd_v = 0x04,
// expand_both = expand_fwd | expand_bwd,
// expand_or_new = allocate_new | expand_both,
shrink_in_place_v = 0x08,
nothrow_allocation_v = 0x10
};
typedef int allocation_type;
static const allocation_type allocate_new = (allocation_type)allocate_new_v;
static const allocation_type expand_fwd = (allocation_type)expand_fwd_v;
static const allocation_type expand_bwd = (allocation_type)expand_bwd_v;
static const allocation_type shrink_in_place = (allocation_type)shrink_in_place_v;
static const allocation_type nothrow_allocation = (allocation_type)nothrow_allocation_v;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_TYPE_COMMAND_HPP

View File

@@ -0,0 +1,223 @@
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_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/allocators/allocation_type.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/version_type.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
#include <stdexcept>
/*!\file
Describes an allocator that allocates portions of fixed size
memory buffer (shared memory, mapped file...)
*/
namespace boost {
namespace interprocess {
/*!An STL compatible allocator that uses a segment manager as
memory source. The internal pointer type will of the same type (raw, smart) as
"typename SegmentManager::void_pointer" type. This allows
placing the allocator in shared memory, memory mapped-files, etc...*/
template<class T, class SegmentManager>
class allocator
{
private:
/*!Self type*/
typedef allocator<T, SegmentManager> self_t;
/*!Segment manager*/
typedef SegmentManager segment_manager;
/*!Pointer to void */
typedef typename segment_manager::void_pointer aux_pointer_t;
/*!Typedef to const void pointer */
typedef typename
detail::template pointer_to_other
<aux_pointer_t, const void>::type cvoid_ptr;
/*!Pointer to the allocator*/
typedef typename detail::pointer_to_other
<cvoid_ptr, segment_manager>::type alloc_ptr_t;
/*!Not assignable from related allocator*/
template<class T2, class AllocAlgo2>
allocator& operator=(const allocator<T2, AllocAlgo2>&);
/*!Not assignable from other allocator*/
allocator& operator=(const allocator&);
/*!Pointer to the allocator*/
alloc_ptr_t mp_mngr;
public:
typedef T value_type;
typedef typename detail::pointer_to_other
<cvoid_ptr, T>::type pointer;
typedef typename detail::
pointer_to_other<pointer, const T>::type const_pointer;
typedef typename workaround::random_it
<value_type>::reference reference;
typedef typename workaround::random_it
<value_type>::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef detail::version_type<allocator, 2> version;
/*!Obtains an allocator of other type*/
template<class T2>
struct rebind
{
typedef allocator<T2, SegmentManager> other;
};
/*!Returns the segment manager. Never throws*/
segment_manager* get_segment_manager()const
{ return detail::get_pointer(mp_mngr); }
/*!Returns address of mutable object. Never throws*/
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
/*!Returns address of non mutable object. Never throws*/
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
/*!Constructor from the segment manager. Never throws*/
allocator(segment_manager *segment_mngr)
: mp_mngr(segment_mngr) { }
/*!Constructor from other allocator. Never throws*/
allocator(const allocator &other)
: mp_mngr(other.get_segment_manager()){ }
/*!Constructor from related allocator. Never throws*/
template<class T2>
allocator(const allocator<T2, SegmentManager> &other)
: mp_mngr(other.get_segment_manager()){}
/*!Allocates memory for an array of count elements.
Throws boost::interprocess::bad_alloc if there is no enough memory*/
pointer allocate(size_type count, cvoid_ptr hint = 0)
{ return pointer((value_type*)mp_mngr->allocate(count*sizeof(value_type))); }
/*!Deallocates memory previously allocated. Never throws*/
void deallocate(const pointer &ptr, size_type)
{ mp_mngr->deallocate(detail::get_pointer(ptr)); }
/*!Construct object, calling constructor.
Throws if T(const Convertible &) throws*/
template<class Convertible>
void construct(const pointer &ptr, const Convertible &value)
{ new(detail::get_pointer(ptr)) value_type(value); }
/*!Destroys object. Throws if object's destructor throws*/
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
/*!Returns the number of elements that could be allocated. Never throws*/
size_type max_size() const
{ return mp_mngr->get_size(); }
/*!Swap segment manager. Does not throw. If each allocator is placed in
different memory segments, the result is undefined.*/
friend void swap(self_t &alloc1, self_t &alloc2)
{ detail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); }
//Experimental version 2 allocator functions
std::pair<pointer, bool>
allocation_command(allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0)
{
std::size_t l_size = limit_size*sizeof(value_type);
std::size_t p_size = preferred_size*sizeof(value_type);
std::size_t r_size;
std::pair<void *, bool> result =
mp_mngr->allocation_command
(command, l_size, p_size, r_size, detail::get_pointer(reuse));
received_size = r_size/sizeof(value_type);
return std::pair<pointer, bool>
(static_cast<value_type*>(result.first), result.second);
}
/*!Returns maximum the number of objects the previously allocated memory
pointed by p can hold.*/
size_type size(const pointer &p) const
{
return (size_type)mp_mngr->size
(detail::get_pointer(p))/sizeof(value_type);
}
/*!Allocates just one object. Memory allocated with this function
must be deallocated only with deallocate_one().
Throws boost::interprocess::bad_alloc if there is no enough memory*/
pointer allocate_one()
{ return this->allocate(1); }
/*!Deallocates memory previously allocated with allocate_one().
You should never use deallocate_one to deallocate memory allocated
with other functions different from allocate_one(). Never throws*/
void deallocate_one(const pointer &p)
{ return this->deallocate(p, 1); }
};
/*!Equality test for same type of allocator*/
template<class T, class SegmentManager> inline
bool operator==(const allocator<T , SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
/*!Inequality test for same type of allocator*/
template<class T, class SegmentManager> inline
bool operator!=(const allocator<T, SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
/*!This specialization indicates that the construct function allows
convertible types to construct the value type. This allows
storing less allocator instances in containers.*/
template<class T, class SegmentManager>
struct has_convertible_construct
<boost::interprocess::allocator<T, SegmentManager> >
{
enum { value = true };
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP

View File

@@ -0,0 +1,429 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_CACHED_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_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/utility/addressof.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <memory>
#include <algorithm>
#include <stdio.h>
#include <cstddef>
/*!\file
Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
*/
namespace boost {
namespace interprocess {
/*!An STL node allocator that uses a segment manager as memory
source. The internal pointer type will of the same type (raw, smart) as
"typename SegmentManager::void_pointer" type. This allows
placing the allocator in shared memory, memory mapped-files, etc...
This node allocator shares a segregated storage between all instances of
cached_node_allocator with equal sizeof(T) placed in the same fixed size
memory segment. But also caches some nodes privately to
avoid some synchronization overhead.*/
template<class T, class SegmentManager>
class cached_node_allocator
{
enum { NumAlloc = 64 };
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename detail::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
typedef SegmentManager segment_manager;
typedef typename detail::
pointer_to_other<void_pointer, char>::type char_pointer;
typedef typename SegmentManager::mutex_family::mutex_t mutex_t;
typedef cached_node_allocator<T, SegmentManager> self_t;
enum { DEFAULT_MAX_CACHED_NODES = 64 };
public:
//-------
typedef typename detail::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename detail::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename workaround::random_it
<value_type>::reference reference;
typedef typename workaround::random_it
<value_type>::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
/*!Obtains cached_node_allocator from other cached_node_allocator*/
template<class T2>
struct rebind
{
typedef cached_node_allocator<T2, SegmentManager> other;
};
private:
/*!Not assignable from related cached_node_allocator*/
template<class T2, class AllogAlgo2>
cached_node_allocator& operator=
(const cached_node_allocator<T2, AllogAlgo2>&);
/*!Not assignable from other cached_node_allocator*/
cached_node_allocator& operator=(const cached_node_allocator&);
public:
/*!Constructor from a segment manager. If not present, constructs
a node pool. Increments the reference count of the node pool.
Can throw boost::interprocess::bad_alloc*/
cached_node_allocator(segment_manager *segment_mngr,
std::size_t max_cached_nodes = DEFAULT_MAX_CACHED_NODES)
: mp_node_pool(priv_get_or_create(segment_mngr)),
mp_cached(0),
m_cached_nodes(0),
m_max_cached_nodes(max_cached_nodes)
{ }
/*!Copy constructor from other cached_node_allocator. Increments the
reference count of the associated node pool. Never throws*/
cached_node_allocator(const cached_node_allocator &other)
: mp_node_pool(other.get_node_pool()),
mp_cached(0),
m_cached_nodes(0),
m_max_cached_nodes(other.get_max_cached_nodes())
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>(other.get_node_pool());
node_pool->inc_ref_count();
}
/*!Copy constructor from related cached_node_allocator. If not present, constructs
a node pool. Increments the reference count of the associated node pool.
Can throw boost::interprocess::bad_alloc*/
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager> &other)
: mp_node_pool(priv_get_or_create(other.get_segment_manager())),
mp_cached(0),
m_cached_nodes(0),
m_max_cached_nodes(other.get_max_cached_nodes())
{ }
/*!Destructor, removes node_pool_t from memory
if its reference count reaches to zero. Never throws*/
~cached_node_allocator()
{
priv_deallocate_all_cached_nodes();
priv_destroy_if_last_link();
}
/*!Returns a pointer to the node pool. Never throws*/
void* get_node_pool() const
{ return detail::get_pointer(mp_node_pool); }
/*!Returns the segment manager. Never throws*/
segment_manager* get_segment_manager()const
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>(detail::get_pointer(mp_node_pool));
return node_pool->get_segment_manager();
}
/*!Sets the new max cached nodes value. This can provoke deallocations
if "newmax" is less than current cached nodes. Never throws*/
void set_max_cached_nodes(std::size_t newmax)
{
m_max_cached_nodes = newmax;
priv_deallocate_remaining_nodes();
}
/*!Returns the max cached nodes parameter. Never throws*/
std::size_t get_max_cached_nodes() const
{ return m_max_cached_nodes; }
/*!Return address of mutable value. Never throws*/
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
/*!Return address of non mutable value. Never throws*/
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
/*!Construct object, calling constructor.
Throws if T(const Convertible &) throws*/
template<class Convertible>
void construct(const pointer &ptr, const Convertible &value)
{ new(detail::get_pointer(ptr)) value_type(value); }
/*!Destroys object. Throws if object's destructor throws*/
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
/*!Returns the number of elements that could be allocated. Never throws*/
size_type max_size() const
{ return this->get_segment_manager()->get_size(); }
/*!Allocate memory for an array of count elements.
Throws boost::interprocess::bad_alloc if there is no enough memory*/
pointer allocate(size_type count, cvoid_pointer hint = 0)
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
void * ret;
if(count == 1){
//If don't have any cached node, we have to get a null
//terminated linked list of n nodes from the pool
if(!mp_cached){
node_pool_t *node_pool = static_cast<node_pool_t*>(detail::get_pointer(mp_node_pool));
mp_cached = detail::char_ptr_cast(node_pool->allocate_nodes(m_max_cached_nodes/2));
m_cached_nodes = m_max_cached_nodes/2;
}
//Get the first node
ret = detail::get_pointer(mp_cached);
mp_cached = node_pool_t::next_node(detail::get_pointer(mp_cached));
--m_cached_nodes;
}
else{
node_pool_t *node_pool = static_cast<node_pool_t*>(detail::get_pointer(mp_node_pool));
ret = node_pool->allocate(count);
}
return pointer(static_cast<T*>(ret));
}
/*!Deallocate allocated memory. Never throws*/
void deallocate(const pointer &ptr, size_type count)
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
if(count == 1){
//Check if cache is full
if(m_cached_nodes >= m_max_cached_nodes){
//This only occurs if this allocator deallocate memory allocated
//with other equal allocator. Since the cache is full, and more
//deallocations are probably coming, we'll make some room in cache
//in a single, efficient multi node deallocation.
priv_deallocate_n_nodes(m_cached_nodes - m_max_cached_nodes/2);
}
char *node = detail::char_ptr_cast(detail::get_pointer(ptr));
node_pool_t::next_node(detail::get_pointer(node)) = mp_cached;
mp_cached = node;
++m_cached_nodes;
}
else{
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
node_pool->deallocate(detail::get_pointer(ptr), count);
}
}
/*!Swaps allocators. Does not throw. If each allocator is placed in a
different shared memory segments, the result is undefined.*/
friend void swap(self_t &alloc1, self_t &alloc2)
{
detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool);
detail::do_swap(alloc1.mp_cached, alloc2.mp_cached);
detail::do_swap(alloc1.m_cached_nodes, alloc2.m_cached_nodes);
detail::do_swap(alloc1.m_max_cached_nodes, alloc2.m_max_cached_nodes);
}
void clear_cache()
{ this->priv_deallocate_all_cached_nodes(); }
private:
/*!Object function that creates the node allocator if it is not created and
increments reference count if it is already created*/
struct get_or_create_func
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
/*!This connects or constructs the unique instance of node_pool_t
Can throw boost::interprocess::bad_alloc*/
void operator()()
{
//Find or create the node_pool_t
mp_node_pool = mp_named_alloc->template find_or_construct
<node_pool_t>(unique_instance)(mp_named_alloc);
//If valid, increment link count
if(mp_node_pool != 0)
mp_node_pool->inc_ref_count();
}
/*!Constructor. Initializes function object parameters*/
get_or_create_func(segment_manager *hdr) : mp_named_alloc(hdr){}
node_pool_t *mp_node_pool;
segment_manager *mp_named_alloc;
};
/*!Frees all cached nodes. Never throws*/
void priv_deallocate_all_cached_nodes()
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
node_pool->deallocate_nodes(detail::get_pointer(mp_cached));
mp_cached = 0;
}
/*!Frees all cached nodes at once. Never throws*/
void priv_deallocate_remaining_nodes()
{
if(m_cached_nodes > m_max_cached_nodes){
priv_deallocate_n_nodes(m_cached_nodes);
}
}
/*!Frees n cached nodes at once. Never throws*/
void priv_deallocate_n_nodes(std::size_t n)
{
//Check n
if(n==0) return;
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), NumAlloc> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
//Create a new linked list of n nodes ending in null
//taking the first n bytes of cached nodes list
m_cached_nodes -= n;
char_pointer head = mp_cached, prev;
while(n--){
prev = mp_cached;
mp_cached = node_pool_t::next_node(detail::get_pointer(mp_cached));
}
node_pool_t::next_node(detail::get_pointer(prev)) = 0;
//Deallocate all new linked list at once
node_pool->deallocate_nodes(detail::get_pointer(head));
}
/*!Initialization function, creates an executes atomically the
initialization object functions. Can throw boost::interprocess::bad_alloc*/
void *priv_get_or_create(segment_manager *named_alloc)
{
get_or_create_func func(named_alloc);
named_alloc->atomic_func(func);
return func.mp_node_pool;
}
/*!Object function that decrements the reference count. If the count
reaches to zero destroys the node allocator from memory.
Never throws*/
struct destroy_if_last_link_func
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t,sizeof(T), NumAlloc> node_pool_t;
/*!Decrements reference count and destroys the object if there is no
more attached allocators. Never throws*/
void operator()()
{
//If not the last link return
if(mp_node_pool->dec_ref_count() != 0) return;
//Last link, let's destroy the segment_manager
mp_named_alloc->template destroy<node_pool_t>(unique_instance);
}
/*!Constructor. Initializes function object parameters*/
destroy_if_last_link_func(segment_manager *nhdr,
node_pool_t *phdr)
: mp_named_alloc(nhdr), mp_node_pool(phdr){}
segment_manager *mp_named_alloc;
node_pool_t *mp_node_pool;
};
/*!Destruction function, initializes and executes destruction function
object. Never throws*/
void priv_destroy_if_last_link()
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t,sizeof(T), NumAlloc> node_pool_t;
//Get segment manager
segment_manager *segment_mngr = this->get_segment_manager();
//Get pool pointer
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
//Execute destruction functor atomically
destroy_if_last_link_func func(segment_mngr, node_pool);
segment_mngr->atomic_func(func);
}
private:
// We can't instantiate a pointer like this:
// detail::shared_node_pool<SegmentManager, mutex_t,
// sizeof(T), NumAlloc> *mp_node_pool;
// since it can provoke an early instantiation of T, that could be
// incomplete at that moment (for example, a node of a node-based container)
// This provokes errors on some node based container implementations using
// this pooled allocator as this allocator type.
//
// Because of this, we will use a void offset pointer and we'll do some
//(ugly )casts when needed.
void_pointer mp_node_pool;
char_pointer mp_cached; //Ptr to the first cached node
std::size_t m_cached_nodes;
std::size_t m_max_cached_nodes;
};
/*!Equality test for same type of cached_node_allocator*/
template<class T, class A> inline
bool operator==(const cached_node_allocator<T, A> &alloc1,
const cached_node_allocator<T, A> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
/*!Inequality test for same type of cached_node_allocator*/
template<class T, class A> inline
bool operator!=(const cached_node_allocator<T, A> &alloc1,
const cached_node_allocator<T, A> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
/*!This specialization indicates that the construct function allows
convertible types to construct the value type. This allows
storing less allocator instances in containers.*/
template<class T, class SegmentManager>
struct has_convertible_construct
<boost::interprocess::cached_node_allocator<T, SegmentManager> >
{
enum { value = true };
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,341 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NODE_ALLOCATOR_ALGO_HPP
#define BOOST_INTERPROCESS_NODE_ALLOCATOR_ALGO_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/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/math/common_factor_ct.hpp>
#include <boost/noncopyable.hpp>
#include <cstddef>
#include <assert.h>
/*!\file
Describes the real pool allocator shared by many Interprocess pool allocators
*/
namespace boost {
namespace interprocess {
namespace detail {
/*!Pooled shared memory allocator using single segregated storage. Includes
a reference count but the class does not delete itself, this is
responsibility of user classes. Node size (NodeSize) and the number of
nodes allocated per chunk (NumAlloc) are known at compile time*/
template<class SegmentManager, std::size_t NodeSize, std::size_t NumAlloc >
class private_node_pool : private boost::noncopyable
{
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename pointer_to_other<void_pointer, char>::type char_ptr_t;
enum { RealNodeSize =
boost::math::static_lcm<NodeSize, sizeof(char_ptr_t)>::value };
enum { BlockSize =
detail::ct_rounded_size<RealNodeSize*NumAlloc, sizeof(char_ptr_t)>::value };
enum { ChunkSize = BlockSize + sizeof(char_ptr_t) };
public:
/*!Segment manager typedef*/
typedef SegmentManager segment_manager;
/*!Constructor from a segment manager. Never throws*/
private_node_pool(segment_manager *segment_mngr)
: //To indicate null, we set pointers to themselves
//General purpose allocator
mp_segment_mngr(segment_mngr),
mp_firstBlock(0),
mp_free(0),
//Debug node count
m_allocated(0),
m_free_nodes(0)
{}
/*!Destructor. Deallocates all allocated chunks. Never throws*/
~private_node_pool()
{ priv_clear(); }
/*!Returns the segment manager. Never throws*/
segment_manager* get_segment_manager()const
{ return mp_segment_mngr.get(); }
/*!Allocates array of count elements. Can throw boost::interprocess::bad_alloc*/
void *allocate(std::size_t count)
{
std::size_t bytes = count*NodeSize;
if(bytes > RealNodeSize)//Normal allocation, no pooling used
return mp_segment_mngr->allocate(bytes);
else //Node allocation, pooling used
return priv_alloc_node();
}
/*!Deallocates an array pointed by ptr. Never throws*/
void deallocate(void *ptr, std::size_t count)
{
std::size_t bytes = count*NodeSize;
if(bytes > RealNodeSize)//Normal allocation was used
mp_segment_mngr->deallocate(ptr);
else //Node allocation was used
priv_dealloc_node(ptr);
}
/*!Allocates a singly linked list of n nodes ending in null pointer.
can throw boost::interprocess::bad_alloc*/
void *allocate_nodes(std::size_t n)
{
while(m_free_nodes < n){
priv_alloc_chunk();
}
m_allocated += n;
m_free_nodes -= n;
void *ret = mp_free.get();
while(n--){
//We take the first free node
if(n == 0){
//Last node we must mark next node as null
char *end = mp_free.get();
mp_free = next_node(end);
//Mark next node of last node as null
next_node(end) = 0;
}
else{
mp_free = next_node(mp_free.get());
}
}
return ret;
}
/*!Deallocates a linked list of nodes ending in null pointer. Never throws*/
void deallocate_nodes(void *nodes)
{
char *node = char_ptr_cast(nodes);
char_ptr_t tmp;
while(node){
tmp = next_node(node);
priv_dealloc_node(node);
node = tmp.get();
}
}
private:
/*!Deallocates all used memory. Never throws*/
void priv_clear()
{
//check for memory leaks
assert(m_allocated==0);
//We iterate though the NodeBlock list to free the memory
char_ptr_t pNextBlock;
while(mp_firstBlock){
pNextBlock = priv_next_chunk(mp_firstBlock.get());
mp_segment_mngr->deallocate(mp_firstBlock.get());
mp_firstBlock = pNextBlock;
}
mp_firstBlock = 0;
mp_free = 0;
}
/*!Allocates one node, using single segregated storage algorithm.
Never throws*/
void *priv_alloc_node()
{
//If there are no free nodes we allocate a new block
if (!mp_free)
priv_alloc_chunk();
//We take the first free node
char_ptr_t pTmp = mp_free;
mp_free = next_node(mp_free.get());
++m_allocated;
--m_free_nodes;
return pTmp.get();
}
/*!Deallocates one node, using single segregated storage algorithm.
Never throws*/
void priv_dealloc_node(void *pElem)
{
//We put the node at the beginning of the free node list
char *pTmp = detail::char_ptr_cast(pElem);
//We must build the offset pointer in memory
next_node(pTmp) = mp_free;
mp_free = pTmp;
assert(m_allocated>0);
--m_allocated;
++m_free_nodes;
}
/*!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc*/
void priv_alloc_chunk()
{
//We allocate a new NodeBlock and put it as first
//element in the free Node list
char *pNode = detail::char_ptr_cast(mp_segment_mngr->allocate(ChunkSize));
char *pBlock = pNode;
priv_next_chunk(pBlock) = mp_firstBlock;
mp_firstBlock = pBlock;
//We initialize all Nodes in Node Block to insert
//them in the free Node list
for(std::size_t i = 0; i < NumAlloc; ++i){
next_node(pNode) = mp_free;
mp_free = pNode;
pNode += RealNodeSize;
}
m_free_nodes += NumAlloc;
}
public:
/*!Returns a reference to the next node from a raw pointer pointing
to a free node. Never throws*/
static inline char_ptr_t &next_node (void *node)
{ return *static_cast<char_ptr_t*>(node); }
private:
/*!Returns a reference to the next chunk from a raw pointer pointing
to a chunk. Never throws*/
static inline char_ptr_t & priv_next_chunk (void *chunk)
{
return *static_cast<char_ptr_t*>(
static_cast<void*>((detail::char_ptr_cast(chunk)+BlockSize)));
}
private:
typedef typename pointer_to_other
<void_pointer, segment_manager>::type segment_mngr_ptr_t;
segment_mngr_ptr_t mp_segment_mngr; //Segment manager
char_ptr_t mp_firstBlock; //Ptr to the first block
char_ptr_t mp_free; //Ptr to the first free node
std::size_t m_allocated; //Used nodes for debugging
std::size_t m_free_nodes; //Free nodes
};
/*!Pooled shared memory allocator using single segregated storage. Includes
a reference count but the class does not delete itself, this is
responsibility of user classes. Node size (NodeSize) and the number of
nodes allocated per chunk (NumAlloc) are known at compile time*/
template<class SegmentManager, class Mutex,
std::size_t NodeSize, std::size_t NumAlloc>
class shared_node_pool
: public private_node_pool
<SegmentManager, NodeSize, NumAlloc>
{
private:
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename pointer_to_other<void_pointer, char>::type char_ptr_t;
typedef private_node_pool
<SegmentManager,
NodeSize, NumAlloc> private_node_allocator_t;
public:
/*!Segment manager typedef*/
typedef SegmentManager segment_manager;
/*!Constructor from a segment manager. Never throws*/
shared_node_pool(segment_manager *segment_mngr)
: private_node_allocator_t(segment_mngr){}
/*!Destructor. Deallocates all allocated chunks. Never throws*/
~shared_node_pool()
{}
/*!Allocates array of count elements. Can throw boost::interprocess::bad_alloc*/
void *allocate(std::size_t count)
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate(count);
}
/*!Deallocates an array pointed by ptr. Never throws*/
void deallocate(void *ptr, std::size_t count)
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate(ptr, count);
}
/*!Allocates a singly linked list of n nodes ending in null pointer.
can throw boost::interprocess::bad_alloc*/
void *allocate_nodes(std::size_t n)
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_nodes(n);
}
/*!Deallocates a linked list of nodes ending in null pointer. Never throws*/
void deallocate_nodes(void * nodes)
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(nodes);
}
/*!Increments internal reference count and returns new count. Never throws*/
std::size_t inc_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
return ++m_header.m_usecount;
}
/*!Decrements internal reference count and returns new count. Never throws*/
std::size_t dec_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<Mutex> guard(m_header);
//-----------------------
assert(m_header.m_usecount > 0);
return --m_header.m_usecount;
}
private:
/*!This struct includes needed data and derives from
interprocess_mutex to allow EBO when using null interprocess_mutex*/
struct header_t : Mutex
{
std::size_t m_usecount; //Number of attached allocators
header_t()
: m_usecount(0) {}
} m_header;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_ALGO_HPP

View File

@@ -0,0 +1,318 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_POOLED_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_POOLED_NODE_ALLOCATOR_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/utility/addressof.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <memory>
#include <algorithm>
#include <stdio.h>
#include <cstddef>
/*!\file
Describes node_allocator pooled shared memory STL compatible allocator
*/
namespace boost {
namespace interprocess {
/*!An STL node allocator that uses a segment manager as memory
source. The internal pointer type will of the same type (raw, smart) as
"typename SegmentManager::void_pointer" type. This allows
placing the allocator in shared memory, memory mapped-files, etc...
This node allocator shares a segregated storage between all instances
of node_allocator with equal sizeof(T) placed in the same segment
group. N is the number of nodes allocated at once when the allocator
needs runs out of nodes*/
template<class T, std::size_t N, class SegmentManager>
class node_allocator
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename detail::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
typedef SegmentManager segment_manager;
typedef typename detail::
pointer_to_other<void_pointer, char>::type char_pointer;
typedef typename SegmentManager::
mutex_family::mutex_t mutex_t;
typedef node_allocator
<T, N, SegmentManager> self_t;
public:
//-------
typedef typename detail::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename detail::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename workaround::random_it
<value_type>::reference reference;
typedef typename workaround::random_it
<value_type>::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
/*!Obtains node_allocator from other node_allocator*/
template<class T2>
struct rebind
{
typedef node_allocator<T2, N, SegmentManager> other;
};
private:
/*!Not assignable from related node_allocator*/
template<class T2, std::size_t N2, class AllocAlgo2>
node_allocator& operator=
(const node_allocator<T2, N2, AllocAlgo2>&);
/*!Not assignable from other node_allocator*/
node_allocator& operator=(const node_allocator&);
public:
/*!Constructor from a segment manager. If not present, constructs a node
pool. Increments the reference count of the associated node pool.
Can throw boost::interprocess::bad_alloc*/
node_allocator(segment_manager *segment_mngr)
: mp_node_pool(priv_get_or_create(segment_mngr)) { }
/*!Copy constructor from other node_allocator. Increments the reference
count of the associated node pool. Never throws*/
node_allocator(const node_allocator &other)
: mp_node_pool(other.get_node_pool())
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), N> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>(other.get_node_pool());
node_pool->inc_ref_count();
}
/*!Copy constructor from related node_allocator. If not present, constructs
a node pool. Increments the reference count of the associated node pool.
Can throw boost::interprocess::bad_alloc*/
template<class T2>
node_allocator
(const node_allocator<T2, N, SegmentManager> &other)
: mp_node_pool(priv_get_or_create(other.get_segment_manager())) { }
/*!Destructor, removes node_pool_t from memory
if its reference count reaches to zero. Never throws*/
~node_allocator()
{ priv_destroy_if_last_link(); }
/*!Returns a pointer to the node pool. Never throws*/
void* get_node_pool() const
{ return detail::get_pointer(mp_node_pool); }
/*!Returns the segment manager. Never throws*/
segment_manager* get_segment_manager()const
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), N> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
return node_pool->get_segment_manager();
}
/*!Return address of mutable value. Never throws*/
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
/*!Return address of nonmutable value. Never throws*/
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
/*!Construct object, calling constructor.
Throws if T(const Convertible &) throws*/
template<class Convertible>
void construct(const pointer &ptr, const Convertible &value)
{ new(detail::get_pointer(ptr)) value_type(value); }
/*!Destroys object. Throws if object's destructor throws*/
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
/*!Returns the number of elements that could be allocated. Never throws*/
size_type max_size() const
{ return this->get_segment_manager()->get_size(); }
/*!Allocate memory for an array of count elements.
Throws boost::interprocess::bad_alloc if there is no enough memory*/
pointer allocate(size_type count, cvoid_pointer = 0)
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), N> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
return pointer(static_cast<T*>(node_pool->allocate(count)));
}
/*!Deallocate allocated memory. Never throws*/
void deallocate(const pointer &ptr, size_type count)
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), N> node_pool_t;
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
node_pool->deallocate(detail::get_pointer(ptr), count);
}
/*!Swaps allocators. Does not throw. If each allocator is placed in a
different memory segment, the result is undefined.*/
friend void swap(self_t &alloc1, self_t &alloc2)
{
using namespace std;
swap(alloc1.mp_node_pool, alloc2.mp_node_pool);
}
private:
/*!Object function that creates the node allocator if it is not created and
increments reference count if it is already created*/
struct get_or_create_func
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t, sizeof(T), N> node_pool_t;
/*!This connects or constructs the unique instance of node_pool_t
Can throw boost::interprocess::bad_alloc*/
void operator()()
{
//Find or create the node_pool_t
mp_node_pool = mp_named_alloc->template find_or_construct
<node_pool_t>(unique_instance)(mp_named_alloc);
//If valid, increment link count
if(mp_node_pool != 0)
mp_node_pool->inc_ref_count();
}
/*!Constructor. Initializes function object parameters*/
get_or_create_func(segment_manager *hdr) : mp_named_alloc(hdr){}
node_pool_t *mp_node_pool;
segment_manager *mp_named_alloc;
};
/*!Initialization function, creates an executes atomically the
initialization object functions. Can throw boost::interprocess::bad_alloc*/
void *priv_get_or_create(segment_manager *named_alloc)
{
get_or_create_func func(named_alloc);
named_alloc->atomic_func(func);
return func.mp_node_pool;
}
/*!Object function that decrements the reference count. If the count
reaches to zero destroys the node allocator from memory.
Never throws*/
struct destroy_if_last_link_func
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t,sizeof(T), N> node_pool_t;
/*!Decrements reference count and destroys the object if there is no
more attached allocators. Never throws*/
void operator()()
{
//If not the last link return
if(mp_node_pool->dec_ref_count() != 0) return;
//Last link, let's destroy the segment_manager
mp_named_alloc->template destroy<node_pool_t>(unique_instance);
}
/*!Constructor. Initializes function object parameters*/
destroy_if_last_link_func(segment_manager *nhdr,
node_pool_t *phdr)
: mp_named_alloc(nhdr), mp_node_pool(phdr){}
segment_manager *mp_named_alloc;
node_pool_t *mp_node_pool;
};
/*!Destruction function, initializes and executes destruction function
object. Never throws*/
void priv_destroy_if_last_link()
{
typedef detail::shared_node_pool
<SegmentManager, mutex_t,sizeof(T), N> node_pool_t;
//Get segment manager
segment_manager *named_segment_mngr = this->get_segment_manager();
//Get node pool pointer
node_pool_t *node_pool = static_cast<node_pool_t*>
(detail::get_pointer(mp_node_pool));
//Execute destruction functor atomically
destroy_if_last_link_func func(named_segment_mngr, node_pool);
named_segment_mngr->atomic_func(func);
}
private:
// We can't instantiate a pointer like this:
// detail::shared_node_pool<SegmentManager, mutex_t,
// sizeof(T), N> *mp_node_pool;
// since it can provoke an early instantiation of T, that could be
// incomplete at that moment (for example, a node of a node-based container)
// This provokes errors on some node based container implementations using
// this pooled allocator as allocator type.
//
// Because of this, we will use a void offset pointer and we'll do some
//(ugly )casts when needed.
void_pointer mp_node_pool;
};
/*!Equality test for same type of node_allocator*/
template<class T, std::size_t N, class A> inline
bool operator==(const node_allocator<T, N, A> &alloc1,
const node_allocator<T, N, A> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
/*!Inequality test for same type of node_allocator*/
template<class T, std::size_t N, class A> inline
bool operator!=(const node_allocator<T, N, A> &alloc1,
const node_allocator<T, N, A> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
/*!This specialization indicates that the construct function allows
convertible types to construct the value type. This allows
storing less allocator instances in containers.*/
template<class T, std::size_t N, class A>
struct has_convertible_construct
<boost::interprocess::node_allocator<T, N, A> >
{
enum { value = true };
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_POOLED_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,249 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_PRIVATE_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_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/utility/addressof.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <stdio.h>
#include <cstddef>
/*!\file
Describes private_node_allocator pooled shared memory STL compatible allocator
*/
namespace boost {
namespace interprocess {
/*!An STL node allocator that uses a segment manager as memory
source. The internal pointer type will of the same type (raw, smart) as
"typename SegmentManager::void_pointer" type. This allows
placing the allocator in shared memory, memory mapped-files, etc...
This allocator has its own node pool. N is the number of nodes allocated
at once when the allocator needs runs out of nodes*/
template<class T, std::size_t N, class SegmentManager>
class private_node_allocator
{
private:
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename detail::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
typedef SegmentManager segment_manager;
typedef typename detail::
pointer_to_other<void_pointer, char>::type char_pointer;
typedef typename detail::pointer_to_other
<void_pointer, segment_manager>::type segment_mngr_ptr_t;
typedef typename SegmentManager::
mutex_family::mutex_t mutex_t;
typedef private_node_allocator
<T, N, SegmentManager> self_t;
public:
//-------
typedef typename detail::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename detail::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename workaround::random_it
<value_type>::reference reference;
typedef typename workaround::random_it
<value_type>::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
/*!Obtains node_allocator from other node_allocator*/
template<class T2>
struct rebind
{
typedef private_node_allocator<T2, N, SegmentManager> other;
};
/*!Not assignable from related private_node_allocator*/
template<class T2, std::size_t N2, class MemoryAlgorithm2>
private_node_allocator& operator=
(const private_node_allocator<T2, N2, MemoryAlgorithm2>&);
/*!Not assignable from other private_node_allocator*/
private_node_allocator& operator=(const private_node_allocator&);
void priv_initialize()
{
typedef detail::private_node_pool
<SegmentManager, sizeof(T), N> priv_node_pool_t;
void * ptr = mp_segment_mngr->allocate(sizeof(priv_node_pool_t));
//This does not throw
new(ptr)priv_node_pool_t(detail::get_pointer(mp_segment_mngr));
//Construction ok, don't free memory
mp_node_pool = ptr;
}
void priv_free()
{
//-------------------------------------------------------------
typedef detail::private_node_pool
<SegmentManager, sizeof(T), N> priv_node_pool_t;
//-------------------------------------------------------------
priv_node_pool_t *pnode_pool = static_cast<priv_node_pool_t*>
(detail::get_pointer(mp_node_pool));
segment_manager &segment_mngr = *mp_segment_mngr;
//This never throws
pnode_pool->~priv_node_pool_t();
segment_mngr.deallocate(pnode_pool);
}
public:
/*!Constructor from a segment manager.*/
private_node_allocator(segment_manager *segment_mngr)
: mp_segment_mngr(segment_mngr), mp_node_pool(0){}
/*!Copy constructor from other private_node_allocator. Never throws*/
private_node_allocator(const private_node_allocator &other)
: mp_segment_mngr(other.get_segment_manager()), mp_node_pool(0){}
/*!Copy constructor from related private_node_allocator. Never throws.*/
template<class T2>
private_node_allocator
(const private_node_allocator<T2, N, SegmentManager> &other)
: mp_segment_mngr(other.get_segment_manager()), mp_node_pool(0){}
/*!Destructor, frees all used memory. Never throws*/
~private_node_allocator()
{ if(mp_node_pool) priv_free(); }
/*!Returns the segment manager. Never throws*/
segment_manager* get_segment_manager()const
{ return detail::get_pointer(mp_segment_mngr); }
/*!Return address of mutable value. Never throws*/
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
/*!Return address of non mutable value*. Never throws*/
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
/*!Construct object, calling constructor.
Throws if T(const Convertible &) throws*/
template<class Convertible>
void construct(const pointer &ptr, const Convertible &value)
{ new(detail::get_pointer(ptr)) value_type(value); }
/*!Destroys object. Throws if object's destructor throws*/
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
/*!Returns the number of elements that could be allocated. Never throws*/
size_type max_size() const
{ return mp_segment_mngr->get_size(); }
/*!Allocate memory for an array of count elements.
Throws boost::interprocess::bad_alloc if there is no enough memory*/
pointer allocate(size_type count, cvoid_pointer hint = 0)
{
//----------------------------------------------------------
typedef detail::private_node_pool
<SegmentManager, sizeof(T), N> priv_node_pool_t;
//----------------------------------------------------------
if(!mp_node_pool) priv_initialize();
priv_node_pool_t *node_pool = static_cast<priv_node_pool_t*>
(detail::get_pointer(mp_node_pool));
return pointer(static_cast<value_type*>(node_pool->allocate(count)));
}
/*!Deallocate allocated memory. Never throws*/
void deallocate(const pointer &ptr, size_type count)
{
//----------------------------------------------------------
typedef detail::private_node_pool
<SegmentManager, sizeof(T), N> priv_node_pool_t;
//----------------------------------------------------------
if(!mp_node_pool) priv_initialize();
priv_node_pool_t *node_pool = static_cast<priv_node_pool_t*>(
detail::get_pointer(mp_node_pool));
node_pool->deallocate(detail::get_pointer(ptr), count);
}
/*!Swaps allocators. Does not throw. If each allocator is placed in a
different shared memory segments, the result is undefined.*/
friend void swap(self_t &alloc1,self_t &alloc2)
{
using namespace std;
swap (alloc1.mp_segment_mngr, alloc2.mp_segment_mngr);
swap (alloc1.mp_node_pool, alloc2.mp_node_pool);
}
private:
// We can't instantiate a pointer like this:
// detail::private_node_pool<SegmentManager,
// sizeof(T), N> *mp_node_pool;
// since it can provoke an early instantiation of T, that is not
// complete at the moment (for example, a node of a node-based pointer)
// This provokes errors on some node based container implementations using
// this pooled allocator as this allocator type.
//
// Because of this, we will use a void smart pointer and we'll do some casts
// when needed.
segment_mngr_ptr_t mp_segment_mngr;
void_pointer mp_node_pool;
};
/*!Equality test for same type of private_node_allocator*/
template<class T, std::size_t N, class A> inline
bool operator==(const private_node_allocator<T, N, A> &alloc1,
const private_node_allocator<T, N, A> &alloc2)
{ return &alloc1 == &alloc2; }
/*!Inequality test for same type of private_node_allocator*/
template<class T, std::size_t N, class A> inline
bool operator!=(const private_node_allocator<T, N, A> &alloc1,
const private_node_allocator<T, N, A> &alloc2)
{
return &alloc1 != &alloc2;
}
/*!This specialization indicates that the construct function allows
convertible types to construct the value type. This allows
storing less allocator instances in containers.*/
template<class T, std::size_t N, class A>
struct has_convertible_construct
<boost::interprocess::private_node_allocator<T, N, A> >
{
enum { value = true };
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,830 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_tree file. Modified by Ion Gaztañaga 2005.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_TREE_HPP
#define BOOST_INTERPROCESS_TREE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/detail/tree_func.hpp>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/interprocess/detail/generic_cast.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/mpl/if.hpp>
#include <iterator>
#include <algorithm>
//Red-black tree class, designed for use in implementing STL
//associative containers (set, multiset, map, and multimap). The
//insertion and deletion algorithms are based on those in Cormen,
//Leiserson, and Rivest, Introduction to Algorithms (MIT Press, 1990),
//except that
//
//(1) the header cell is maintained with links not only to the root
//but also to the leftmost node of the tree, to enable constant time
//this->begin(), and to the rightmost node of the tree, to enable linear time
//performance when used with the generic set algorithms (set_union,
//etc.);
//
//(2) when a node being deleted has two children its successor node is
//relinked into its place, rather than copied, so that the only
//iterators invalidated are those referring to the deleted node.
namespace boost { namespace interprocess { namespace detail {
template <class Alloc>
struct rb_tree_node
: rb_tree_node_base<typename pointer_to_other<typename Alloc::pointer, void>::type>
{
typedef rb_tree_node_base<typename pointer_to_other
<typename Alloc::pointer, void>::type> base_t;
typedef typename boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type node_allocator_t;
typedef typename base_t::basic_node_pointer basic_node_pointer;
typedef typename node_allocator_t::pointer node_pointer;
typedef typename Alloc::value_type value_type;
typedef typename Alloc::const_pointer const_pointer;
typedef typename Alloc::pointer pointer;
typedef typename Alloc::const_reference const_reference;
typedef typename Alloc::reference reference;
typedef typename Alloc::difference_type difference_type;
rb_tree_node(const value_type & value)
: m_value(value)
{}
static node_pointer downcast(basic_node_pointer upclass_pointer/*const basic_node_pointer &upclass_pointer*/)
{
return boost::interprocess::do_static_cast<node_pointer>(upclass_pointer);
}
const value_type &value() const { return m_value; }
value_type &value() { return m_value; }
private:
value_type m_value;
};
template <class T, class Alloc, bool convertible_construct>
class rb_tree_alloc_base
//Inherit from node allocator
: public boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type,
//Inherit from node_ptr allocator
public boost::detail::allocator::
rebind_to<Alloc, typename
boost::detail::allocator::rebind_to
<Alloc, rb_tree_node<Alloc> >::type::value_type::basic_node_pointer>::type,
//Inherit from value_ptr allocator
public boost::detail::allocator::rebind_to<Alloc, T>::type
{
public:
typedef typename boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type node_allocator_t;
typedef typename node_allocator_t::value_type node_val_t;
typedef typename node_allocator_t::pointer node_pointer;
typedef typename boost::detail::allocator::
rebind_to<Alloc, T>::type value_allocator_t;
typedef typename value_allocator_t::value_type value_val_t;
typedef typename value_allocator_t::pointer value_ptr_t;
typedef typename value_allocator_t::const_pointer value_cptr_t;
typedef typename value_allocator_t::reference value_ref_t;
typedef typename value_allocator_t::const_reference value_cref_t;
typedef typename boost::detail::allocator::
rebind_to<Alloc, typename node_val_t::
basic_node_pointer>::type basic_node_ptr_allocator_t;
typedef typename basic_node_ptr_allocator_t::pointer basic_node_ptr_ptr_t;
typedef typename basic_node_ptr_allocator_t::value_type basic_node_ptr_t;
typedef detail::scoped_deallocator<node_allocator_t> NodeDeallocator;
typedef detail::scoped_destructor <basic_node_ptr_allocator_t> BasicPtrDestructor;
rb_tree_alloc_base(const value_allocator_t& a)
: node_allocator_t(a),
basic_node_ptr_allocator_t(a),
value_allocator_t(a)
{ this->initialize_when_empty(); }
rb_tree_alloc_base(const rb_tree_alloc_base &x)
: node_allocator_t(x),
basic_node_ptr_allocator_t(x),
value_allocator_t(x)
{
if (!x.m_header->parent()){
this->initialize_when_empty();
}
}
~rb_tree_alloc_base()
{ this->uninitialize_when_empty(); }
node_pointer allocate_and_construct_node(value_cref_t x)
{
node_pointer p = node_allocator_t::allocate(1);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(p, *this);
basic_node_ptr_ptr_t pleft(basic_node_ptr_allocator_t::address(p->left())),
pright(basic_node_ptr_allocator_t::address(p->right())),
pparent(basic_node_ptr_allocator_t::address(p->parent()));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
basic_node_ptr_allocator_t::construct(pleft, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
left_destroy(pleft, *this);
basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
right_destroy(pright, *this);
basic_node_ptr_allocator_t::construct(pparent, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
parent_destroy(pparent, *this);
value_allocator_t::construct(value_allocator_t::address(p->value()), x);
left_destroy.release();
right_destroy.release();
parent_destroy.release();
}
node_deallocator.release();
return p;
}
void destroy_and_deallocate_node(node_pointer p)
{
node_allocator_t::destroy(p);
node_allocator_t::deallocate(p, 1);
}
typename node_allocator_t::size_type max_size() const
{ return node_allocator_t::max_size(); }
void swap (rb_tree_alloc_base &x)
{
node_allocator_t& this_alloc = static_cast<node_allocator_t&>(*this);
node_allocator_t& other_alloc = static_cast<node_allocator_t&>(x);
if (this_alloc != other_alloc){
detail::do_swap(static_cast<value_allocator_t&>(*this),
static_cast<value_allocator_t&>(x));
detail::do_swap(static_cast<basic_node_ptr_allocator_t&>(*this),
static_cast<basic_node_ptr_allocator_t&>(x));
detail::do_swap(this_alloc, other_alloc);
}
detail::do_swap(this->m_header, x.m_header);
}
private:
void initialize_when_empty()
{
this->m_header = node_allocator_t::allocate(1);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(this->m_header, *this);
basic_node_ptr_ptr_t pleft(basic_node_ptr_allocator_t::address(this->m_header->left())),
pright(basic_node_ptr_allocator_t::address(this->m_header->right())),
pparent(basic_node_ptr_allocator_t::address(this->m_header->parent()));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
basic_node_ptr_allocator_t::construct(pleft, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
left_destroy(pleft, *this);
basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
right_destroy(pleft, *this);
basic_node_ptr_allocator_t::construct(pparent, basic_node_ptr_t());
left_destroy.release();
right_destroy.release();
}
//m_value is not constructed since it is not used
//m_color is POD so we don't need to construct it
this->m_header->color() = node_val_t::red_color; // used to distinguish header from
// root, in iterator.operator++
this->m_header->parent() = 0;
this->m_header->left() = this->m_header;
this->m_header->right() = this->m_header;
node_deallocator.release();
}
void uninitialize_when_empty()
{
//Destructors must not throw
basic_node_ptr_allocator_t::destroy(basic_node_ptr_allocator_t::address(this->m_header->left()));
basic_node_ptr_allocator_t::destroy(basic_node_ptr_allocator_t::address(this->m_header->right()));
basic_node_ptr_allocator_t::destroy(basic_node_ptr_allocator_t::address(this->m_header->parent()));
//m_color is POD so we don't need to destroy it
//m_value was not constructed so we don't need to destroy it
node_allocator_t::deallocate(this->m_header, 1);
}
protected:
node_pointer m_header;
};
template <class T, class Alloc>
class rb_tree_alloc_base<T, Alloc, true>
//Inherit from node allocator
: public boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type
{
public:
typedef typename boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type node_allocator_t;
typedef typename node_allocator_t::value_type node_val_t;
typedef typename node_allocator_t::pointer node_pointer;
typedef typename boost::detail::allocator::
rebind_to<Alloc, T>::type value_allocator_t;
typedef typename value_allocator_t::value_type value_val_t;
typedef typename value_allocator_t::pointer value_ptr_t;
typedef typename value_allocator_t::const_pointer value_cptr_t;
typedef typename value_allocator_t::reference value_ref_t;
typedef typename value_allocator_t::const_reference value_cref_t;
typedef typename boost::detail::allocator::
rebind_to<Alloc, typename node_val_t::
basic_node_pointer>::type basic_node_ptr_allocator_t;
typedef typename basic_node_ptr_allocator_t::pointer basic_node_ptr_ptr_t;
typedef typename basic_node_ptr_allocator_t::value_type basic_node_ptr_t;
typedef detail::scoped_deallocator<node_allocator_t> NodeDeallocator;
typedef detail::scoped_destructor <basic_node_ptr_allocator_t> BasicPtrDestructor;
rb_tree_alloc_base(const value_allocator_t& a)
: node_allocator_t(a)
{ this->initialize_when_empty(); }
rb_tree_alloc_base(const rb_tree_alloc_base &x)
: node_allocator_t(x)
{ this->initialize_when_empty(); }
~rb_tree_alloc_base()
{ this->uninitialize_when_empty(); }
template<class Convertible>
node_pointer allocate_and_construct_node(const Convertible &x)
{
node_pointer p = node_allocator_t::allocate(1);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(p, *this);
node_allocator_t::construct(p, x);
node_deallocator.release();
return p;
}
void destroy_and_deallocate_node(node_pointer p)
{
node_allocator_t::destroy(p);
node_allocator_t::deallocate(p, 1);
}
typename node_allocator_t::size_type max_size() const
{ return node_allocator_t::max_size(); }
void swap (rb_tree_alloc_base &x)
{
node_allocator_t& this_alloc = static_cast<node_allocator_t&>(*this);
node_allocator_t& other_alloc = static_cast<node_allocator_t&>(x);
if (this_alloc != other_alloc){
detail::do_swap(this_alloc, other_alloc);
}
detail::do_swap(this->m_header, x.m_header);
}
private:
void initialize_when_empty()
{
this->m_header = node_allocator_t::allocate(1);
//If the pointer type a has trivial constructor we can avoid this
if(!boost::has_trivial_constructor<node_pointer>::value){
basic_node_ptr_allocator_t node_ptr_allocator(*this);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(this->m_header, *this);
basic_node_ptr_ptr_t pleft(node_ptr_allocator.address(this->m_header->left())),
pright(node_ptr_allocator.address(this->m_header->right())),
pparent(node_ptr_allocator.address(this->m_header->parent()));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
node_ptr_allocator.construct(pleft, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
left_destroy(pleft, node_ptr_allocator);
node_ptr_allocator.construct(pright, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
right_destroy(pright, node_ptr_allocator);
node_ptr_allocator.construct(pparent, basic_node_ptr_t());
left_destroy.release();
right_destroy.release();
}
node_deallocator.release();
}
//m_value is not constructed since it is not used
//m_color is POD so we don't need to construct it
this->m_header->color() = node_val_t::red_color; // used to distinguish header from
// root, in iterator.operator++
this->m_header->parent() = 0;
this->m_header->left() = this->m_header;
this->m_header->right() = this->m_header;
}
void uninitialize_when_empty()
{
//If the pointer type a has trivial destructor we can avoid this
if(!boost::has_trivial_destructor<node_pointer>::value){
basic_node_ptr_allocator_t node_ptr_allocator(*this);
//Destructors must not throw
node_ptr_allocator.destroy(node_ptr_allocator.address(this->m_header->left()));
node_ptr_allocator.destroy(node_ptr_allocator.address(this->m_header->right()));
node_ptr_allocator.destroy(node_ptr_allocator.address(this->m_header->parent()));
}
//m_color is POD so we don't need to destroy it
//m_value was not constructed so we don't need to destroy it
node_allocator_t::deallocate(this->m_header, 1);
}
protected:
node_pointer m_header;
};
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
class rb_tree
: protected rb_tree_alloc_base<Value, Alloc,
has_convertible_construct<Alloc>::value>
{
private:
typedef rb_tree_alloc_base<Value, Alloc,
has_convertible_construct<Alloc>::value> base_t;
typedef typename base_t::node_pointer node_pointer;
typedef typename base_t::node_val_t node_val_t;
typedef typename node_val_t::basic_node_pointer basic_node_pointer;
typedef rb_tree_algo<node_val_t> rb_tree_algo_t;
typedef rb_tree_func<node_val_t, Key,
KeyOfValue, Compare > rb_tree_func_t;
public:
typedef Key key_type;
typedef Value value_type;
typedef typename base_t::value_ptr_t pointer;
typedef typename base_t::value_cptr_t const_pointer;
typedef typename base_t::value_ref_t reference;
typedef typename base_t::value_cref_t const_reference;
typedef typename base_t::value_allocator_t allocator_type;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef rb_tree_const_iterator<node_val_t> const_iterator;
typedef rb_tree_iterator<node_val_t> iterator;
typedef boost::reverse_iterator<iterator> reverse_iterator;
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
rb_tree(const Compare& comp = Compare(),
const allocator_type& a = allocator_type())
: base_t(a), m_data(comp, 0)
{ }
rb_tree(const rb_tree& x)
: base_t(x),
m_data(x.get_compare(), 0)
{
if (x.root()){
this->m_header->color() = node_val_t::red_color;
this->root()=
this->copy_node(node_val_t::downcast(x.m_header->parent()),
this->m_header);
this->leftmost() =
rb_tree_algo_t::minimum_node(node_val_t::downcast(this->root()));
this->rightmost() =
rb_tree_algo_t::maximum_node(node_val_t::downcast(this->root()));
}
this->m_data.m_node_count = x.m_data.m_node_count;
}
~rb_tree() { this->clear(); }
rb_tree& operator=(const rb_tree& x)
{
if (this != &x) {
// Note that Key may be a constant type.
this->clear();
this->m_data.m_node_count = 0;
this->get_compare() = x.get_compare();
if (!x.root()) {
this->root() = 0;
this->leftmost() = this->m_header;
this->rightmost() = this->m_header;
}
else{
this->root() = this->copy_node(x.root(), this->m_header);
this->leftmost() =
rb_tree_algo_t::minimum_node(node_val_t::downcast(this->root()));
this->rightmost() =
rb_tree_algo_t::maximum_node(node_val_t::downcast(this->root()));
this->m_data.m_node_count = x.m_data.m_node_count;
}
}
return *this;
}
public:
// accessors:
Compare key_comp() const
{ return this->get_compare(); }
allocator_type get_allocator() const
{ return allocator_type(*this); }
iterator begin()
{ return iterator(this->leftmost()); }
const_iterator begin() const
{ return const_iterator(this->leftmost()); }
iterator end()
{ return iterator(this->m_header); }
const_iterator end() const
{ return const_iterator(this->m_header); }
reverse_iterator rbegin()
{ return reverse_iterator(this->end()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(this->end()); }
reverse_iterator rend()
{ return reverse_iterator(this->begin()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(this->begin()); }
bool empty() const
{ return !this->m_data.m_node_count; }
size_type size() const
{ return this->m_data.m_node_count; }
size_type max_size() const
{ return base_t::max_size(); }
void swap(rb_tree& t)
{
detail::do_swap(this->m_data.m_node_count, t.m_data.m_node_count);
detail::do_swap(this->get_compare(), t.get_compare());
base_t::swap(t);
}
public:
// insert/erase
std::pair<iterator,bool> insert_unique(const value_type& v)
{
KeyOfValue key_of_value;
node_pointer out;
typename rb_tree_func_t::insert_unique_context context;
if(!rb_tree_func_t::insert_unique_prepare
(this->m_header, this->m_data, key_of_value(v), out, context)){
return std::pair<iterator,bool>(iterator(out), false);
}
node_pointer new_node = this->allocate_and_construct_node(v);
++this->m_data.m_node_count;
rb_tree_func_t::insert_unique_commit
(this->m_header, this->m_data, new_node, out, context);
return std::pair<iterator,bool>(iterator(out), true);
}
iterator insert_unique(iterator hint, const value_type& v)
{
KeyOfValue key_of_value;
node_pointer out;
typename rb_tree_func_t::insert_unique_context context;
if(!rb_tree_func_t::insert_unique_hint_prepare
(this->m_header, this->m_data, hint.get_ptr(),
key_of_value(v), out, context)){
return iterator(out);
}
node_pointer new_node = this->allocate_and_construct_node(v);
++this->m_data.m_node_count;
rb_tree_func_t::insert_unique_commit(this->m_header, this->m_data, new_node, out, context);
return iterator(out);
}
template <class InputIterator>
void insert_unique(InputIterator first, InputIterator last)
{
for ( ; first != last; ++first)
this->insert_unique(*first);
}
iterator insert_equal(const value_type& v)
{
node_pointer tmp = this->allocate_and_construct_node(v);
rb_tree_func_t::insert_equal(this->m_header, this->m_data, tmp);
++this->m_data.m_node_count;
return iterator(tmp);
}
iterator insert_equal(iterator hint, const value_type& v)
{
node_pointer tmp = this->allocate_and_construct_node(v);
rb_tree_func_t::insert_equal_hint(this->m_header, this->m_data,
hint.get_ptr(), tmp);
++this->m_data.m_node_count;
return iterator(tmp);
}
template <class InputIterator>
void insert_equal(InputIterator first, InputIterator last)
{
for ( ; first != last; ++first)
this->insert_equal(*first);
}
iterator erase(const_iterator position)
{
iterator ret(position.get_ptr());
++ret;
node_pointer y = node_val_t::downcast(rb_tree_func_t::erase_node(this->m_header, position.get_ptr()));
this->destroy_and_deallocate_node(y);
--this->m_data.m_node_count;
return ret;
}
size_type erase(const key_type& x)
{
std::pair<iterator,iterator> p = this->equal_range(x);
size_type n = std::distance(p.first, p.second);
this->erase(p.first, p.second);
return n;
}
iterator erase(const_iterator first, const_iterator last)
{
if (first == this->begin() && last == this->end()){
this->clear();
return begin();
}
else{
while (first != last){
first = this->erase(first);
}
return iterator(last.get_ptr());
}
}
void clear()
{
if (this->m_data.m_node_count) {
this->erase_node(node_val_t::downcast(this->root()));
this->leftmost() = this->m_header;
this->root() = 0;
this->rightmost() = this->m_header;
this->m_data.m_node_count = 0;
}
}
// set operations:
iterator find(const key_type& k)
{ return iterator(rb_tree_func_t::find(this->m_header, this->m_data, k)); }
const_iterator find(const key_type& k) const
{ return const_iterator(rb_tree_func_t::find(this->m_header, this->m_data, k)); }
size_type count(const key_type& k) const
{ return size_type(rb_tree_func_t::count(this->m_header, this->m_data, k)); }
iterator lower_bound(const key_type& k)
{ return iterator(rb_tree_func_t::lower_bound(this->m_header, this->m_data, k)); }
const_iterator lower_bound(const key_type& k) const
{ return const_iterator(rb_tree_func_t::lower_bound(this->m_header, this->m_data, k)); }
iterator upper_bound(const key_type& k)
{ return iterator (rb_tree_func_t::upper_bound(this->m_header, this->m_data, k)); }
const_iterator upper_bound(const key_type& k) const
{ return const_iterator (rb_tree_func_t::upper_bound(this->m_header, this->m_data, k)); }
std::pair<iterator,iterator> equal_range(const key_type& k)
{
node_pointer lower, upper;
rb_tree_func_t::equal_range(this->m_header, this->m_data, k, lower, upper);
return std::pair<iterator, iterator>(iterator(lower), iterator(upper));
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
{
node_pointer lower, upper;
rb_tree_func_t::equal_range(this->m_header, this->m_data, k, lower, upper);
return std::pair<const_iterator, const_iterator>(const_iterator(lower), const_iterator(upper));
}
private:
basic_node_pointer &root() const
{ return this->m_header->parent(); }
basic_node_pointer &leftmost() const
{ return this->m_header->left(); }
basic_node_pointer &rightmost() const
{ return this->m_header->right(); }
node_pointer clone_node(basic_node_pointer x)
{
basic_node_pointer tmp = this->allocate_and_construct_node(node_val_t::downcast(x)->value());
tmp->color() = x->color();
tmp->left() = 0;
tmp->right() = 0;
return node_val_t::downcast(tmp);
}
const Compare & get_compare() const
{ return static_cast<const Compare&>(m_data); }
Compare & get_compare()
{ return static_cast<Compare&>(m_data); }
static const Key& get_node_key(node_pointer x)
{ return KeyOfValue()(x->value()); }
node_pointer copy_node(basic_node_pointer x, basic_node_pointer p)
{
// structural copy. x and p must be non-null.
node_pointer top = this->clone_node(x);
top->parent() = p;
BOOST_TRY {
if (x->right())
top->right() = this->copy_node(x->right(), top);
p = top;
x = x->left();
while (x) {
node_pointer y = this->clone_node(x);
p->left() = y;
y->parent() = p;
if (x->right()){
y->right() = this->copy_node(x->right(), y);
}
p = y;
x = x->left();
}
}
BOOST_CATCH(...){
this->erase_node(top);
BOOST_RETHROW;
}
BOOST_CATCH_END
return top;
}
void erase_node(node_pointer x)
{
// erase without rebalancing
while (x) {
this->erase_node(node_val_t::downcast(x->right()));
node_pointer y = node_val_t::downcast(x->left());
this->destroy_and_deallocate_node(x);
x = y;
}
}
private:
struct Data
: public Compare
{
Data(const Compare &comp, size_type node_count)
: Compare(comp), m_node_count(node_count){}
size_type m_node_count; // keeps track of size of tree
} m_data;
};
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator==(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return x.size() == y.size() &&
std::equal(x.begin(), x.end(), y.begin());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return std::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator!=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return !(x == y);
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return y < x;
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return !(y < x);
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return !(x < y);
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline void
swap(rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
x.swap(y);
}
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_TREE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,857 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_tree file. Modified by Ion Gaztañaga 2005.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_TREE_FUNC_HPP
#define BOOST_INTERPROCESS_TREE_FUNC_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/iterator.hpp>
namespace boost {
namespace interprocess {
namespace detail {
template <class VoidPointer>
struct rb_tree_node_base
{
typedef typename boost::interprocess::detail::pointer_to_other
<VoidPointer, rb_tree_node_base<VoidPointer> >::type basic_node_pointer;
enum color_t { red_color = false, black_color = true };
const basic_node_pointer &parent() const { return mp_parent; }
basic_node_pointer &parent() { return mp_parent; }
const basic_node_pointer &left() const { return mp_left; }
basic_node_pointer &left() { return mp_left; }
const basic_node_pointer &right() const { return mp_right; }
basic_node_pointer &right() { return mp_right; }
const color_t &color() const { return m_color; }
color_t &color() { return m_color; }
private:
basic_node_pointer mp_parent;
basic_node_pointer mp_left;
basic_node_pointer mp_right;
color_t m_color;
};
/*!Basic red-black tree functions that don't need
comparison operator*/
template <class NodeBase>
class rb_tree_algo
{
typedef typename NodeBase::basic_node_pointer basic_node_pointer;
public:
static basic_node_pointer next_node(basic_node_pointer node)
{
if (node->right()) {
node = node->right();
while (node->left()){
node = node->left();
}
}
else{
basic_node_pointer y = node->parent();
while (node == y->right()) {
node = y;
y = y->parent();
}
if (node->right() != y)
node = y;
}
return node;
}
static basic_node_pointer previous_node(basic_node_pointer node)
{
if (node->color() == NodeBase::red_color &&
node->parent()->parent() == node){
node = node->right();
}
else if (node->left()) {
basic_node_pointer y = node->left();
while (y->right()){
y = y->right();
}
node = y;
}
else{
basic_node_pointer y = node->parent();
while (node == y->left()) {
node = y;
y = y->parent();
}
node = y;
}
return node;
}
static bool is_header (const basic_node_pointer p)
{
return p->color() == NodeBase::red_color && p->parent()->parent() == p;
}
static basic_node_pointer minimum_node(basic_node_pointer x)
{
while (x->left()){
x = x->left();
}
return x;
}
static basic_node_pointer maximum_node(basic_node_pointer x)
{
while (x->right()){
x = x->right();
}
return x;
}
static void replace_own (const basic_node_pointer &header,
const basic_node_pointer &own,
const basic_node_pointer &p)
{
if (header->parent() == own)
header->parent() = p;
else if (own->parent()->left() == own)
own->parent()->left() = p;
else
own->parent()->right() = p;
}
static void rotate_left(const basic_node_pointer &header, basic_node_pointer x)
{
basic_node_pointer y = x->right();
x->right() = y->left();
if (y->left() !=0)
y->left()->parent() = x;
y->parent() = x->parent();
replace_own(header, x, y);
y->left() = x;
x->parent() = y;
}
static void rotate_right(const basic_node_pointer &header, basic_node_pointer x)
{
basic_node_pointer y = x->left();
x->left() = y->right();
if (y->right())
y->right()->parent() = x;
y->parent() = x->parent();
replace_own(header, x, y);
y->right() = x;
x->parent() = y;
}
static void rebalance(const basic_node_pointer &header, basic_node_pointer x)
{
x->color() = NodeBase::red_color;
while (x != header->parent() && x->parent()->color() == NodeBase::red_color) {
if (x->parent() == x->parent()->parent()->left()) {
basic_node_pointer y = x->parent()->parent()->right();
if (y && y->color() == NodeBase::red_color) {
x->parent()->color() = NodeBase::black_color;
y->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
x = x->parent()->parent();
}
else{
if (x == x->parent()->right()) {
x = x->parent();
rotate_left(header, x);
}
x->parent()->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
rotate_right(header, x->parent()->parent());
}
}
else{
basic_node_pointer y = x->parent()->parent()->left();
if (y && y->color() == NodeBase::red_color) {
x->parent()->color() = NodeBase::black_color;
y->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
x = x->parent()->parent();
}
else{
if (x == x->parent()->left()) {
x = x->parent();
rotate_right(header, x);
}
x->parent()->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
rotate_left(header, x->parent()->parent());
}
}
}
header->parent()->color() = NodeBase::black_color;
}
static basic_node_pointer erase_node
(const basic_node_pointer &header, basic_node_pointer z)
{
basic_node_pointer& root = header->parent();
basic_node_pointer& leftmost = header->left();
basic_node_pointer& rightmost = header->right();
basic_node_pointer y = z;
basic_node_pointer x = 0;
basic_node_pointer x_parent = 0;
if (!y->left()) // z has at most one non-null child. y == z.
x = y->right(); // x might be null.
else
if (!y->right()) // z has exactly one non-null child. y == z.
x = y->left(); // x is not null.
else{ // z has two non-null children. Set y to
y = y->right(); // z's successor. x might be null.
while (y->left())
y = y->left();
x = y->right();
}
if (y != z) { // relink y in place of z. y is z's successor
z->left()->parent() = y;
y->left() = z->left();
if (y != z->right()) {
x_parent = y->parent();
if (x)
x->parent() = y->parent();
y->parent()->left() = x; // y must be a child of mp_left
y->right() = z->right();
z->right()->parent() = y;
}
else
x_parent = y;
replace_own(header, z, y);
y->parent() = z->parent();
std::swap(y->color(), z->color());
y = z;
// y now points to node to be actually deleted
}
else{ // y == z
x_parent = y->parent();
if (x)
x->parent() = y->parent();
replace_own(header, z, x);
if (leftmost == z)
if (!z->right()) // z->left must be null also
leftmost = z->parent();
// makes leftmost == this->m_header if z == root
else
leftmost = minimum_node(x);
if (rightmost == z)
if (!z->left()) // z->right must be null also
rightmost = z->parent();
// makes rightmost == this->m_header if z == root
else // x == z->left
rightmost = maximum_node(x);
}
if (y->color() != NodeBase::red_color) {
while (x != root && (!x || x->color() == NodeBase::black_color))
if (x == x_parent->left()) {
basic_node_pointer w = x_parent->right();
if (w->color() == NodeBase::red_color) {
w->color() = NodeBase::black_color;
x_parent->color() = NodeBase::red_color;
rotate_left(header, x_parent);
w = x_parent->right();
}
if ((!w->left() ||
w->left()->color() == NodeBase::black_color) &&
(!w->right() ||
w->right()->color() == NodeBase::black_color)) {
w->color() = NodeBase::red_color;
x = x_parent;
x_parent = x_parent->parent();
}
else{
if (!w->right() ||
w->right()->color() == NodeBase::black_color) {
if (w->left())
w->left()->color() = NodeBase::black_color;
w->color() = NodeBase::red_color;
rotate_right(header, w);
w = x_parent->right();
}
w->color() = x_parent->color();
x_parent->color() = NodeBase::black_color;
if (w->right())
w->right()->color() = NodeBase::black_color;
rotate_left(header, x_parent);
break;
}
}
else{
// same as above, with mp_right <-> mp_left.
basic_node_pointer w = x_parent->left();
if (w->color() == NodeBase::red_color) {
w->color() = NodeBase::black_color;
x_parent->color() = NodeBase::red_color;
rotate_right(header, x_parent);
w = x_parent->left();
}
if ((!w->right() ||
w->right()->color() == NodeBase::black_color) &&
(!w->left() ||
w->left()->color() == NodeBase::black_color)) {
w->color() = NodeBase::red_color;
x = x_parent;
x_parent = x_parent->parent();
}
else{
if (!w->left() ||
w->left()->color() == NodeBase::black_color) {
if (w->right())
w->right()->color() = NodeBase::black_color;
w->color() = NodeBase::red_color;
rotate_left(header, w);
w = x_parent->left();
}
w->color() = x_parent->color();
x_parent->color() = NodeBase::black_color;
if (w->left())
w->left()->color() = NodeBase::black_color;
rotate_right(header, x_parent);
break;
}
}
if (x)
x->color() = NodeBase::black_color;
}
return y;
}
static basic_node_pointer link_and_rebalance
(basic_node_pointer header, bool link_left, basic_node_pointer y, basic_node_pointer z)
{
if (link_left) {
y->left() = z; // also makes header->left() = z
// when y == _header
if (y == header) {
header->parent() = z;
header->right() = z;
}
else if (y == header->left())
header->left() = z; // maintain header->left() pointing to min node
}
else{
y->right() = z;
if (y == header->right())
header->right() = z; // maintain header->right() pointing to max node
}
z->parent() = y;
z->left() = 0;
z->right() = 0;
rebalance(header, z);
return z;
}
static void clear(basic_node_pointer header)
{
header->left() = header;
header->right() = header;
header->parent() = 0;
}
static bool empty(const basic_node_pointer &header) { return !header->parent(); }
};
/*!Basic red-black tree functions that only need
the comparison functor and functors to obtain the
key from a value*/
template <class Node, class Key, class KeyOfValue,
class KeyCompare>
class rb_tree_func : public rb_tree_algo<Node>
{
typedef rb_tree_algo<rb_tree_node_base<typename pointer_to_other
<typename Node::basic_node_pointer, void>::type> > rb_tree_algo_t;
// typedef rb_tree_algo<Node> rb_tree_algo_t;
typedef typename Node::node_pointer node_pointer;
typedef typename Node::basic_node_pointer basic_node_pointer;
static bool node_compare (const KeyCompare &key_compare,
const node_pointer &node,
const node_pointer &other_node)
{
return key_compare(KeyOfValue()(node->value()),
KeyOfValue()(other_node->value()));
}
public:
struct insert_unique_context
{
basic_node_pointer x;
basic_node_pointer y;
};
static node_pointer find(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
basic_node_pointer y = header; // Last node which is not less than k.
basic_node_pointer x = header->parent(); // Current node.
while (x) {
if (!(key_compare(KeyOfValue()(Node::downcast(x)->value()), k))){
y = x, x = x->left();
}
else{
x = x->right();
}
}
if(y == header || key_compare(k, KeyOfValue()(Node::downcast(y)->value()))){
y = header;
}
return Node::downcast(y);
}
static node_pointer upper_bound(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
basic_node_pointer y = header; //Last node which is greater than k.
basic_node_pointer x = header->parent(); //Current node.
while (x){
if (key_compare(k, KeyOfValue()(Node::downcast(x)->value()))){
y = x, x = x->left();
}
else{
x = x->right();
}
}
return Node::downcast(y);
}
static node_pointer lower_bound(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
basic_node_pointer y = header; // Last node which is not less than k.
basic_node_pointer x = header->parent(); // Current node.
while (x){
if (!key_compare(KeyOfValue()(Node::downcast(x)->value()), k)){
y = x, x = x->left();
}
else{
x = x->right();
}
}
return Node::downcast(y);
}
static bool insert_unique (const node_pointer &header,
const KeyCompare &key_compare,
node_pointer &new_node,
node_pointer &out)
{
insert_unique_context context;
if(!insert_unique_prepare(header, key_compare, KeyOfValue()(new_node->value()), out, context)){
return false;
}
insert_unique_commit(header, key_compare, new_node, out, context);
return true;
}
static bool insert_unique_hint(const node_pointer &header,
const KeyCompare &key_compare,
const node_pointer &hint,
node_pointer &new_node,
node_pointer &out)
{
insert_unique_context context;
if(!insert_unique_hint_prepare
(header, hint, key_compare, KeyOfValue()(new_node->value()), out, context)){
return false;
}
insert_unique_commit(header, key_compare, new_node, out, context);
return true;
}
static bool insert_unique_prepare (const node_pointer & header,
const KeyCompare &key_compare,
const Key &key,
node_pointer &out,
insert_unique_context &context)
{
basic_node_pointer &x = context.x;
basic_node_pointer &y = context.y;
bool comp = true, do_insert = false;
x = header->parent();
y = header;
while (x) {
y = x;
comp = key_compare(key, KeyOfValue()(Node::downcast(x)->value()));
x = comp ? x->left() : x->right();
}
out = Node::downcast(y);
if (comp){
if (out == header->left()){
return true;
}
else{
out = Node::downcast(rb_tree_algo_t::previous_node(out));
}
}
if (!do_insert && key_compare(KeyOfValue()(Node::downcast(out)->value()), key)){
return true;
}
return false;
}
static bool insert_unique_hint_prepare(const node_pointer &header,
const KeyCompare &key_compare,
const node_pointer &hint,
const Key &key,
node_pointer &out,
insert_unique_context &context)
{
if (hint == header->left()) { // this->begin()
if (!rb_tree_algo<Node>::empty(header) &&
key_compare(key, KeyOfValue()(hint->value()))){
context.x = hint;
context.y = hint;
return true;
}
// first argument just needs to be non-null
else{
return insert_unique_prepare(header, key_compare, key, out, context);
}
}
else if (hint == header) { // end()
if (key_compare(KeyOfValue()(Node::downcast(header->right())->value()), key)){
context.x = 0;
context.y = header->right();
return true;
}
else{
return insert_unique_prepare(header, key_compare, key, out, context);
}
}
else{
node_pointer before = hint;
before = Node::downcast(rb_tree_algo_t::previous_node(before));
if (key_compare(KeyOfValue()(before->value()), key)&&
key_compare(key, KeyOfValue()(hint->value())) ){
if (!before->right()){
context.x = 0;
context.y = before;
return true;
}
else{
context.x = hint;
context.y = hint;
return true;
// first argument just needs to be non-null
}
}
else{
return insert_unique_prepare(header, key_compare, key, out, context);
}
}
}
static void insert_unique_commit (const node_pointer &header,
const KeyCompare &key_compare,
node_pointer &new_node,
node_pointer &out,
insert_unique_context &context)
{
basic_node_pointer &x = context.x;
basic_node_pointer &y = context.y;
const bool link_left = (y == header) || x ||
node_compare(key_compare, new_node, Node::downcast(y));
out = Node::downcast(rb_tree_algo_t::link_and_rebalance(header, link_left, y, new_node));
}
static void insert_equal (const node_pointer & header,
const KeyCompare &key_compare,
node_pointer &new_node)
{
basic_node_pointer y = header;
basic_node_pointer x = header->parent();
while (x) {
y = x;
x = node_compare(key_compare, new_node, Node::downcast(x))
? x->left() : x->right();
}
bool link_left = (y == header) || node_compare(key_compare, new_node, Node::downcast(y));
rb_tree_algo_t::link_and_rebalance(header, link_left, y, new_node);
}
static void insert_equal_hint (const node_pointer & header,
const KeyCompare &key_compare,
const node_pointer &hint,
node_pointer &new_node)
{
if (rb_tree_algo<Node>::empty(header))
return insert_equal (header, key_compare, new_node);
node_pointer par = 0;
bool link_left = false;
if (hint == header->left()) {
if (node_compare(key_compare, new_node, hint)) {
par = hint;
link_left = true;
}
}
else if (hint == header) {
if (node_compare (key_compare, Node::downcast(header->right()), new_node)) {
par = header;
link_left = false;
}
}
else {
node_pointer before = hint;
before = Node::downcast(rb_tree_algo_t::previous_node(before));
if (node_compare (key_compare, before, new_node) &&
node_compare(key_compare, new_node, hint)) {
if (!before->right()) {
par = before;
link_left = false;
}
else {
par = hint;
link_left = true;
}
}
}
if (par) {
rb_tree_algo_t::link_and_rebalance(header, link_left, par, new_node);
}
else {
insert_equal(header, key_compare, new_node);
}
}
static std::size_t erase_with_key(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
node_pointer lower, upper, tmp;
rb_tree_algo_t::equal_range(header, k, lower, upper);
std::size_t count = 0;
while(lower != upper){
tmp = lower;
lower = rb_tree_algo_t::next_node(lower);
rb_tree_algo_t::erase(header, tmp);
++count;
}
return count;
}
static void equal_range(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k,
node_pointer &lower,
node_pointer &upper)
{
lower = lower_bound(header, key_compare, k);
upper = upper_bound(header, key_compare, k);
}
static std::size_t count(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
node_pointer lower, upper;
equal_range(header, key_compare, k, lower, upper);
std::size_t count = 0;
while(lower != upper){
lower = Node::downcast(rb_tree_algo_t::next_node(lower));
++count;
}
return count;
}
};
template <class Node>
class rb_tree_const_iterator
: public boost::iterator<std::bidirectional_iterator_tag,
typename Node::value_type,
typename Node::difference_type,
typename Node::const_pointer,
typename Node::const_reference>
{
private:
typedef boost::iterator<std::bidirectional_iterator_tag,
typename Node::value_type,
typename Node::difference_type,
typename Node::const_pointer,
typename Node::const_reference> base_t;
protected:
typedef typename Node::node_pointer node_pointer;
typedef typename Node::basic_node_pointer basic_node_pointer;
typedef rb_tree_algo<Node> rb_tree_algo_t;
node_pointer mp_node;
public:
typedef typename base_t::pointer pointer;
typedef typename base_t::reference reference;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
typedef typename base_t::value_type value_type;
rb_tree_const_iterator()
{}
explicit rb_tree_const_iterator(const node_pointer &x)
: mp_node(x)
{}
explicit rb_tree_const_iterator(const basic_node_pointer &x)
: mp_node(Node::downcast(x))
{}
rb_tree_const_iterator(const rb_tree_const_iterator & it)
: mp_node(it.get_ptr())
{}
reference operator*() const
{ return mp_node->value(); }
pointer operator->() const
{ return pointer(&mp_node->value()); }
rb_tree_const_iterator& operator++()
{
mp_node = Node::downcast(rb_tree_algo_t::next_node(mp_node));
return *this;
}
rb_tree_const_iterator operator++(int)
{
rb_tree_const_iterator tmp = *this;
mp_node = rb_tree_algo_t::next_node(mp_node);
return tmp;
}
rb_tree_const_iterator& operator--()
{
mp_node = rb_tree_algo_t::previous_node(mp_node);
return *this;
}
rb_tree_const_iterator operator--(int)
{
rb_tree_const_iterator tmp = *this;
mp_node = rb_tree_algo_t::previous_node(mp_node);
return tmp;
}
friend bool operator==(const rb_tree_const_iterator& x, const rb_tree_const_iterator& y)
{ return x.get_ptr() == y.get_ptr(); }
friend bool operator!=(const rb_tree_const_iterator& x, const rb_tree_const_iterator& y)
{ return x.get_ptr() != y.get_ptr(); }
node_pointer &get_ptr()
{ return mp_node; }
const node_pointer &get_ptr() const
{ return mp_node; }
};
//list rb_tree_iterator
template <class Node>
class rb_tree_iterator : public rb_tree_const_iterator<Node>
{
private:
typedef rb_tree_const_iterator<Node> base_t;
typedef typename base_t::node_pointer node_pointer;
typedef typename base_t::basic_node_pointer basic_node_pointer;
public:
typedef typename Node::pointer pointer;
typedef typename Node::reference reference;
//Constructors
rb_tree_iterator()
{}
explicit rb_tree_iterator(const node_pointer &ptr)
: base_t(ptr)
{}
explicit rb_tree_iterator(const basic_node_pointer &ptr)
: base_t(ptr)
{}
//Pointer like operators
reference operator*() const { return this->mp_node->value(); }
pointer operator->() const { return pointer(&this->mp_node->value()); }
//Increment / Decrement
rb_tree_iterator& operator++()
{ base_t::operator++(); return *this; }
rb_tree_iterator operator++(int)
{ node_pointer tmp = this->mp_node; ++*this; return rb_tree_iterator(tmp); }
rb_tree_iterator& operator--()
{ base_t::operator--(); return *this; }
rb_tree_iterator operator--(int)
{ rb_tree_iterator tmp = *this; --*this; return tmp; }
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_TREE_FUNC_HPP

View File

@@ -0,0 +1,629 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
///////////////////////////////////////////////////////////////////////////////
//
// Parts of this file come from SGI's stl_tree.h and stl_algo.h files.
// Modified by Ion Gaztañaga 2005.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
// Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
// purpose is hereby granted without fee, provided that the above copyright
// notice appear in all copies and that both that copyright notice and this
// permission notice appear in supporting documentation.
// The author or Addison-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
///////////////////////////////////////////////////////////////////////////////
//
// Parts of this file come from AssocVector.h file from Loki library
//
////////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_FLAT_TREE_HPP
#define BOOST_INTERPROCESS_FLAT_TREE_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/containers/vector.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <algorithm>
#include <functional>
#include <utility>
namespace boost {
namespace interprocess {
namespace detail {
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
class flat_tree
{
typedef boost::interprocess::vector<Value, Alloc> vector_t;
typedef typename vector_t::allocator_type allocator_t;
public:
class value_compare
: private Compare
{
typedef Value first_argument_type;
typedef Value second_argument_type;
typedef bool return_type;
public:
value_compare(const Compare &pred)
: Compare(pred)
{}
bool operator()(const Value& lhs, const Value& rhs) const
{
KeyOfValue key_extract;
return Compare::operator()(key_extract(lhs), key_extract(rhs));
}
const Compare &get_comp() const
{ return *this; }
Compare &get_comp()
{ return *this; }
};
private:
struct Data
//Inherit from value_compare to do EBO
: public value_compare
{
public:
Data(const Compare &comp,
const vector_t &vect)
: value_compare(comp), m_vect(vect){}
Data(const value_compare &comp,
const vector_t &vect)
: value_compare(comp), m_vect(vect){}
Data(const Compare &comp,
const allocator_t &alloc)
: value_compare(comp), m_vect(alloc){}
public:
vector_t m_vect;
};
Data m_data;
public:
typedef typename vector_t::value_type value_type;
typedef typename vector_t::pointer pointer;
typedef typename vector_t::const_pointer const_pointer;
typedef typename vector_t::reference reference;
typedef typename vector_t::const_reference const_reference;
typedef Key key_type;
typedef Compare key_compare;
typedef typename vector_t::allocator_type allocator_type;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef typename vector_t::iterator iterator;
typedef typename vector_t::const_iterator const_iterator;
typedef boost::reverse_iterator<iterator> reverse_iterator;
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
// allocation/deallocation
flat_tree(const Compare& comp = Compare(),
const allocator_type& a = allocator_type())
: m_data(comp, a)
{ }
flat_tree(const flat_tree& x)
: m_data(x.m_data, x.m_data.m_vect)
{ }
~flat_tree() { }
flat_tree& operator=(const flat_tree& x)
{ flat_tree(x).swap(*this); return *this; }
public:
// accessors:
Compare key_comp() const
{ return this->m_data.get_comp(); }
allocator_type get_allocator() const
{ return this->m_data.m_vect.get_allocator(); }
iterator begin()
{ return this->m_data.m_vect.begin(); }
const_iterator begin() const
{ return this->m_data.m_vect.begin(); }
iterator end()
{ return this->m_data.m_vect.end(); }
const_iterator end() const
{ return this->m_data.m_vect.end(); }
reverse_iterator rbegin()
{ return reverse_iterator(this->end()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(this->end()); }
reverse_iterator rend()
{ return reverse_iterator(this->begin()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(this->begin()); }
bool empty() const
{ return this->m_data.m_vect.empty(); }
size_type size() const
{ return this->m_data.m_vect.size(); }
size_type max_size() const
{ return this->m_data.m_vect.max_size(); }
void swap(flat_tree& other)
{
vector_t & myvect = this->m_data.m_vect;
vector_t & othervect = other.m_data.m_vect;
myvect.swap(othervect);
value_compare& mycomp = this->m_data;
value_compare& othercomp = other.m_data;
detail::do_swap(mycomp, othercomp);
}
public:
// insert/erase
std::pair<iterator,bool> insert_unique(const value_type& val)
{ return this->priv_insert_unique(this->begin(), this->end(), val); }
// insert/erase
std::pair<iterator,bool> priv_insert_unique
(iterator beg, iterator end, const value_type& val)
{
bool found = true;
const value_compare &value_comp = this->m_data;
iterator i = this->priv_lower_bound(beg, end, KeyOfValue()(val));
if (i == end || value_comp(val, *i)){
i = this->m_data.m_vect.insert(i, val);
found = false;
}
return std::make_pair(i, !found);
}
iterator insert_equal(const value_type& val)
{
iterator i = this->upper_bound(KeyOfValue()(val));
i = this->m_data.m_vect.insert(i, val);
return i;
}
iterator insert_unique(iterator pos, const value_type& val)
{
/* old code
const value_compare &value_comp = this->m_data;
if (pos != this->end() && value_comp(*pos, val)){
if(++pos == this->end() ||
!value_comp(*pos, val)){
if(value_comp(val, *pos))
return this->m_data.m_vect.insert(pos, val);
else
return pos;
}
}
return insert_unique(val).first;
*/
/* N1780
To insert val at pos:
if pos == end || val <= *pos
if pos == begin || val >= *(pos-1)
insert val before pos
else
insert val before upper_bound(val)
else if pos+1 == end || val <= *(pos+1)
insert val after pos
else
insert val before lower_bound(val)
*/
const value_compare &value_comp = this->m_data;
if(pos == this->end() || value_comp(val, *pos)){
if(pos != this->begin() && !value_comp(val, pos[-1])){
if(value_comp(pos[-1], val)){
return this->m_data.m_vect.insert(pos, val);
}
else{
return pos;
}
}
return this->priv_insert_unique(this->begin(), pos, val).first;
}
/* Works, but increases code complexity
//Next check
else if (value_comp(*pos, val) && !value_comp(pos[1], val)){
if(value_comp(val, pos[1])){
return this->m_data.m_vect.insert(pos+1, val);
}
else{
return pos;
}
}*/
else{
//[... pos ... val ... ]
//The hint is before the insertion position, so insert it
//in the remaining range
return this->priv_insert_unique(pos, this->end(), val).first;
}
}
iterator insert_equal(iterator pos, const value_type& val)
{
/* N1780
To insert val at pos:
if pos == end || val <= *pos
if pos == begin || val >= *(pos-1)
insert val before pos
else
insert val before upper_bound(val)
else if pos+1 == end || val <= *(pos+1)
insert val after pos
else
insert val before lower_bound(val)
*/
const value_compare &value_comp = this->m_data;
if(pos == this->end() || !value_comp(*pos, val)){
if (pos == this->begin() || !value_comp(val, pos[-1])){
return this->m_data.m_vect.insert(pos, val);
}
else{
return this->m_data.m_vect.insert
// (this->upper_bound(KeyOfValue()(val)), val);
(this->priv_upper_bound(this->begin(), pos, KeyOfValue()(val)), val);
}
}
/*Works, but increases code complexity
else if (++pos == this->end() || !value_comp(*pos, val)){
return this->m_data.m_vect.insert(pos, val);
}
*/
else{
return this->m_data.m_vect.insert
//(this->lower_bound(KeyOfValue()(val)), val);
(this->priv_lower_bound(pos, this->end(), KeyOfValue()(val)), val);
}
}
template <class InIt>
void insert_unique(InIt first, InIt last)
{
for ( ; first != last; ++first)
this->insert_unique(*first);
}
template <class InIt>
void insert_equal(InIt first, InIt last)
{
for ( ; first != last; ++first)
this->insert_equal(*first);
}
iterator erase(const_iterator position)
{ return this->m_data.m_vect.erase(position); }
size_type erase(const key_type& k)
{
std::pair<iterator,iterator > itp = this->equal_range(k);
size_type ret = static_cast<size_type>(itp.second-itp.first);
if (ret){
this->erase(itp.first, itp.second);
}
return ret;
}
iterator erase(const_iterator first, const_iterator last)
{ return this->m_data.m_vect.erase(first, last); }
void clear()
{ this->m_data.m_vect.clear(); }
// set operations:
iterator find(const key_type& k)
{
const Compare &key_comp = this->m_data.get_comp();
iterator i = this->lower_bound(k);
if (i != this->end() && key_comp(k, KeyOfValue()(*i))){
i = this->end();
}
return i;
}
const_iterator find(const key_type& k) const
{
const Compare &key_comp = this->m_data.get_comp();
const_iterator i = this->lower_bound(k);
if (i != this->end() && key_comp(k, KeyOfValue()(*i))){
i = this->end();
}
return i;
}
size_type count(const key_type& k) const
{
std::pair<const_iterator, const_iterator> p = this->equal_range(k);
size_type n = p.second - p.first;
return n;
}
iterator lower_bound(const key_type& k)
{
return this->priv_lower_bound(this->begin(), this->end(), k);
}
const_iterator lower_bound(const key_type& k) const
{
return this->priv_lower_bound(this->begin(), this->end(), k);
}
iterator upper_bound(const key_type& k)
{
return this->priv_upper_bound(this->begin(), this->end(), k);
}
const_iterator upper_bound(const key_type& k) const
{
return this->priv_upper_bound(this->begin(), this->end(), k);
}
std::pair<iterator,iterator> equal_range(const key_type& k)
{
return this->priv_equal_range(this->begin(), this->end(), k);
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
{
return this->priv_equal_range(this->begin(), this->end(), k);
}
size_type capacity() const
{ return this->m_data.m_vect.capacity(); }
void reserve(size_type count)
{ this->m_data.m_vect.reserve(count); }
private:
template <class RanIt>
RanIt priv_lower_bound(RanIt first, RanIt last,
const key_type & key) const
{
const Compare &key_comp = this->m_data.get_comp();
KeyOfValue key_extract;
difference_type len = last - first, half;
RanIt middle;
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (key_comp(key_extract(*middle), key)) {
++middle;
first = middle;
len = len - half - 1;
}
else
len = half;
}
return first;
}
template <class RanIt>
RanIt priv_upper_bound(RanIt first, RanIt last,
const key_type & key) const
{
const Compare &key_comp = this->m_data.get_comp();
KeyOfValue key_extract;
difference_type len = last - first, half;
RanIt middle;
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (key_comp(key, key_extract(*middle))) {
len = half;
}
else{
first = ++middle;
len = len - half - 1;
}
}
return first;
}
template <class RanIt>
std::pair<RanIt, RanIt>
priv_equal_range(RanIt first, RanIt last, const key_type& key) const
{
const Compare &key_comp = this->m_data.get_comp();
KeyOfValue key_extract;
difference_type len = last - first, half;
RanIt middle, left, right;
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (key_comp(key_extract(*middle), key)){
first = middle;
++first;
len = len - half - 1;
}
else if (key_comp(key, key_extract(*middle))){
len = half;
}
else {
left = this->priv_lower_bound(first, middle, key);
first += len;
right = this->priv_upper_bound(++middle, first, key);
return std::pair<RanIt, RanIt>(left, right);
}
}
return std::pair<RanIt, RanIt>(first, first);
}
template <class FwdIt>
void priv_insert_unique(FwdIt first, FwdIt last, std::forward_iterator_tag)
{
size_type len = static_cast<size_type>(std::distance(first, last));
this->reserve(this->size()+len);
priv_insert_unique(first, last, std::input_iterator_tag());
}
template <class FwdIt>
void priv_insert_equal(FwdIt first, FwdIt last, std::forward_iterator_tag)
{
size_type len = static_cast<size_type>(std::distance(first, last));
this->reserve(this->size()+len);
this->priv_insert_equal(first, last, std::input_iterator_tag());
}
template <class InIt>
void priv_insert_unique(InIt first, InIt last, std::input_iterator_tag)
{
for ( ; first != last; ++first)
this->insert_unique(*first);
}
template <class InIt>
void priv_insert_equal(InIt first, InIt last, std::input_iterator_tag)
{
for ( ; first != last; ++first)
this->insert_equal(*first);
}
};
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator==(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return x.size() == y.size() &&
std::equal(x.begin(), x.end(), y.begin());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return std::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator!=(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return !(x == y); }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return y < x; }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<=(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return !(y < x); }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>=(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return !(x < y); }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline void
swap(flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ x.swap(y); }
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_FLAT_TREE_HPP

View File

@@ -0,0 +1,857 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_tree file. Modified by Ion Gaztañaga 2005.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_TREE_FUNC_HPP
#define BOOST_INTERPROCESS_TREE_FUNC_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/iterator.hpp>
namespace boost {
namespace interprocess {
namespace detail {
template <class VoidPointer>
struct rb_tree_node_base
{
typedef typename boost::interprocess::detail::pointer_to_other
<VoidPointer, rb_tree_node_base<VoidPointer> >::type basic_node_pointer;
enum color_t { red_color = false, black_color = true };
const basic_node_pointer &parent() const { return mp_parent; }
basic_node_pointer &parent() { return mp_parent; }
const basic_node_pointer &left() const { return mp_left; }
basic_node_pointer &left() { return mp_left; }
const basic_node_pointer &right() const { return mp_right; }
basic_node_pointer &right() { return mp_right; }
const color_t &color() const { return m_color; }
color_t &color() { return m_color; }
private:
basic_node_pointer mp_parent;
basic_node_pointer mp_left;
basic_node_pointer mp_right;
color_t m_color;
};
/*!Basic red-black tree functions that don't need
comparison operator*/
template <class NodeBase>
class rb_tree_algo
{
typedef typename NodeBase::basic_node_pointer basic_node_pointer;
public:
static basic_node_pointer next_node(basic_node_pointer node)
{
if (node->right()) {
node = node->right();
while (node->left()){
node = node->left();
}
}
else{
basic_node_pointer y = node->parent();
while (node == y->right()) {
node = y;
y = y->parent();
}
if (node->right() != y)
node = y;
}
return node;
}
static basic_node_pointer previous_node(basic_node_pointer node)
{
if (node->color() == NodeBase::red_color &&
node->parent()->parent() == node){
node = node->right();
}
else if (node->left()) {
basic_node_pointer y = node->left();
while (y->right()){
y = y->right();
}
node = y;
}
else{
basic_node_pointer y = node->parent();
while (node == y->left()) {
node = y;
y = y->parent();
}
node = y;
}
return node;
}
static bool is_header (const basic_node_pointer p)
{
return p->color() == NodeBase::red_color && p->parent()->parent() == p;
}
static basic_node_pointer minimum_node(basic_node_pointer x)
{
while (x->left()){
x = x->left();
}
return x;
}
static basic_node_pointer maximum_node(basic_node_pointer x)
{
while (x->right()){
x = x->right();
}
return x;
}
static void replace_own (const basic_node_pointer &header,
const basic_node_pointer &own,
const basic_node_pointer &p)
{
if (header->parent() == own)
header->parent() = p;
else if (own->parent()->left() == own)
own->parent()->left() = p;
else
own->parent()->right() = p;
}
static void rotate_left(const basic_node_pointer &header, basic_node_pointer x)
{
basic_node_pointer y = x->right();
x->right() = y->left();
if (y->left() !=0)
y->left()->parent() = x;
y->parent() = x->parent();
replace_own(header, x, y);
y->left() = x;
x->parent() = y;
}
static void rotate_right(const basic_node_pointer &header, basic_node_pointer x)
{
basic_node_pointer y = x->left();
x->left() = y->right();
if (y->right())
y->right()->parent() = x;
y->parent() = x->parent();
replace_own(header, x, y);
y->right() = x;
x->parent() = y;
}
static void rebalance(const basic_node_pointer &header, basic_node_pointer x)
{
x->color() = NodeBase::red_color;
while (x != header->parent() && x->parent()->color() == NodeBase::red_color) {
if (x->parent() == x->parent()->parent()->left()) {
basic_node_pointer y = x->parent()->parent()->right();
if (y && y->color() == NodeBase::red_color) {
x->parent()->color() = NodeBase::black_color;
y->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
x = x->parent()->parent();
}
else{
if (x == x->parent()->right()) {
x = x->parent();
rotate_left(header, x);
}
x->parent()->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
rotate_right(header, x->parent()->parent());
}
}
else{
basic_node_pointer y = x->parent()->parent()->left();
if (y && y->color() == NodeBase::red_color) {
x->parent()->color() = NodeBase::black_color;
y->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
x = x->parent()->parent();
}
else{
if (x == x->parent()->left()) {
x = x->parent();
rotate_right(header, x);
}
x->parent()->color() = NodeBase::black_color;
x->parent()->parent()->color() = NodeBase::red_color;
rotate_left(header, x->parent()->parent());
}
}
}
header->parent()->color() = NodeBase::black_color;
}
static basic_node_pointer erase_node
(const basic_node_pointer &header, basic_node_pointer z)
{
basic_node_pointer& root = header->parent();
basic_node_pointer& leftmost = header->left();
basic_node_pointer& rightmost = header->right();
basic_node_pointer y = z;
basic_node_pointer x = 0;
basic_node_pointer x_parent = 0;
if (!y->left()) // z has at most one non-null child. y == z.
x = y->right(); // x might be null.
else
if (!y->right()) // z has exactly one non-null child. y == z.
x = y->left(); // x is not null.
else{ // z has two non-null children. Set y to
y = y->right(); // z's successor. x might be null.
while (y->left())
y = y->left();
x = y->right();
}
if (y != z) { // relink y in place of z. y is z's successor
z->left()->parent() = y;
y->left() = z->left();
if (y != z->right()) {
x_parent = y->parent();
if (x)
x->parent() = y->parent();
y->parent()->left() = x; // y must be a child of mp_left
y->right() = z->right();
z->right()->parent() = y;
}
else
x_parent = y;
replace_own(header, z, y);
y->parent() = z->parent();
std::swap(y->color(), z->color());
y = z;
// y now points to node to be actually deleted
}
else{ // y == z
x_parent = y->parent();
if (x)
x->parent() = y->parent();
replace_own(header, z, x);
if (leftmost == z)
if (!z->right()) // z->left must be null also
leftmost = z->parent();
// makes leftmost == this->m_header if z == root
else
leftmost = minimum_node(x);
if (rightmost == z)
if (!z->left()) // z->right must be null also
rightmost = z->parent();
// makes rightmost == this->m_header if z == root
else // x == z->left
rightmost = maximum_node(x);
}
if (y->color() != NodeBase::red_color) {
while (x != root && (!x || x->color() == NodeBase::black_color))
if (x == x_parent->left()) {
basic_node_pointer w = x_parent->right();
if (w->color() == NodeBase::red_color) {
w->color() = NodeBase::black_color;
x_parent->color() = NodeBase::red_color;
rotate_left(header, x_parent);
w = x_parent->right();
}
if ((!w->left() ||
w->left()->color() == NodeBase::black_color) &&
(!w->right() ||
w->right()->color() == NodeBase::black_color)) {
w->color() = NodeBase::red_color;
x = x_parent;
x_parent = x_parent->parent();
}
else{
if (!w->right() ||
w->right()->color() == NodeBase::black_color) {
if (w->left())
w->left()->color() = NodeBase::black_color;
w->color() = NodeBase::red_color;
rotate_right(header, w);
w = x_parent->right();
}
w->color() = x_parent->color();
x_parent->color() = NodeBase::black_color;
if (w->right())
w->right()->color() = NodeBase::black_color;
rotate_left(header, x_parent);
break;
}
}
else{
// same as above, with mp_right <-> mp_left.
basic_node_pointer w = x_parent->left();
if (w->color() == NodeBase::red_color) {
w->color() = NodeBase::black_color;
x_parent->color() = NodeBase::red_color;
rotate_right(header, x_parent);
w = x_parent->left();
}
if ((!w->right() ||
w->right()->color() == NodeBase::black_color) &&
(!w->left() ||
w->left()->color() == NodeBase::black_color)) {
w->color() = NodeBase::red_color;
x = x_parent;
x_parent = x_parent->parent();
}
else{
if (!w->left() ||
w->left()->color() == NodeBase::black_color) {
if (w->right())
w->right()->color() = NodeBase::black_color;
w->color() = NodeBase::red_color;
rotate_left(header, w);
w = x_parent->left();
}
w->color() = x_parent->color();
x_parent->color() = NodeBase::black_color;
if (w->left())
w->left()->color() = NodeBase::black_color;
rotate_right(header, x_parent);
break;
}
}
if (x)
x->color() = NodeBase::black_color;
}
return y;
}
static basic_node_pointer link_and_rebalance
(basic_node_pointer header, bool link_left, basic_node_pointer y, basic_node_pointer z)
{
if (link_left) {
y->left() = z; // also makes header->left() = z
// when y == _header
if (y == header) {
header->parent() = z;
header->right() = z;
}
else if (y == header->left())
header->left() = z; // maintain header->left() pointing to min node
}
else{
y->right() = z;
if (y == header->right())
header->right() = z; // maintain header->right() pointing to max node
}
z->parent() = y;
z->left() = 0;
z->right() = 0;
rebalance(header, z);
return z;
}
static void clear(basic_node_pointer header)
{
header->left() = header;
header->right() = header;
header->parent() = 0;
}
static bool empty(const basic_node_pointer &header) { return !header->parent(); }
};
/*!Basic red-black tree functions that only need
the comparison functor and functors to obtain the
key from a value*/
template <class Node, class Key, class KeyOfValue,
class KeyCompare>
class rb_tree_func : public rb_tree_algo<Node>
{
typedef rb_tree_algo<rb_tree_node_base<typename pointer_to_other
<typename Node::basic_node_pointer, void>::type> > rb_tree_algo_t;
// typedef rb_tree_algo<Node> rb_tree_algo_t;
typedef typename Node::node_pointer node_pointer;
typedef typename Node::basic_node_pointer basic_node_pointer;
static bool node_compare (const KeyCompare &key_compare,
const node_pointer &node,
const node_pointer &other_node)
{
return key_compare(KeyOfValue()(node->value()),
KeyOfValue()(other_node->value()));
}
public:
struct insert_unique_context
{
basic_node_pointer x;
basic_node_pointer y;
};
static node_pointer find(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
basic_node_pointer y = header; // Last node which is not less than k.
basic_node_pointer x = header->parent(); // Current node.
while (x) {
if (!(key_compare(KeyOfValue()(Node::downcast(x)->value()), k))){
y = x, x = x->left();
}
else{
x = x->right();
}
}
if(y == header || key_compare(k, KeyOfValue()(Node::downcast(y)->value()))){
y = header;
}
return Node::downcast(y);
}
static node_pointer upper_bound(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
basic_node_pointer y = header; //Last node which is greater than k.
basic_node_pointer x = header->parent(); //Current node.
while (x){
if (key_compare(k, KeyOfValue()(Node::downcast(x)->value()))){
y = x, x = x->left();
}
else{
x = x->right();
}
}
return Node::downcast(y);
}
static node_pointer lower_bound(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
basic_node_pointer y = header; // Last node which is not less than k.
basic_node_pointer x = header->parent(); // Current node.
while (x){
if (!key_compare(KeyOfValue()(Node::downcast(x)->value()), k)){
y = x, x = x->left();
}
else{
x = x->right();
}
}
return Node::downcast(y);
}
static bool insert_unique (const node_pointer &header,
const KeyCompare &key_compare,
node_pointer &new_node,
node_pointer &out)
{
insert_unique_context context;
if(!insert_unique_prepare(header, key_compare, KeyOfValue()(new_node->value()), out, context)){
return false;
}
insert_unique_commit(header, key_compare, new_node, out, context);
return true;
}
static bool insert_unique_hint(const node_pointer &header,
const KeyCompare &key_compare,
const node_pointer &hint,
node_pointer &new_node,
node_pointer &out)
{
insert_unique_context context;
if(!insert_unique_hint_prepare
(header, hint, key_compare, KeyOfValue()(new_node->value()), out, context)){
return false;
}
insert_unique_commit(header, key_compare, new_node, out, context);
return true;
}
static bool insert_unique_prepare (const node_pointer & header,
const KeyCompare &key_compare,
const Key &key,
node_pointer &out,
insert_unique_context &context)
{
basic_node_pointer &x = context.x;
basic_node_pointer &y = context.y;
bool comp = true, do_insert = false;
x = header->parent();
y = header;
while (x) {
y = x;
comp = key_compare(key, KeyOfValue()(Node::downcast(x)->value()));
x = comp ? x->left() : x->right();
}
out = Node::downcast(y);
if (comp){
if (out == header->left()){
return true;
}
else{
out = Node::downcast(rb_tree_algo_t::previous_node(out));
}
}
if (!do_insert && key_compare(KeyOfValue()(Node::downcast(out)->value()), key)){
return true;
}
return false;
}
static bool insert_unique_hint_prepare(const node_pointer &header,
const KeyCompare &key_compare,
const node_pointer &hint,
const Key &key,
node_pointer &out,
insert_unique_context &context)
{
if (hint == header->left()) { // this->begin()
if (!rb_tree_algo<Node>::empty(header) &&
key_compare(key, KeyOfValue()(hint->value()))){
context.x = hint;
context.y = hint;
return true;
}
// first argument just needs to be non-null
else{
return insert_unique_prepare(header, key_compare, key, out, context);
}
}
else if (hint == header) { // end()
if (key_compare(KeyOfValue()(Node::downcast(header->right())->value()), key)){
context.x = 0;
context.y = header->right();
return true;
}
else{
return insert_unique_prepare(header, key_compare, key, out, context);
}
}
else{
node_pointer before = hint;
before = Node::downcast(rb_tree_algo_t::previous_node(before));
if (key_compare(KeyOfValue()(before->value()), key)&&
key_compare(key, KeyOfValue()(hint->value())) ){
if (!before->right()){
context.x = 0;
context.y = before;
return true;
}
else{
context.x = hint;
context.y = hint;
return true;
// first argument just needs to be non-null
}
}
else{
return insert_unique_prepare(header, key_compare, key, out, context);
}
}
}
static void insert_unique_commit (const node_pointer &header,
const KeyCompare &key_compare,
node_pointer &new_node,
node_pointer &out,
insert_unique_context &context)
{
basic_node_pointer &x = context.x;
basic_node_pointer &y = context.y;
const bool link_left = (y == header) || x ||
node_compare(key_compare, new_node, Node::downcast(y));
out = Node::downcast(rb_tree_algo_t::link_and_rebalance(header, link_left, y, new_node));
}
static void insert_equal (const node_pointer & header,
const KeyCompare &key_compare,
node_pointer &new_node)
{
basic_node_pointer y = header;
basic_node_pointer x = header->parent();
while (x) {
y = x;
x = node_compare(key_compare, new_node, Node::downcast(x))
? x->left() : x->right();
}
bool link_left = (y == header) || node_compare(key_compare, new_node, Node::downcast(y));
rb_tree_algo_t::link_and_rebalance(header, link_left, y, new_node);
}
static void insert_equal_hint (const node_pointer & header,
const KeyCompare &key_compare,
const node_pointer &hint,
node_pointer &new_node)
{
if (rb_tree_algo<Node>::empty(header))
return insert_equal (header, key_compare, new_node);
node_pointer par = 0;
bool link_left = false;
if (hint == header->left()) {
if (node_compare(key_compare, new_node, hint)) {
par = hint;
link_left = true;
}
}
else if (hint == header) {
if (node_compare (key_compare, Node::downcast(header->right()), new_node)) {
par = header;
link_left = false;
}
}
else {
node_pointer before = hint;
before = Node::downcast(rb_tree_algo_t::previous_node(before));
if (node_compare (key_compare, before, new_node) &&
node_compare(key_compare, new_node, hint)) {
if (!before->right()) {
par = before;
link_left = false;
}
else {
par = hint;
link_left = true;
}
}
}
if (par) {
rb_tree_algo_t::link_and_rebalance(header, link_left, par, new_node);
}
else {
insert_equal(header, key_compare, new_node);
}
}
static std::size_t erase_with_key(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
node_pointer lower, upper, tmp;
rb_tree_algo_t::equal_range(header, k, lower, upper);
std::size_t count = 0;
while(lower != upper){
tmp = lower;
lower = rb_tree_algo_t::next_node(lower);
rb_tree_algo_t::erase(header, tmp);
++count;
}
return count;
}
static void equal_range(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k,
node_pointer &lower,
node_pointer &upper)
{
lower = lower_bound(header, key_compare, k);
upper = upper_bound(header, key_compare, k);
}
static std::size_t count(const node_pointer &header,
const KeyCompare &key_compare,
const Key& k)
{
node_pointer lower, upper;
equal_range(header, key_compare, k, lower, upper);
std::size_t count = 0;
while(lower != upper){
lower = Node::downcast(rb_tree_algo_t::next_node(lower));
++count;
}
return count;
}
};
template <class Node>
class rb_tree_const_iterator
: public boost::iterator<std::bidirectional_iterator_tag,
typename Node::value_type,
typename Node::difference_type,
typename Node::const_pointer,
typename Node::const_reference>
{
private:
typedef boost::iterator<std::bidirectional_iterator_tag,
typename Node::value_type,
typename Node::difference_type,
typename Node::const_pointer,
typename Node::const_reference> base_t;
protected:
typedef typename Node::node_pointer node_pointer;
typedef typename Node::basic_node_pointer basic_node_pointer;
typedef rb_tree_algo<Node> rb_tree_algo_t;
node_pointer mp_node;
public:
typedef typename base_t::pointer pointer;
typedef typename base_t::reference reference;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
typedef typename base_t::value_type value_type;
rb_tree_const_iterator()
{}
explicit rb_tree_const_iterator(const node_pointer &x)
: mp_node(x)
{}
explicit rb_tree_const_iterator(const basic_node_pointer &x)
: mp_node(Node::downcast(x))
{}
rb_tree_const_iterator(const rb_tree_const_iterator & it)
: mp_node(it.get_ptr())
{}
reference operator*() const
{ return mp_node->value(); }
pointer operator->() const
{ return pointer(&mp_node->value()); }
rb_tree_const_iterator& operator++()
{
mp_node = Node::downcast(rb_tree_algo_t::next_node(mp_node));
return *this;
}
rb_tree_const_iterator operator++(int)
{
rb_tree_const_iterator tmp = *this;
mp_node = rb_tree_algo_t::next_node(mp_node);
return tmp;
}
rb_tree_const_iterator& operator--()
{
mp_node = rb_tree_algo_t::previous_node(mp_node);
return *this;
}
rb_tree_const_iterator operator--(int)
{
rb_tree_const_iterator tmp = *this;
mp_node = rb_tree_algo_t::previous_node(mp_node);
return tmp;
}
friend bool operator==(const rb_tree_const_iterator& x, const rb_tree_const_iterator& y)
{ return x.get_ptr() == y.get_ptr(); }
friend bool operator!=(const rb_tree_const_iterator& x, const rb_tree_const_iterator& y)
{ return x.get_ptr() != y.get_ptr(); }
node_pointer &get_ptr()
{ return mp_node; }
const node_pointer &get_ptr() const
{ return mp_node; }
};
//list rb_tree_iterator
template <class Node>
class rb_tree_iterator : public rb_tree_const_iterator<Node>
{
private:
typedef rb_tree_const_iterator<Node> base_t;
typedef typename base_t::node_pointer node_pointer;
typedef typename base_t::basic_node_pointer basic_node_pointer;
public:
typedef typename Node::pointer pointer;
typedef typename Node::reference reference;
//Constructors
rb_tree_iterator()
{}
explicit rb_tree_iterator(const node_pointer &ptr)
: base_t(ptr)
{}
explicit rb_tree_iterator(const basic_node_pointer &ptr)
: base_t(ptr)
{}
//Pointer like operators
reference operator*() const { return this->mp_node->value(); }
pointer operator->() const { return pointer(&this->mp_node->value()); }
//Increment / Decrement
rb_tree_iterator& operator++()
{ base_t::operator++(); return *this; }
rb_tree_iterator operator++(int)
{ node_pointer tmp = this->mp_node; ++*this; return rb_tree_iterator(tmp); }
rb_tree_iterator& operator--()
{ base_t::operator--(); return *this; }
rb_tree_iterator operator--(int)
{ rb_tree_iterator tmp = *this; --*this; return tmp; }
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_TREE_FUNC_HPP

View File

@@ -0,0 +1,505 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_map/stl_multimap files.
// Modified by Ion Gaztañaga 2005.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_FLAT_MAP_HPP
#define BOOST_INTERPROCESS_FLAT_MAP_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 <utility>
#include <functional>
#include <memory>
#include <boost/interprocess/containers/detail/flat_tree.hpp>
namespace boost { namespace interprocess {
// Forward declarations of operators == and <, needed for friend declarations.
template <class Key, class T, class Pred, class Alloc>
class flat_map;
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
class flat_map
{
private:
typedef detail::flat_tree<Key,
std::pair<Key, T>,
detail::select1st< std::pair<Key, T> >,
Pred,
Alloc> tree_t;
tree_t m_flat_tree; // flat tree representing flat_map
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef typename tree_t::value_compare value_compare;
typedef T mapped_type;
typedef typename tree_t::key_compare key_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
// allocation/deallocation
explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type())
: m_flat_tree(comp, a) {}
template <class InputIterator>
flat_map(InputIterator first, InputIterator last)
: m_flat_tree(Pred(), allocator_type())
{ m_flat_tree.insert_unique(first, last); }
template <class InputIterator>
flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a)
{ m_flat_tree.insert_unique(first, last); }
flat_map(const flat_map<Key,T,Pred,Alloc>& x)
: m_flat_tree(x.m_flat_tree) {}
flat_map<Key,T,Pred,Alloc>& operator=(const flat_map<Key, T, Pred, Alloc>& x)
{ m_flat_tree = x.m_flat_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_flat_tree.key_comp(); }
value_compare value_comp() const
{ return value_compare(m_flat_tree.key_comp()); }
allocator_type get_allocator() const
{ return m_flat_tree.get_allocator(); }
iterator begin()
{ return m_flat_tree.begin(); }
const_iterator begin() const
{ return m_flat_tree.begin(); }
iterator end()
{ return m_flat_tree.end(); }
const_iterator end() const
{ return m_flat_tree.end(); }
reverse_iterator rbegin()
{ return m_flat_tree.rbegin(); }
const_reverse_iterator rbegin() const
{ return m_flat_tree.rbegin(); }
reverse_iterator rend()
{ return m_flat_tree.rend(); }
const_reverse_iterator rend() const
{ return m_flat_tree.rend(); }
bool empty() const
{ return m_flat_tree.empty(); }
size_type size() const
{ return m_flat_tree.size(); }
size_type max_size() const
{ return m_flat_tree.max_size(); }
T &operator[](const key_type& k)
{
iterator i = lower_bound(k);
// i->first is greater than or equivalent to k.
if (i == end() || key_comp()(k, (*i).first))
i = insert(i, value_type(k, T()));
return (*i).second;
}
void swap(flat_map<Key,T,Pred,Alloc>& x)
{ m_flat_tree.swap(x.m_flat_tree); }
// insert/erase
std::pair<iterator,bool> insert(const value_type& x)
{ return m_flat_tree.insert_unique(x); }
iterator insert(iterator position, const value_type& x)
{ return m_flat_tree.insert_unique(position, x); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_flat_tree.insert_unique(first, last); }
void erase(const_iterator position)
{ m_flat_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_flat_tree.erase(x); }
void erase(const_iterator first, const_iterator last)
{ m_flat_tree.erase(first, last); }
void clear()
{ m_flat_tree.clear(); }
// flat_map operations:
iterator find(const key_type& x)
{ return m_flat_tree.find(x); }
const_iterator find(const key_type& x) const
{ return m_flat_tree.find(x); }
size_type count(const key_type& x) const
{ return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; }
iterator lower_bound(const key_type& x)
{ return m_flat_tree.lower_bound(x); }
const_iterator lower_bound(const key_type& x) const
{ return m_flat_tree.lower_bound(x); }
iterator upper_bound(const key_type& x)
{ return m_flat_tree.upper_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_flat_tree.upper_bound(x); }
std::pair<iterator,iterator> equal_range(const key_type& x)
{ return m_flat_tree.equal_range(x); }
std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
{ return m_flat_tree.equal_range(x); }
size_type capacity() const
{ return m_flat_tree.capacity(); }
void reserve(size_type count)
{ m_flat_tree.reserve(count); }
template <class K1, class T1, class C1, class A1>
friend bool operator== (const flat_map<K1, T1, C1, A1>&,
const flat_map<K1, T1, C1, A1>&);
template <class K1, class T1, class C1, class A1>
friend bool operator< (const flat_map<K1, T1, C1, A1>&,
const flat_map<K1, T1, C1, A1>&);
};
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y)
{ return x.m_flat_tree == y.m_flat_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y)
{ return x.m_flat_tree < y.m_flat_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator!=(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y)
{ return !(x == y); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y)
{ return y < x; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<=(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y)
{ return !(y < x); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>=(const flat_map<Key,T,Pred,Alloc>& x,
const flat_map<Key,T,Pred,Alloc>& y)
{ return !(x < y); }
template <class Key, class T, class Pred, class Alloc>
inline void swap(flat_map<Key,T,Pred,Alloc>& x,
flat_map<Key,T,Pred,Alloc>& y)
{ x.swap(y); }
// Forward declaration of operators < and ==, needed for friend declaration.
template <class Key, class T,
class Pred,
class Alloc>
class flat_multimap;
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
class flat_multimap
{
private:
typedef detail::flat_tree<Key,
std::pair<Key, T>,
detail::select1st< std::pair<Key, T> >,
Pred,
Alloc> tree_t;
tree_t m_flat_tree; // flat tree representing flat_map
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef typename tree_t::value_compare value_compare;
typedef T mapped_type;
typedef typename tree_t::key_compare key_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
// allocation/deallocation
explicit flat_multimap(const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a) { }
template <class InputIterator>
flat_multimap(InputIterator first, InputIterator last,
const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a)
{ m_flat_tree.insert_equal(first, last); }
flat_multimap(const flat_multimap<Key,T,Pred,Alloc>& x)
: m_flat_tree(x.m_flat_tree) { }
flat_multimap<Key,T,Pred,Alloc>&
operator=(const flat_multimap<Key,T,Pred,Alloc>& x)
{ m_flat_tree = x.m_flat_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_flat_tree.key_comp(); }
value_compare value_comp() const
{ return value_compare(m_flat_tree.key_comp()); }
allocator_type get_allocator() const
{ return m_flat_tree.get_allocator(); }
iterator begin()
{ return m_flat_tree.begin(); }
const_iterator begin() const
{ return m_flat_tree.begin(); }
iterator end()
{ return m_flat_tree.end(); }
const_iterator end() const
{ return m_flat_tree.end(); }
reverse_iterator rbegin()
{ return m_flat_tree.rbegin(); }
const_reverse_iterator rbegin() const
{ return m_flat_tree.rbegin(); }
reverse_iterator rend()
{ return m_flat_tree.rend(); }
const_reverse_iterator rend() const
{ return m_flat_tree.rend(); }
bool empty() const
{ return m_flat_tree.empty(); }
size_type size() const
{ return m_flat_tree.size(); }
size_type max_size() const
{ return m_flat_tree.max_size(); }
void swap(flat_multimap<Key,T,Pred,Alloc>& x)
{ m_flat_tree.swap(x.m_flat_tree); }
// insert/erase
iterator insert(const value_type& x)
{ return m_flat_tree.insert_equal(x); }
iterator insert(iterator position, const value_type& x)
{ return m_flat_tree.insert_equal(position, x); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_flat_tree.insert_equal(first, last); }
void erase(const_iterator position)
{ m_flat_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_flat_tree.erase(x); }
void erase(const_iterator first, const_iterator last)
{ m_flat_tree.erase(first, last); }
void clear()
{ m_flat_tree.clear(); }
// flat_multimap operations:
iterator find(const key_type& x)
{ return m_flat_tree.find(x); }
const_iterator find(const key_type& x) const
{ return m_flat_tree.find(x); }
size_type count(const key_type& x) const
{ return m_flat_tree.count(x); }
iterator lower_bound(const key_type& x)
{return m_flat_tree.lower_bound(x); }
const_iterator lower_bound(const key_type& x) const
{ return m_flat_tree.lower_bound(x); }
iterator upper_bound(const key_type& x)
{return m_flat_tree.upper_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_flat_tree.upper_bound(x); }
std::pair<iterator,iterator> equal_range(const key_type& x)
{ return m_flat_tree.equal_range(x); }
std::pair<const_iterator,const_iterator>
equal_range(const key_type& x) const
{ return m_flat_tree.equal_range(x); }
size_type capacity() const
{ return m_flat_tree.capacity(); }
void reserve(size_type count)
{ m_flat_tree.reserve(count); }
template <class K1, class T1, class C1, class A1>
friend bool operator== (const flat_multimap<K1, T1, C1, A1>& x,
const flat_multimap<K1, T1, C1, A1>& y);
template <class K1, class T1, class C1, class A1>
friend bool operator< (const flat_multimap<K1, T1, C1, A1>& x,
const flat_multimap<K1, T1, C1, A1>& y);
};
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y)
{ return x.m_flat_tree == y.m_flat_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y)
{ return x.m_flat_tree < y.m_flat_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator!=(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y)
{ return !(x == y); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y)
{ return y < x; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<=(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y)
{ return !(y < x); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>=(const flat_multimap<Key,T,Pred,Alloc>& x,
const flat_multimap<Key,T,Pred,Alloc>& y)
{ return !(x < y); }
template <class Key, class T, class Pred, class Alloc>
inline void swap(flat_multimap<Key,T,Pred,Alloc>& x,
flat_multimap<Key,T,Pred,Alloc>& y)
{ x.swap(y); }
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_FLAT_MAP_HPP */

View File

@@ -0,0 +1,483 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztañaga 2004.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SHMEM_FLAT_SET_HPP
#define BOOST_INTERPROCESS_SHMEM_FLAT_SET_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 <utility>
#include <functional>
#include <memory>
#include <boost/interprocess/containers/detail/flat_tree.hpp>
namespace boost { namespace interprocess {
// Forward declarations of operators < and ==, needed for friend declaration.
template <class T, class Pred, class Alloc>
class flat_set;
template <class T, class Pred, class Alloc>
inline bool operator==(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
inline bool operator<(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
class flat_set
{
private:
typedef detail::flat_tree<T, T,
detail::identity<T>, Pred, Alloc> tree_t;
tree_t m_flat_tree; // flat tree representing flat_set
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef typename tree_t::key_compare key_compare;
typedef typename tree_t::value_compare value_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
// allocation/deallocation
explicit flat_set(const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a) {}
template <class InputIterator>
flat_set(InputIterator first, InputIterator last,
const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a)
{ m_flat_tree.insert_unique(first, last); }
flat_set(const flat_set<T,Pred,Alloc>& x)
: m_flat_tree(x.m_flat_tree) {}
flat_set<T,Pred,Alloc>& operator=(const flat_set<T, Pred, Alloc>& x)
{ m_flat_tree = x.m_flat_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_flat_tree.key_comp(); }
value_compare value_comp() const
{ return m_flat_tree.key_comp(); }
allocator_type get_allocator() const
{ return m_flat_tree.get_allocator(); }
const_iterator begin() const
{ return m_flat_tree.begin(); }
const_iterator end() const
{ return m_flat_tree.end(); }
const_reverse_iterator rbegin() const
{ return m_flat_tree.rbegin(); }
const_reverse_iterator rend() const
{ return m_flat_tree.rend(); }
iterator begin()
{ return m_flat_tree.begin(); }
iterator end()
{ return m_flat_tree.end(); }
reverse_iterator rbegin()
{ return m_flat_tree.rbegin(); }
reverse_iterator rend()
{ return m_flat_tree.rend(); }
bool empty() const
{ return m_flat_tree.empty(); }
size_type size() const
{ return m_flat_tree.size(); }
size_type max_size() const
{ return m_flat_tree.max_size(); }
void swap(flat_set<T,Pred,Alloc>& x)
{ m_flat_tree.swap(x.m_flat_tree); }
// insert/erase
std::pair<iterator,bool> insert(const value_type& x)
{ return m_flat_tree.insert_unique(x); }
iterator insert(iterator position, const value_type& x)
{ return m_flat_tree.insert_unique(position, x); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_flat_tree.insert_unique(first, last); }
iterator erase(const_iterator position)
{ return m_flat_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_flat_tree.erase(x); }
iterator erase(const_iterator first, const_iterator last)
{ return m_flat_tree.erase(first, last); }
void clear()
{ m_flat_tree.clear(); }
// flat_set operations:
const_iterator find(const key_type& x) const
{ return m_flat_tree.find(x); }
iterator find(const key_type& x)
{ return m_flat_tree.find(x); }
size_type count(const key_type& x) const
{ return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; }
const_iterator lower_bound(const key_type& x) const
{ return m_flat_tree.lower_bound(x); }
iterator lower_bound(const key_type& x)
{ return m_flat_tree.lower_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_flat_tree.upper_bound(x); }
iterator upper_bound(const key_type& x)
{ return m_flat_tree.upper_bound(x); }
std::pair<const_iterator, const_iterator>
equal_range(const key_type& x) const
{ return m_flat_tree.equal_range(x); }
std::pair<iterator,iterator>
equal_range(const key_type& x)
{ return m_flat_tree.equal_range(x); }
size_type capacity() const
{ return m_flat_tree.capacity(); }
void reserve(size_type count)
{ m_flat_tree.reserve(count); }
template <class K1, class C1, class A1>
friend bool operator== (const flat_set<K1,C1,A1>&, const flat_set<K1,C1,A1>&);
template <class K1, class C1, class A1>
friend bool operator< (const flat_set<K1,C1,A1>&, const flat_set<K1,C1,A1>&);
};
template <class T, class Pred, class Alloc>
inline bool operator==(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y)
{ return x.m_flat_tree == y.m_flat_tree; }
template <class T, class Pred, class Alloc>
inline bool operator<(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y)
{ return x.m_flat_tree < y.m_flat_tree; }
template <class T, class Pred, class Alloc>
inline bool operator!=(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y)
{ return !(x == y); }
template <class T, class Pred, class Alloc>
inline bool operator>(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y)
{ return y < x; }
template <class T, class Pred, class Alloc>
inline bool operator<=(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y)
{ return !(y < x); }
template <class T, class Pred, class Alloc>
inline bool operator>=(const flat_set<T,Pred,Alloc>& x,
const flat_set<T,Pred,Alloc>& y)
{ return !(x < y); }
template <class T, class Pred, class Alloc>
inline void swap(flat_set<T,Pred,Alloc>& x,
flat_set<T,Pred,Alloc>& y)
{ x.swap(y); }
// Forward declaration of operators < and ==, needed for friend declaration.
template <class T, class Pred, class Alloc>
class flat_multiset;
template <class T, class Pred, class Alloc>
inline bool operator==(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
inline bool operator<(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
class flat_multiset
{
private:
typedef detail::flat_tree<T, T,
detail::identity<T>, Pred, Alloc> tree_t;
tree_t m_flat_tree; // flat tree representing flat_multiset
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef typename tree_t::key_compare key_compare;
typedef typename tree_t::value_compare value_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
// allocation/deallocation
explicit flat_multiset(const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a) {}
template <class InputIterator>
flat_multiset(InputIterator first, InputIterator last,
const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_flat_tree(comp, a)
{ m_flat_tree.insert_equal(first, last); }
flat_multiset(const flat_multiset<T,Pred,Alloc>& x)
: m_flat_tree(x.m_flat_tree) {}
flat_multiset<T,Pred,Alloc>& operator=(const flat_multiset<T,Pred,Alloc>& x)
{ m_flat_tree = x.m_flat_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_flat_tree.key_comp(); }
value_compare value_comp() const
{ return m_flat_tree.key_comp(); }
allocator_type get_allocator() const
{ return m_flat_tree.get_allocator(); }
const_iterator begin() const
{ return m_flat_tree.begin(); }
const_iterator end() const
{ return m_flat_tree.end(); }
const_reverse_iterator rbegin() const
{ return m_flat_tree.rbegin(); }
const_reverse_iterator rend() const
{ return m_flat_tree.rend(); }
iterator begin()
{ return m_flat_tree.begin(); }
iterator end()
{ return m_flat_tree.end(); }
reverse_iterator rbegin()
{ return m_flat_tree.rbegin(); }
reverse_iterator rend()
{ return m_flat_tree.rend(); }
bool empty() const
{ return m_flat_tree.empty(); }
size_type size() const
{ return m_flat_tree.size(); }
size_type max_size() const
{ return m_flat_tree.max_size(); }
void swap(flat_multiset<T,Pred,Alloc>& x)
{ m_flat_tree.swap(x.m_flat_tree); }
// insert/erase
iterator insert(const value_type& x)
{ return m_flat_tree.insert_equal(x); }
iterator insert(iterator position, const value_type& x)
{ return m_flat_tree.insert_equal(position, x); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_flat_tree.insert_equal(first, last); }
iterator erase(const_iterator position)
{ return m_flat_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_flat_tree.erase(x); }
iterator erase(const_iterator first, const_iterator last)
{ return m_flat_tree.erase(first, last); }
void clear()
{ m_flat_tree.clear(); }
// flat_multiset operations:
const_iterator find(const key_type& x) const
{ return m_flat_tree.find(x); }
iterator find(const key_type& x)
{ return m_flat_tree.find(x); }
size_type count(const key_type& x) const
{ return m_flat_tree.count(x); }
const_iterator lower_bound(const key_type& x) const
{ return m_flat_tree.lower_bound(x); }
iterator lower_bound(const key_type& x)
{ return m_flat_tree.lower_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_flat_tree.upper_bound(x); }
iterator upper_bound(const key_type& x)
{ return m_flat_tree.upper_bound(x); }
std::pair<const_iterator, const_iterator>
equal_range(const key_type& x) const
{ return m_flat_tree.equal_range(x); }
std::pair<iterator,iterator>
equal_range(const key_type& x)
{ return m_flat_tree.equal_range(x); }
size_type capacity() const
{ return m_flat_tree.capacity(); }
void reserve(size_type count)
{ m_flat_tree.reserve(count); }
template <class K1, class C1, class A1>
friend bool operator== (const flat_multiset<K1,C1,A1>&,
const flat_multiset<K1,C1,A1>&);
template <class K1, class C1, class A1>
friend bool operator< (const flat_multiset<K1,C1,A1>&,
const flat_multiset<K1,C1,A1>&);
};
template <class T, class Pred, class Alloc>
inline bool operator==(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y)
{ return x.m_flat_tree == y.m_flat_tree; }
template <class T, class Pred, class Alloc>
inline bool operator<(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y)
{ return x.m_flat_tree < y.m_flat_tree; }
template <class T, class Pred, class Alloc>
inline bool operator!=(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y)
{ return !(x == y); }
template <class T, class Pred, class Alloc>
inline bool operator>(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y)
{ return y < x; }
template <class T, class Pred, class Alloc>
inline bool operator<=(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y)
{ return !(y < x); }
template <class T, class Pred, class Alloc>
inline bool operator>=(const flat_multiset<T,Pred,Alloc>& x,
const flat_multiset<T,Pred,Alloc>& y)
{ return !(x < y); }
template <class T, class Pred, class Alloc>
inline void swap(flat_multiset<T,Pred,Alloc>& x,
flat_multiset<T,Pred,Alloc>& y)
{ x.swap(y); }
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_SHMEM_FLAT_SET_HPP */
// Local Variables:
// mode:C++
// End:

View File

@@ -0,0 +1,947 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_list.h file. Modified by Ion Gaztañaga 2004
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_LIST_HPP_
#define BOOST_INTERPROCESS_LIST_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/containers/vector.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/mpl/if.hpp>
#include <utility>
#include <memory>
#include <functional>
#include <algorithm>
namespace boost {
namespace interprocess {
namespace detail {
template <class A>
struct interprocess_list_node;
template <class A>
struct interprocess_list_node_base
{
typedef typename boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::type NodeAlloc;
typedef typename NodeAlloc::pointer pointer;
pointer m_next;
pointer m_prev;
static void reverse(pointer &head)
{
pointer tmp = head;
do {
detail::do_swap(tmp->m_next, tmp->m_prev);
tmp = tmp->m_prev; // Old next node is now prev.
} while (tmp != head);
}
static std::size_t size(const pointer &head)
{
std::size_t count = 0;
for(pointer node = head; node->m_next != head; node = node->m_next){
++count;
}
return count;
}
};
template <class A>
struct interprocess_list_node
: public interprocess_list_node_base<A>
{
typedef typename boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::type NodeAlloc;
typedef typename NodeAlloc::pointer pointer;
typedef typename A::value_type value_t;
interprocess_list_node(const value_t &value)
: m_data(value){}
value_t m_data;
};
template<class T, class A, bool convertible_construct>
struct interprocess_list_alloc
: public boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::type,
public boost::detail::allocator::
rebind_to<A, typename boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::
type::pointer >::type,
public A
{
typedef interprocess_list_node<A> Node;
typedef typename boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::type NodeAlloc;
typedef typename boost::detail::allocator::
rebind_to<A, typename NodeAlloc::pointer>::type PtrAlloc;
typedef A ValAlloc;
typedef typename NodeAlloc::pointer NodePtr;
typedef detail::scoped_deallocator<NodeAlloc> Deallocator;
typedef detail::scoped_destructor<PtrAlloc> PtrDestructor;
enum {
node_has_trivial_destructor =
boost::has_trivial_destructor<NodePtr>::value |
boost::has_trivial_destructor<T>::value
};
interprocess_list_alloc(const ValAlloc &a)
: NodeAlloc(a), PtrAlloc(a), ValAlloc(a)
{ priv_init(); }
interprocess_list_alloc(const interprocess_list_alloc &other)
: NodeAlloc(other), PtrAlloc(other), ValAlloc(other)
{ priv_init(); }
~interprocess_list_alloc()
{ this->priv_destroy(); }
typename NodeAlloc::size_type max_size() const
{ return NodeAlloc::max_size(); }
void priv_init()
{
m_node = NodeAlloc::allocate(1);
if(!boost::has_trivial_constructor<NodePtr>::value){
scoped_ptr<Node, Deallocator>node_deallocator(m_node, *this);
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
typedef typename PtrAlloc::pointer NodePtrPtr;
NodePtrPtr pnext(PtrAlloc::address(m_node->m_next)),
pprev(PtrAlloc::address(m_node->m_prev));
PtrAlloc::construct(pnext, m_node);
scoped_ptr<NodePtr, PtrDestructor> next_destroy(pnext, *this);
PtrAlloc::construct(pprev, m_node);
next_destroy.release();
}
node_deallocator.release();
}
else{
m_node->m_next = m_node;
m_node->m_prev = m_node;
}
}
void priv_destroy()
{
if(!boost::has_trivial_constructor<NodePtr>::value){
PtrAlloc::destroy(&m_node->m_next);
PtrAlloc::destroy(&m_node->m_prev);
}
NodeAlloc::deallocate(m_node, 1);
}
template <class Convertible>
NodePtr create_node(NodePtr next, NodePtr prev, const Convertible& x)
{
NodePtr p = NodeAlloc::allocate(1);
scoped_ptr<Node, Deallocator>node_deallocator(m_node, *this);
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
if(!boost::has_trivial_constructor<NodePtr>::value){
typedef typename PtrAlloc::pointer NodePtrPtr;
NodePtrPtr pnext(PtrAlloc::address(p->m_next)),
pprev(PtrAlloc::address(p->m_prev));
PtrAlloc::construct(pnext, next);
scoped_ptr<NodePtr, PtrDestructor> next_destroy(pnext, *this);
PtrAlloc::construct(pprev, prev);
scoped_ptr<NodePtr, PtrDestructor> prev_destroy(pprev, *this);
ValAlloc::construct(ValAlloc::address(p->m_data), x);
next_destroy.release();
prev_destroy.release();
}
else{
p->m_next = next;
p->m_prev = prev;
ValAlloc::construct(ValAlloc::address(p->m_data), x);
}
}
node_deallocator.release();
return (p);
}
void destroy_node(NodePtr node)
{
if(!node_has_trivial_destructor){
NodeAlloc::destroy(node);
}
NodeAlloc::deallocate(node, 1);
}
void swap(interprocess_list_alloc &x)
{
if (static_cast<NodeAlloc&>(*this) !=
static_cast<NodeAlloc&>(x)){
detail::do_swap(static_cast<NodeAlloc&>(*this),
static_cast<NodeAlloc&>(x));
detail::do_swap(static_cast<PtrAlloc&>(*this),
static_cast<PtrAlloc&>(x));
detail::do_swap(static_cast<ValAlloc&>(*this),
static_cast<ValAlloc&>(x));
}
detail::do_swap(this->m_node, x.m_node);
}
protected:
typename NodeAlloc::pointer m_node;
};
template<class T, class A>
struct interprocess_list_alloc<T, A, true>
: public boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::type
{
typedef interprocess_list_node<A> Node;
typedef typename boost::detail::allocator::
rebind_to<A, interprocess_list_node<A> >::type NodeAlloc;
typedef typename boost::detail::allocator::
rebind_to<A, typename NodeAlloc::pointer>::type PtrAlloc;
typedef A ValAlloc;
typedef typename NodeAlloc::pointer NodePtr;
typedef detail::scoped_deallocator<NodeAlloc> Deallocator;
typedef detail::scoped_destructor<PtrAlloc> PtrDestructor;
enum {
node_has_trivial_destructor =
boost::has_trivial_destructor<NodePtr>::value |
boost::has_trivial_destructor<T>::value
};
interprocess_list_alloc(const ValAlloc &a)
: NodeAlloc(a)
{ this->priv_init(); }
interprocess_list_alloc(const interprocess_list_alloc &other)
: NodeAlloc(other)
{ this->priv_init(); }
~interprocess_list_alloc()
{ this->priv_destroy(); }
typename NodeAlloc::size_type max_size() const
{ return NodeAlloc::max_size(); }
template<class Convertible>
NodePtr create_node(NodePtr next, NodePtr prev, const Convertible& x)
{
NodePtr p = NodeAlloc::allocate(1);
scoped_ptr<Node, Deallocator>node_deallocator(p, *this);
NodeAlloc::construct(p, x);
node_deallocator.release();
p->m_next = next;
p->m_prev = prev;
return (p);
}
void destroy_node(NodePtr node)
{
if(!node_has_trivial_destructor){
NodeAlloc::destroy(node);
}
NodeAlloc::deallocate(node, 1);
}
void swap(interprocess_list_alloc &x)
{
NodeAlloc& this_alloc = static_cast<NodeAlloc&>(*this);
NodeAlloc& other_alloc = static_cast<NodeAlloc&>(x);
if (this_alloc != other_alloc){
detail::do_swap(this_alloc, other_alloc);
}
detail::do_swap(this->m_node, x.m_node);
}
protected:
typename NodeAlloc::pointer m_node;
private:
void priv_init()
{
m_node = NodeAlloc::allocate(1);
if(!boost::has_trivial_constructor<NodePtr>::value){
typedef typename PtrAlloc::pointer NodePtrPtr;
scoped_ptr<Node, Deallocator>node_deallocator(m_node, *this);
PtrAlloc ptr_alloc(*this);
NodePtrPtr pnext(ptr_alloc.address(m_node->m_next)),
pprev(ptr_alloc.address(m_node->m_prev));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
ptr_alloc.construct(pnext, m_node);
scoped_ptr<NodePtr, PtrDestructor> next_destroy(pnext, ptr_alloc);
ptr_alloc.construct(pprev, m_node);
next_destroy.release();
}
node_deallocator.release();
}
else{
m_node->m_next = m_node;
m_node->m_prev = m_node;
}
}
void priv_destroy()
{
if(!boost::has_trivial_destructor<NodePtr>::value){
PtrAlloc ptr_alloc(*this);
ptr_alloc.destroy(ptr_alloc.address(m_node->m_next));
ptr_alloc.destroy(ptr_alloc.address(m_node->m_prev));
}
NodeAlloc::deallocate(m_node, 1);
}
};
} //namespace detail {
template <class T, class A>
class list
: protected detail::interprocess_list_alloc<T, A,
has_convertible_construct<A>::value>
{
typedef detail::interprocess_list_alloc<T, A,
has_convertible_construct< A>::value> AllocHolder;
typedef typename AllocHolder::NodePtr NodePtr;
typedef list <T, A> ThisType;
typedef typename AllocHolder::NodeAlloc NodeAlloc;
typedef typename AllocHolder::PtrAlloc PtrAlloc;
typedef typename AllocHolder::ValAlloc ValAlloc;
typedef detail::interprocess_list_node<A> Node;
public:
typedef A allocator_type;
typedef T value_type;
typedef typename A::pointer pointer;
typedef typename A::const_pointer const_pointer;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
typedef typename A::size_type size_type;
typedef typename A::difference_type difference_type;
typedef difference_type list_difference_type;
typedef pointer list_pointer;
typedef const_pointer list_const_pointer;
typedef reference list_reference;
typedef const_reference list_const_reference;
public:
//list const_iterator
class const_iterator
: public boost::iterator<std::bidirectional_iterator_tag,
value_type, list_difference_type,
list_const_pointer, list_const_reference>
{
private:
const NodePtr &get_ptr() const { return m_ptr; }
NodePtr &get_ptr() { return m_ptr; }
protected:
NodePtr m_ptr;
explicit const_iterator(NodePtr ptr) : m_ptr(ptr){}
void prot_incr() { m_ptr = m_ptr->m_next; }
void prot_decr() { m_ptr = m_ptr->m_prev; }
public:
friend class list<T, A>;
typedef list_difference_type difference_type;
//Constructors
const_iterator() : m_ptr(0){}
//Pointer like operators
const_reference operator*() const
{ return m_ptr->m_data; }
const_pointer operator->() const
{ return const_pointer(&m_ptr->m_data); }
//Increment / Decrement
const_iterator& operator++()
{ prot_incr(); return *this; }
const_iterator operator++(int)
{ NodePtr tmp = m_ptr; ++*this; return const_iterator(tmp); }
const_iterator& operator--()
{ prot_decr(); return *this; }
const_iterator operator--(int)
{ NodePtr tmp = m_ptr; --*this; return const_iterator(tmp); }
//Comparison operators
bool operator== (const const_iterator& r) const
{ return m_ptr == r.m_ptr; }
bool operator!= (const const_iterator& r) const
{ return m_ptr != r.m_ptr; }
bool operator< (const const_iterator& r) const
{ return m_ptr < r.m_ptr; }
bool operator<= (const const_iterator& r) const
{ return m_ptr <= r.m_ptr; }
bool operator> (const const_iterator& r) const
{ return m_ptr > r.m_ptr; }
bool operator>= (const const_iterator& r) const
{ return m_ptr >= r.m_ptr; }
};
//list iterator
class iterator : public const_iterator
{
protected:
explicit iterator(NodePtr ptr) : const_iterator(ptr){}
public:
friend class list<T, A>;
typedef list_pointer pointer;
typedef list_reference reference;
//Constructors
iterator(){}
//Pointer like operators
reference operator*() const { return this->m_ptr->m_data; }
pointer operator->() const { return pointer(&this->m_ptr->m_data); }
//Increment / Decrement
iterator& operator++()
{ this->prot_incr(); return *this; }
iterator operator++(int)
{ NodePtr tmp = this->m_ptr; ++*this; return iterator(tmp); }
iterator& operator--()
{ this->prot_decr(); return *this; }
iterator operator--(int)
{ iterator tmp = *this; --*this; return tmp; }
};
typedef boost::reverse_iterator<iterator> reverse_iterator;
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
explicit list(const allocator_type &a = A())
: AllocHolder(a)
{}
list(size_type n, const T& value = T(), const A& a = A())
: AllocHolder(a)
{ insert(begin(), n, value); }
list(const list& x)
: AllocHolder(x)
{ insert(begin(), x.begin(), x.end()); }
template <class InpIt>
list(InpIt first, InpIt last, const A &a = A())
: AllocHolder(a)
{ insert(begin(), first, last); }
~list()
{ clear(); }
allocator_type get_allocator() const { return allocator_type(*this); }
void clear()
{
NodePtr cur = this->m_node->m_next;
while (cur != this->m_node) {
NodePtr tmp = cur;
cur = cur->m_next;
AllocHolder::destroy_node(tmp);
}
this->m_node->m_next = this->m_node;
this->m_node->m_prev = this->m_node;
}
iterator begin()
{ return iterator(this->m_node->m_next); }
const_iterator begin() const
{ return const_iterator(this->m_node->m_next); }
iterator end()
{ return iterator(this->m_node); }
const_iterator end() const
{ return const_iterator(this->m_node); }
reverse_iterator rbegin()
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(end()); }
reverse_iterator rend()
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(begin()); }
bool empty() const
{ return this->m_node->m_next == this->m_node; }
size_type size() const
{ return Node::size(this->m_node); }
size_type max_size() const
{ return AllocHolder::max_size(); }
void push_front(const T& x)
{ insert(begin(), x); }
void push_back (const T& x)
{ insert(end(), x); }
void pop_front()
{ erase(begin()); }
void pop_back()
{ iterator tmp = end(); erase(--tmp); }
reference front()
{ return *begin(); }
const_reference front() const
{ return *begin(); }
reference back()
{ return *(--end()); }
const_reference back() const
{ return *(--end()); }
void resize(size_type new_size, const T& x = T())
{
iterator i = begin();
size_type len = 0;
for ( ; i != end() && len < new_size; ++i, ++len){}
if (len == new_size)
erase(i, end());
else // i == end()
insert(end(), new_size - len, x);
}
void swap(ThisType& x)
{ AllocHolder::swap(x); }
ThisType& operator=(const ThisType& x)
{
if (this != &x) {
this->assign(x.begin(), x.end());
}
return *this;
}
void insert(iterator pos, size_type n, const T& x)
{ this->priv_fill_insert(pos, n, x); }
template <class InpIt>
void insert(iterator pos, InpIt first, InpIt last)
{
const bool aux_boolean = boost::is_integral<InpIt>::value;
typedef boost::mpl::bool_<aux_boolean> Result;
this->priv_insert_dispatch(pos, first, last, Result());
}
iterator insert(iterator position, const T& x)
{
NodePtr tmp = AllocHolder::create_node(position.get_ptr(),
position.get_ptr()->m_prev,
x);
position.get_ptr()->m_prev->m_next = tmp;
position.get_ptr()->m_prev = tmp;
return iterator(tmp);
}
iterator erase(const_iterator position)
{
NodePtr next_node = position.get_ptr()->m_next;
NodePtr prev_node = position.get_ptr()->m_prev;
NodePtr node = position.get_ptr();
prev_node->m_next = next_node;
next_node->m_prev = prev_node;
AllocHolder::destroy_node(node);
return iterator(next_node);
}
iterator erase(const_iterator first, const_iterator last)
{
while (first != last)
this->erase(first++);
return iterator(last.get_ptr());
}
// assign(), a generalized assignment member function. Two
// versions: one that takes a count, and one that takes a range.
// The range version is a member template, so we dispatch on whether
// or not the type is an integer.
void assign(size_type n, const T& val)
{ this->priv_fill_assign(n, val); }
template <class InpIt>
void assign(InpIt first, InpIt last)
{
const bool aux_boolean = boost::is_integral<InpIt>::value;
typedef boost::mpl::bool_<aux_boolean> Result;
this->priv_assign_dispatch(first, last, Result());
}
void splice(iterator position, ThisType& x)
{
if((NodeAlloc&)*this == (NodeAlloc&)x){
if (!x.empty())
this->priv_transfer(position.get_ptr(), x.m_node->m_next, x.m_node);
}
else{
this->insert(position, x.begin(), x.end());
x.clear();
}
}
void splice(iterator position, ThisType &x, iterator i)
{
if((NodeAlloc&)*this == (NodeAlloc&)x){
iterator j = i;
++j;
if (position == i || position == j) return;
this->priv_transfer(position.get_ptr(), i.get_ptr(), j.get_ptr());
}
else{
this->insert(position, *i);
x.erase(i);
}
}
void splice(iterator position, ThisType &x, iterator first, iterator last)
{
if((NodeAlloc&)*this == (NodeAlloc&)x){
if (first != last)
this->priv_transfer(position.get_ptr(), first.get_ptr(), last.get_ptr());
}
else{
this->insert(position, x.begin(), x.end());
x.erase(first, last);
}
}
void remove(const T& value)
{
iterator first = begin();
iterator last = end();
while (first != last) {
iterator next = first;
++next;
if (*first == value)
this->erase(first);
first = next;
}
}
void reverse()
{ Node::reverse(this->m_node); }
template <class Pred>
void remove_if(Pred pred)
{
iterator first = begin();
iterator last = end();
while (first != last) {
iterator next = first;
++next;
if (pred(*first))
this->erase(first);
first = next;
}
}
void unique()
{ this->unique(value_equal()); }
template <class BinaryPredicate>
void unique(BinaryPredicate binary_pred)
{
iterator first = begin();
iterator last = end();
if (first == last) return;
iterator next = first;
while (++next != last) {
if (binary_pred(*first, *next))
erase(next);
else
first = next;
next = first;
}
}
void merge(list<T, A>& x)
{ this->merge(x, value_less()); }
template <class StrictWeakOrdering>
void merge(list<T, A>& x, StrictWeakOrdering comp)
{
iterator first1 = begin();
iterator last1 = end();
iterator first2 = x.begin();
iterator last2 = x.end();
while (first1 != last1 && first2 != last2){
if (comp(*first2, *first1)) {
iterator next = first2;
this->splice(first1, x, first2, ++next);
first2 = next;
}
else{
++first1;
}
}
if (first2 != last2)
this->splice(last1, x, first2, last2);
}
void sort()
{ this->sort(value_less()); }
template <class StrictWeakOrdering>
void sort(StrictWeakOrdering comp)
{
// Do nothing if the list has length 0 or 1.
if (this->m_node->m_next != this->m_node &&
this->m_node->m_next->m_next != this->m_node) {
ThisType carry(this->get_allocator());
vector<ThisType> counter;
counter.resize(64, carry);
int fill = 0;
while (!this->empty()) {
carry.splice(carry.begin(), *this, begin());
int i = 0;
while(i < fill && !counter[i].empty()) {
counter[i].merge(carry, comp);
carry.swap(counter[i++]);
}
carry.swap(counter[i]);
if (i == fill) ++fill;
}
for (int i = 1; i < fill; ++i)
counter[i].merge(counter[i-1], comp);
this->swap(counter[fill-1]);
}
}
private:
void priv_fill_insert(iterator position, size_type n, const T& x)
{
for ( ; n > 0; --n)
this->insert(position, x);
}
template <class InputIter>
void priv_insert_dispatch(iterator position,
InputIter first, InputIter last,
boost::mpl::false_)
{
for ( ; first != last; ++first){
this->insert(position, *first);
}
}
template<class Integer>
void priv_insert_dispatch(iterator pos, Integer n, Integer x, boost::mpl::true_)
{
this->priv_fill_insert(pos, n, x);
}
void priv_fill_assign(size_type n, const T& val)
{
iterator i = begin();
for ( ; i != end() && n > 0; ++i, --n)
*i = val;
if (n > 0)
this->insert(end(), n, val);
else
this->erase(i, end());
}
template <class Integer>
void priv_assign_dispatch(Integer n, Integer val, boost::mpl::true_)
{ this->priv_fill_assign((size_type) n, (T) val); }
void priv_transfer(NodePtr position, NodePtr first, NodePtr last)
{
if (position != last) {
// Remove [first, last) from its old position.
last->m_prev->m_next = position;
first->m_prev->m_next = last;
position->m_prev->m_next = first;
// Splice [first, last) into its new position.
NodePtr tmp = position->m_prev;
position->m_prev = last->m_prev;
last->m_prev = first->m_prev;
first->m_prev = tmp;
}
}
template <class InputIter>
void priv_assign_dispatch(InputIter first2, InputIter last2,
boost::mpl::false_)
{
iterator first1 = begin();
iterator last1 = end();
for ( ; first1 != last1 && first2 != last2; ++first1, ++first2)
*first1 = *first2;
if (first2 == last2)
this->erase(first1, last1);
else
this->insert(last1, first2, last2);
}
//Functors for member algorithm defaults
struct value_less
{
bool operator()(const value_type &a, const value_type &b) const
{ return a < b; }
};
struct value_equal
{
bool operator()(const value_type &a, const value_type &b) const
{ return a == b; }
};
};
template <class T, class A>
inline bool operator==(const list<T,A>& x, const list<T,A>& y)
{
typedef typename list<T,A>::const_iterator const_iterator;
const_iterator end1 = x.end();
const_iterator end2 = y.end();
const_iterator i1 = x.begin();
const_iterator i2 = y.begin();
while (i1 != end1 && i2 != end2 && *i1 == *i2) {
++i1;
++i2;
}
return i1 == end1 && i2 == end2;
}
template <class T, class A>
inline bool operator<(const list<T,A>& x,
const list<T,A>& y)
{
return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}
template <class T, class A>
inline bool operator!=(const list<T,A>& x, const list<T,A>& y)
{
return !(x == y);
}
template <class T, class A>
inline bool operator>(const list<T,A>& x, const list<T,A>& y)
{
return y < x;
}
template <class T, class A>
inline bool operator<=(const list<T,A>& x, const list<T,A>& y)
{
return !(y < x);
}
template <class T, class A>
inline bool operator>=(const list<T,A>& x, const list<T,A>& y)
{
return !(x < y);
}
template <class T, class A>
inline void swap(list<T, A>& x, list<T, A>& y)
{
x.swap(y);
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_LIST_HPP_

View File

@@ -0,0 +1,533 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gaztañaga 2004.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SHMEM_MAP_HPP
#define BOOST_INTERPROCESS_SHMEM_MAP_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 <utility>
#include <functional>
#include <memory>
#include <boost/interprocess/containers/tree.hpp>
namespace boost { namespace interprocess {
// Forward declarations of operators == and <, needed for friend declarations.
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
class map
{
private:
typedef detail::rb_tree<Key,
std::pair<const Key, T>,
detail::select1st< std::pair<const Key, T> >,
Pred,
Alloc> tree_t;
tree_t m_tree; // red-black tree representing map
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef T mapped_type;
typedef Pred key_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
class value_compare
: public Pred,
public std::binary_function<value_type, value_type, bool>
{
friend class map<Key,T,Pred,Alloc>;
protected :
value_compare(const Pred &c) : Pred(c) {}
public:
bool operator()(const value_type& x, const value_type& y) const {
return Pred::operator()(x.first, y.first);
}
};
// allocation/deallocation
map() : m_tree(Pred(), allocator_type()) {}
explicit map(const Pred& comp,
const allocator_type& a = allocator_type())
: m_tree(comp, a) {}
template <class InputIterator>
map(InputIterator first, InputIterator last)
: m_tree(Pred(), allocator_type())
{ m_tree.insert_unique(first, last); }
template <class InputIterator>
map(InputIterator first, InputIterator last, const Pred& comp,
const allocator_type& a = allocator_type())
: m_tree(comp, a)
{ m_tree.insert_unique(first, last); }
map(const map<Key,T,Pred,Alloc>& x)
: m_tree(x.m_tree) {}
map<Key,T,Pred,Alloc>& operator=(const map<Key, T, Pred, Alloc>& x)
{ m_tree = x.m_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_tree.key_comp(); }
value_compare value_comp() const
{ return value_compare(m_tree.key_comp()); }
allocator_type get_allocator() const
{ return m_tree.get_allocator(); }
iterator begin()
{ return m_tree.begin(); }
const_iterator begin() const
{ return m_tree.begin(); }
iterator end()
{ return m_tree.end(); }
const_iterator end() const
{ return m_tree.end(); }
reverse_iterator rbegin()
{ return m_tree.rbegin(); }
const_reverse_iterator rbegin() const
{ return m_tree.rbegin(); }
reverse_iterator rend()
{ return m_tree.rend(); }
const_reverse_iterator rend() const
{ return m_tree.rend(); }
bool empty() const
{ return m_tree.empty(); }
size_type size() const
{ return m_tree.size(); }
size_type max_size() const
{ return m_tree.max_size(); }
T& operator[](const key_type& k)
{
iterator i = lower_bound(k);
// i->first is greater than or equivalent to k.
if (i == end() || key_comp()(k, (*i).first))
i = insert(i, value_type(k, T()));
return (*i).second;
}
void swap(map<Key,T,Pred,Alloc>& x)
{ m_tree.swap(x.m_tree); }
// insert/erase
std::pair<iterator,bool> insert(const value_type& x)
{ return m_tree.insert_unique(x); }
std::pair<iterator,bool> insert_from(const key_type& k,
const mapped_type& m)
{ return m_tree.insert_unique(value_type(k, m)); }
iterator insert(iterator position, const value_type& x)
{ return m_tree.insert_unique(position, x); }
iterator insert_from(iterator position,
const key_type& k,
const mapped_type& m)
{ return m_tree.insert_unique(position, value_type(k, m)); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_tree.insert_unique(first, last); }
iterator erase(const_iterator position)
{ return m_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_tree.erase(x); }
iterator erase(const_iterator first, const_iterator last)
{ return m_tree.erase(first, last); }
void clear()
{ m_tree.clear(); }
// map operations:
iterator find(const key_type& x)
{ return m_tree.find(x); }
const_iterator find(const key_type& x) const
{ return m_tree.find(x); }
size_type count(const key_type& x) const
{ return m_tree.find(x) == m_tree.end() ? 0 : 1; }
iterator lower_bound(const key_type& x)
{ return m_tree.lower_bound(x); }
const_iterator lower_bound(const key_type& x) const
{ return m_tree.lower_bound(x); }
iterator upper_bound(const key_type& x)
{ return m_tree.upper_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_tree.upper_bound(x); }
std::pair<iterator,iterator> equal_range(const key_type& x)
{ return m_tree.equal_range(x); }
std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
{ return m_tree.equal_range(x); }
template <class K1, class T1, class C1, class A1>
friend bool operator== (const map<K1, T1, C1, A1>&,
const map<K1, T1, C1, A1>&);
template <class K1, class T1, class C1, class A1>
friend bool operator< (const map<K1, T1, C1, A1>&,
const map<K1, T1, C1, A1>&);
};
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y)
{ return x.m_tree == y.m_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y)
{ return x.m_tree < y.m_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator!=(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y)
{ return !(x == y); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y)
{ return y < x; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<=(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y)
{ return !(y < x); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>=(const map<Key,T,Pred,Alloc>& x,
const map<Key,T,Pred,Alloc>& y)
{ return !(x < y); }
template <class Key, class T, class Pred, class Alloc>
inline void swap(map<Key,T,Pred,Alloc>& x,
map<Key,T,Pred,Alloc>& y)
{ x.swap(y); }
// Forward declaration of operators < and ==, needed for friend declaration.
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y);
template <class Key, class T, class Pred, class Alloc>
class multimap
{
private:
typedef detail::rb_tree<Key,
std::pair<const Key, T>,
detail::select1st< std::pair<const Key, T> >,
Pred,
Alloc> tree_t;
tree_t m_tree; // red-black tree representing map
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef T mapped_type;
typedef Pred key_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
class value_compare
: public Pred,
public std::binary_function<value_type, value_type, bool>
{
friend class multimap<Key,T,Pred,Alloc>;
protected :
value_compare(const Pred &c) : Pred(c) {}
public:
bool operator()(const value_type& x, const value_type& y) const {
return Pred::operator()(x.first, y.first);
}
};
// allocation/deallocation
explicit multimap(const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_tree(comp, a) { }
template <class InputIterator>
multimap(InputIterator first, InputIterator last)
: m_tree(Pred(), allocator_type())
{ m_tree.insert_equal(first, last); }
template <class InputIterator>
multimap(InputIterator first, InputIterator last,
const Pred& comp,
const allocator_type& a = allocator_type())
: m_tree(comp, a)
{ m_tree.insert_equal(first, last); }
multimap(const multimap<Key,T,Pred,Alloc>& x)
: m_tree(x.m_tree) { }
multimap<Key,T,Pred,Alloc>&
operator=(const multimap<Key,T,Pred,Alloc>& x)
{ m_tree = x.m_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_tree.key_comp(); }
value_compare value_comp() const
{ return value_compare(m_tree.key_comp()); }
allocator_type get_allocator() const
{ return m_tree.get_allocator(); }
iterator begin()
{ return m_tree.begin(); }
const_iterator begin() const
{ return m_tree.begin(); }
iterator end()
{ return m_tree.end(); }
const_iterator end() const
{ return m_tree.end(); }
reverse_iterator rbegin()
{ return m_tree.rbegin(); }
const_reverse_iterator rbegin() const
{ return m_tree.rbegin(); }
reverse_iterator rend()
{ return m_tree.rend(); }
const_reverse_iterator rend() const
{ return m_tree.rend(); }
bool empty() const
{ return m_tree.empty(); }
size_type size() const
{ return m_tree.size(); }
size_type max_size() const
{ return m_tree.max_size(); }
void swap(multimap<Key,T,Pred,Alloc>& x)
{ m_tree.swap(x.m_tree); }
// insert/erase
iterator insert(const value_type& x)
{ return m_tree.insert_equal(x); }
iterator insert_from(const key_type &k,
const mapped_type &m)
{ return m_tree.insert_equal(value_type(k, m)); }
iterator insert(iterator position, const value_type& x)
{ return m_tree.insert_equal(position, x); }
iterator insert_from(iterator position,
const key_type &k,
const mapped_type &m)
{ return m_tree.insert_equal(position, value_type(k, m)); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_tree.insert_equal(first, last); }
iterator erase(const_iterator position)
{ return m_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_tree.erase(x); }
iterator erase(const_iterator first, const_iterator last)
{ return m_tree.erase(first, last); }
void clear()
{ m_tree.clear(); }
// multimap operations:
iterator find(const key_type& x)
{ return m_tree.find(x); }
const_iterator find(const key_type& x) const
{ return m_tree.find(x); }
size_type count(const key_type& x) const
{ return m_tree.count(x); }
iterator lower_bound(const key_type& x)
{return m_tree.lower_bound(x); }
const_iterator lower_bound(const key_type& x) const
{ return m_tree.lower_bound(x); }
iterator upper_bound(const key_type& x)
{return m_tree.upper_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_tree.upper_bound(x); }
std::pair<iterator,iterator> equal_range(const key_type& x)
{ return m_tree.equal_range(x); }
std::pair<const_iterator,const_iterator>
equal_range(const key_type& x) const
{ return m_tree.equal_range(x); }
template <class K1, class T1, class C1, class A1>
friend bool operator== (const multimap<K1, T1, C1, A1>& x,
const multimap<K1, T1, C1, A1>& y);
template <class K1, class T1, class C1, class A1>
friend bool operator< (const multimap<K1, T1, C1, A1>& x,
const multimap<K1, T1, C1, A1>& y);
};
template <class Key, class T, class Pred, class Alloc>
inline bool operator==(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y)
{ return x.m_tree == y.m_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y)
{ return x.m_tree < y.m_tree; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator!=(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y)
{ return !(x == y); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y)
{ return y < x; }
template <class Key, class T, class Pred, class Alloc>
inline bool operator<=(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y)
{ return !(y < x); }
template <class Key, class T, class Pred, class Alloc>
inline bool operator>=(const multimap<Key,T,Pred,Alloc>& x,
const multimap<Key,T,Pred,Alloc>& y)
{ return !(x < y); }
template <class Key, class T, class Pred, class Alloc>
inline void swap(multimap<Key,T,Pred,Alloc>& x,
multimap<Key,T,Pred,Alloc>& y)
{ x.swap(y); }
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_SHMEM_MAP_HPP */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,474 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztañaga 2004.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SET_HPP
#define BOOST_INTERPROCESS_SET_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 <utility>
#include <functional>
#include <memory>
#include <boost/interprocess/containers/tree.hpp>
namespace boost { namespace interprocess {
// Forward declarations of operators < and ==, needed for friend declaration.
template <class T, class Pred, class Alloc>
inline bool operator==(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
inline bool operator<(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
class set
{
private:
typedef detail::rb_tree<T, T,
detail::identity<T>, Pred, Alloc> tree_t;
tree_t m_tree; // red-black tree representing set
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef Pred key_compare;
typedef Pred value_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
// allocation/deallocation
explicit set(const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_tree(comp, a) {}
template <class InputIterator>
set(InputIterator first, InputIterator last)
: m_tree(Pred(), allocator_type())
{ m_tree.insert_unique(first, last); }
template <class InputIterator>
set(InputIterator first, InputIterator last, const Pred& comp,
const allocator_type& a = allocator_type())
: m_tree(comp, a)
{ m_tree.insert_unique(first, last); }
set(const set<T,Pred,Alloc>& x)
: m_tree(x.m_tree) {}
set<T,Pred,Alloc>& operator=(const set<T, Pred, Alloc>& x)
{ m_tree = x.m_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_tree.key_comp(); }
value_compare value_comp() const
{ return m_tree.key_comp(); }
allocator_type get_allocator() const
{ return m_tree.get_allocator(); }
const_iterator begin() const
{ return m_tree.begin(); }
const_iterator end() const
{ return m_tree.end(); }
const_reverse_iterator rbegin() const
{ return m_tree.rbegin(); }
const_reverse_iterator rend() const
{ return m_tree.rend(); }
iterator begin()
{ return m_tree.begin(); }
iterator end()
{ return m_tree.end(); }
reverse_iterator rbegin()
{ return m_tree.rbegin(); }
reverse_iterator rend()
{ return m_tree.rend(); }
bool empty() const
{ return m_tree.empty(); }
size_type size() const
{ return m_tree.size(); }
size_type max_size() const
{ return m_tree.max_size(); }
void swap(set<T,Pred,Alloc>& x)
{ m_tree.swap(x.m_tree); }
// insert/erase
std::pair<iterator,bool> insert(const value_type& x)
{ return m_tree.insert_unique(x); }
iterator insert(iterator position, const value_type& x)
{ return m_tree.insert_unique(position, x); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_tree.insert_unique(first, last); }
iterator erase(const_iterator position)
{ return m_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_tree.erase(x); }
iterator erase(const_iterator first, const_iterator last)
{ return m_tree.erase(first, last); }
void clear()
{ m_tree.clear(); }
// set operations:
const_iterator find(const key_type& x) const
{ return m_tree.find(x); }
iterator find(const key_type& x)
{ return m_tree.find(x); }
size_type count(const key_type& x) const
{ return m_tree.find(x) == m_tree.end() ? 0 : 1; }
const_iterator lower_bound(const key_type& x) const
{ return m_tree.lower_bound(x); }
iterator lower_bound(const key_type& x)
{ return m_tree.lower_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_tree.upper_bound(x); }
iterator upper_bound(const key_type& x)
{ return m_tree.upper_bound(x); }
std::pair<const_iterator, const_iterator>
equal_range(const key_type& x) const
{ return m_tree.equal_range(x); }
std::pair<iterator,iterator>
equal_range(const key_type& x)
{ return m_tree.equal_range(x); }
template <class K1, class C1, class A1>
friend bool operator== (const set<K1,C1,A1>&, const set<K1,C1,A1>&);
template <class K1, class C1, class A1>
friend bool operator< (const set<K1,C1,A1>&, const set<K1,C1,A1>&);
};
template <class T, class Pred, class Alloc>
inline bool operator==(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y)
{ return x.m_tree == y.m_tree; }
template <class T, class Pred, class Alloc>
inline bool operator<(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y)
{ return x.m_tree < y.m_tree; }
template <class T, class Pred, class Alloc>
inline bool operator!=(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y)
{ return !(x == y); }
template <class T, class Pred, class Alloc>
inline bool operator>(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y)
{ return y < x; }
template <class T, class Pred, class Alloc>
inline bool operator<=(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y)
{ return !(y < x); }
template <class T, class Pred, class Alloc>
inline bool operator>=(const set<T,Pred,Alloc>& x,
const set<T,Pred,Alloc>& y)
{ return !(x < y); }
template <class T, class Pred, class Alloc>
inline void swap(set<T,Pred,Alloc>& x,
set<T,Pred,Alloc>& y)
{ x.swap(y); }
// Forward declaration of operators < and ==, needed for friend declaration.
template <class T, class Pred, class Alloc>
inline bool operator==(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
inline bool operator<(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y);
template <class T, class Pred, class Alloc>
class multiset
{
private:
typedef detail::rb_tree<T, T,
detail::identity<T>, Pred, Alloc> tree_t;
tree_t m_tree; // red-black tree representing multiset
public:
// typedefs:
typedef typename tree_t::key_type key_type;
typedef typename tree_t::value_type value_type;
typedef typename tree_t::pointer pointer;
typedef typename tree_t::const_pointer const_pointer;
typedef typename tree_t::reference reference;
typedef typename tree_t::const_reference const_reference;
typedef Pred key_compare;
typedef Pred value_compare;
typedef typename tree_t::iterator iterator;
typedef typename tree_t::const_iterator const_iterator;
typedef typename tree_t::reverse_iterator reverse_iterator;
typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
typedef typename tree_t::size_type size_type;
typedef typename tree_t::difference_type difference_type;
typedef typename tree_t::allocator_type allocator_type;
// allocation/deallocation
explicit multiset(const Pred& comp = Pred(),
const allocator_type& a = allocator_type())
: m_tree(comp, a) {}
template <class InputIterator>
multiset(InputIterator first, InputIterator last)
: m_tree(Pred(), allocator_type())
{ m_tree.insert_equal(first, last); }
template <class InputIterator>
multiset(InputIterator first, InputIterator last,
const Pred& comp,
const allocator_type& a = allocator_type())
: m_tree(comp, a)
{ m_tree.insert_equal(first, last); }
multiset(const multiset<T,Pred,Alloc>& x)
: m_tree(x.m_tree) {}
multiset<T,Pred,Alloc>& operator=(const multiset<T,Pred,Alloc>& x)
{ m_tree = x.m_tree; return *this; }
// accessors:
key_compare key_comp() const
{ return m_tree.key_comp(); }
value_compare value_comp() const
{ return m_tree.key_comp(); }
allocator_type get_allocator() const
{ return m_tree.get_allocator(); }
const_iterator begin() const
{ return m_tree.begin(); }
const_iterator end() const
{ return m_tree.end(); }
const_reverse_iterator rbegin() const
{ return m_tree.rbegin(); }
const_reverse_iterator rend() const
{ return m_tree.rend(); }
iterator begin()
{ return m_tree.begin(); }
iterator end()
{ return m_tree.end(); }
reverse_iterator rbegin()
{ return m_tree.rbegin(); }
reverse_iterator rend()
{ return m_tree.rend(); }
bool empty() const
{ return m_tree.empty(); }
size_type size() const
{ return m_tree.size(); }
size_type max_size() const
{ return m_tree.max_size(); }
void swap(multiset<T,Pred,Alloc>& x)
{ m_tree.swap(x.m_tree); }
// insert/erase
iterator insert(const value_type& x)
{ return m_tree.insert_equal(x); }
iterator insert(iterator position, const value_type& x)
{ return m_tree.insert_equal(position, x); }
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{ m_tree.insert_equal(first, last); }
iterator erase(const_iterator position)
{ return m_tree.erase(position); }
size_type erase(const key_type& x)
{ return m_tree.erase(x); }
iterator erase(const_iterator first, const_iterator last)
{ return m_tree.erase(first, last); }
void clear()
{ m_tree.clear(); }
// multiset operations:
const_iterator find(const key_type& x) const
{ return m_tree.find(x); }
iterator find(const key_type& x)
{ return m_tree.find(x); }
size_type count(const key_type& x) const
{ return m_tree.count(x); }
const_iterator lower_bound(const key_type& x) const
{ return m_tree.lower_bound(x); }
iterator lower_bound(const key_type& x)
{ return m_tree.lower_bound(x); }
const_iterator upper_bound(const key_type& x) const
{ return m_tree.upper_bound(x); }
iterator upper_bound(const key_type& x)
{ return m_tree.upper_bound(x); }
std::pair<const_iterator, const_iterator>
equal_range(const key_type& x) const
{ return m_tree.equal_range(x); }
std::pair<iterator,iterator>
equal_range(const key_type& x)
{ return m_tree.equal_range(x); }
template <class K1, class C1, class A1>
friend bool operator== (const multiset<K1,C1,A1>&,
const multiset<K1,C1,A1>&);
template <class K1, class C1, class A1>
friend bool operator< (const multiset<K1,C1,A1>&,
const multiset<K1,C1,A1>&);
};
template <class T, class Pred, class Alloc>
inline bool operator==(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y)
{ return x.m_tree == y.m_tree; }
template <class T, class Pred, class Alloc>
inline bool operator<(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y)
{ return x.m_tree < y.m_tree; }
template <class T, class Pred, class Alloc>
inline bool operator!=(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y)
{ return !(x == y); }
template <class T, class Pred, class Alloc>
inline bool operator>(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y)
{ return y < x; }
template <class T, class Pred, class Alloc>
inline bool operator<=(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y)
{ return !(y < x); }
template <class T, class Pred, class Alloc>
inline bool operator>=(const multiset<T,Pred,Alloc>& x,
const multiset<T,Pred,Alloc>& y)
{ return !(x < y); }
template <class T, class Pred, class Alloc>
inline void swap(multiset<T,Pred,Alloc>& x,
multiset<T,Pred,Alloc>& y)
{ x.swap(y); }
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_SET_HPP */
// Local Variables:
// mode:C++
// End:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,830 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_tree file. Modified by Ion Gaztañaga 2005.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_TREE_HPP
#define BOOST_INTERPROCESS_TREE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/detail/tree_func.hpp>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/interprocess/detail/generic_cast.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/mpl/if.hpp>
#include <iterator>
#include <algorithm>
//Red-black tree class, designed for use in implementing STL
//associative containers (set, multiset, map, and multimap). The
//insertion and deletion algorithms are based on those in Cormen,
//Leiserson, and Rivest, Introduction to Algorithms (MIT Press, 1990),
//except that
//
//(1) the header cell is maintained with links not only to the root
//but also to the leftmost node of the tree, to enable constant time
//this->begin(), and to the rightmost node of the tree, to enable linear time
//performance when used with the generic set algorithms (set_union,
//etc.);
//
//(2) when a node being deleted has two children its successor node is
//relinked into its place, rather than copied, so that the only
//iterators invalidated are those referring to the deleted node.
namespace boost { namespace interprocess { namespace detail {
template <class Alloc>
struct rb_tree_node
: rb_tree_node_base<typename pointer_to_other<typename Alloc::pointer, void>::type>
{
typedef rb_tree_node_base<typename pointer_to_other
<typename Alloc::pointer, void>::type> base_t;
typedef typename boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type node_allocator_t;
typedef typename base_t::basic_node_pointer basic_node_pointer;
typedef typename node_allocator_t::pointer node_pointer;
typedef typename Alloc::value_type value_type;
typedef typename Alloc::const_pointer const_pointer;
typedef typename Alloc::pointer pointer;
typedef typename Alloc::const_reference const_reference;
typedef typename Alloc::reference reference;
typedef typename Alloc::difference_type difference_type;
rb_tree_node(const value_type & value)
: m_value(value)
{}
static node_pointer downcast(basic_node_pointer upclass_pointer/*const basic_node_pointer &upclass_pointer*/)
{
return boost::interprocess::do_static_cast<node_pointer>(upclass_pointer);
}
const value_type &value() const { return m_value; }
value_type &value() { return m_value; }
private:
value_type m_value;
};
template <class T, class Alloc, bool convertible_construct>
class rb_tree_alloc_base
//Inherit from node allocator
: public boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type,
//Inherit from node_ptr allocator
public boost::detail::allocator::
rebind_to<Alloc, typename
boost::detail::allocator::rebind_to
<Alloc, rb_tree_node<Alloc> >::type::value_type::basic_node_pointer>::type,
//Inherit from value_ptr allocator
public boost::detail::allocator::rebind_to<Alloc, T>::type
{
public:
typedef typename boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type node_allocator_t;
typedef typename node_allocator_t::value_type node_val_t;
typedef typename node_allocator_t::pointer node_pointer;
typedef typename boost::detail::allocator::
rebind_to<Alloc, T>::type value_allocator_t;
typedef typename value_allocator_t::value_type value_val_t;
typedef typename value_allocator_t::pointer value_ptr_t;
typedef typename value_allocator_t::const_pointer value_cptr_t;
typedef typename value_allocator_t::reference value_ref_t;
typedef typename value_allocator_t::const_reference value_cref_t;
typedef typename boost::detail::allocator::
rebind_to<Alloc, typename node_val_t::
basic_node_pointer>::type basic_node_ptr_allocator_t;
typedef typename basic_node_ptr_allocator_t::pointer basic_node_ptr_ptr_t;
typedef typename basic_node_ptr_allocator_t::value_type basic_node_ptr_t;
typedef detail::scoped_deallocator<node_allocator_t> NodeDeallocator;
typedef detail::scoped_destructor <basic_node_ptr_allocator_t> BasicPtrDestructor;
rb_tree_alloc_base(const value_allocator_t& a)
: node_allocator_t(a),
basic_node_ptr_allocator_t(a),
value_allocator_t(a)
{ this->initialize_when_empty(); }
rb_tree_alloc_base(const rb_tree_alloc_base &x)
: node_allocator_t(x),
basic_node_ptr_allocator_t(x),
value_allocator_t(x)
{
if (!x.m_header->parent()){
this->initialize_when_empty();
}
}
~rb_tree_alloc_base()
{ this->uninitialize_when_empty(); }
node_pointer allocate_and_construct_node(value_cref_t x)
{
node_pointer p = node_allocator_t::allocate(1);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(p, *this);
basic_node_ptr_ptr_t pleft(basic_node_ptr_allocator_t::address(p->left())),
pright(basic_node_ptr_allocator_t::address(p->right())),
pparent(basic_node_ptr_allocator_t::address(p->parent()));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
basic_node_ptr_allocator_t::construct(pleft, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
left_destroy(pleft, *this);
basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
right_destroy(pright, *this);
basic_node_ptr_allocator_t::construct(pparent, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
parent_destroy(pparent, *this);
value_allocator_t::construct(value_allocator_t::address(p->value()), x);
left_destroy.release();
right_destroy.release();
parent_destroy.release();
}
node_deallocator.release();
return p;
}
void destroy_and_deallocate_node(node_pointer p)
{
node_allocator_t::destroy(p);
node_allocator_t::deallocate(p, 1);
}
typename node_allocator_t::size_type max_size() const
{ return node_allocator_t::max_size(); }
void swap (rb_tree_alloc_base &x)
{
node_allocator_t& this_alloc = static_cast<node_allocator_t&>(*this);
node_allocator_t& other_alloc = static_cast<node_allocator_t&>(x);
if (this_alloc != other_alloc){
detail::do_swap(static_cast<value_allocator_t&>(*this),
static_cast<value_allocator_t&>(x));
detail::do_swap(static_cast<basic_node_ptr_allocator_t&>(*this),
static_cast<basic_node_ptr_allocator_t&>(x));
detail::do_swap(this_alloc, other_alloc);
}
detail::do_swap(this->m_header, x.m_header);
}
private:
void initialize_when_empty()
{
this->m_header = node_allocator_t::allocate(1);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(this->m_header, *this);
basic_node_ptr_ptr_t pleft(basic_node_ptr_allocator_t::address(this->m_header->left())),
pright(basic_node_ptr_allocator_t::address(this->m_header->right())),
pparent(basic_node_ptr_allocator_t::address(this->m_header->parent()));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
basic_node_ptr_allocator_t::construct(pleft, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
left_destroy(pleft, *this);
basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
right_destroy(pleft, *this);
basic_node_ptr_allocator_t::construct(pparent, basic_node_ptr_t());
left_destroy.release();
right_destroy.release();
}
//m_value is not constructed since it is not used
//m_color is POD so we don't need to construct it
this->m_header->color() = node_val_t::red_color; // used to distinguish header from
// root, in iterator.operator++
this->m_header->parent() = 0;
this->m_header->left() = this->m_header;
this->m_header->right() = this->m_header;
node_deallocator.release();
}
void uninitialize_when_empty()
{
//Destructors must not throw
basic_node_ptr_allocator_t::destroy(basic_node_ptr_allocator_t::address(this->m_header->left()));
basic_node_ptr_allocator_t::destroy(basic_node_ptr_allocator_t::address(this->m_header->right()));
basic_node_ptr_allocator_t::destroy(basic_node_ptr_allocator_t::address(this->m_header->parent()));
//m_color is POD so we don't need to destroy it
//m_value was not constructed so we don't need to destroy it
node_allocator_t::deallocate(this->m_header, 1);
}
protected:
node_pointer m_header;
};
template <class T, class Alloc>
class rb_tree_alloc_base<T, Alloc, true>
//Inherit from node allocator
: public boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type
{
public:
typedef typename boost::detail::allocator::
rebind_to<Alloc, rb_tree_node<Alloc> >::type node_allocator_t;
typedef typename node_allocator_t::value_type node_val_t;
typedef typename node_allocator_t::pointer node_pointer;
typedef typename boost::detail::allocator::
rebind_to<Alloc, T>::type value_allocator_t;
typedef typename value_allocator_t::value_type value_val_t;
typedef typename value_allocator_t::pointer value_ptr_t;
typedef typename value_allocator_t::const_pointer value_cptr_t;
typedef typename value_allocator_t::reference value_ref_t;
typedef typename value_allocator_t::const_reference value_cref_t;
typedef typename boost::detail::allocator::
rebind_to<Alloc, typename node_val_t::
basic_node_pointer>::type basic_node_ptr_allocator_t;
typedef typename basic_node_ptr_allocator_t::pointer basic_node_ptr_ptr_t;
typedef typename basic_node_ptr_allocator_t::value_type basic_node_ptr_t;
typedef detail::scoped_deallocator<node_allocator_t> NodeDeallocator;
typedef detail::scoped_destructor <basic_node_ptr_allocator_t> BasicPtrDestructor;
rb_tree_alloc_base(const value_allocator_t& a)
: node_allocator_t(a)
{ this->initialize_when_empty(); }
rb_tree_alloc_base(const rb_tree_alloc_base &x)
: node_allocator_t(x)
{ this->initialize_when_empty(); }
~rb_tree_alloc_base()
{ this->uninitialize_when_empty(); }
template<class Convertible>
node_pointer allocate_and_construct_node(const Convertible &x)
{
node_pointer p = node_allocator_t::allocate(1);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(p, *this);
node_allocator_t::construct(p, x);
node_deallocator.release();
return p;
}
void destroy_and_deallocate_node(node_pointer p)
{
node_allocator_t::destroy(p);
node_allocator_t::deallocate(p, 1);
}
typename node_allocator_t::size_type max_size() const
{ return node_allocator_t::max_size(); }
void swap (rb_tree_alloc_base &x)
{
node_allocator_t& this_alloc = static_cast<node_allocator_t&>(*this);
node_allocator_t& other_alloc = static_cast<node_allocator_t&>(x);
if (this_alloc != other_alloc){
detail::do_swap(this_alloc, other_alloc);
}
detail::do_swap(this->m_header, x.m_header);
}
private:
void initialize_when_empty()
{
this->m_header = node_allocator_t::allocate(1);
//If the pointer type a has trivial constructor we can avoid this
if(!boost::has_trivial_constructor<node_pointer>::value){
basic_node_ptr_allocator_t node_ptr_allocator(*this);
scoped_ptr<node_val_t, NodeDeallocator>node_deallocator(this->m_header, *this);
basic_node_ptr_ptr_t pleft(node_ptr_allocator.address(this->m_header->left())),
pright(node_ptr_allocator.address(this->m_header->right())),
pparent(node_ptr_allocator.address(this->m_header->parent()));
//Make sure destructors are called before memory is freed
//if an exception is thrown
{
node_ptr_allocator.construct(pleft, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
left_destroy(pleft, node_ptr_allocator);
node_ptr_allocator.construct(pright, basic_node_ptr_t());
scoped_ptr<basic_node_ptr_t, BasicPtrDestructor>
right_destroy(pright, node_ptr_allocator);
node_ptr_allocator.construct(pparent, basic_node_ptr_t());
left_destroy.release();
right_destroy.release();
}
node_deallocator.release();
}
//m_value is not constructed since it is not used
//m_color is POD so we don't need to construct it
this->m_header->color() = node_val_t::red_color; // used to distinguish header from
// root, in iterator.operator++
this->m_header->parent() = 0;
this->m_header->left() = this->m_header;
this->m_header->right() = this->m_header;
}
void uninitialize_when_empty()
{
//If the pointer type a has trivial destructor we can avoid this
if(!boost::has_trivial_destructor<node_pointer>::value){
basic_node_ptr_allocator_t node_ptr_allocator(*this);
//Destructors must not throw
node_ptr_allocator.destroy(node_ptr_allocator.address(this->m_header->left()));
node_ptr_allocator.destroy(node_ptr_allocator.address(this->m_header->right()));
node_ptr_allocator.destroy(node_ptr_allocator.address(this->m_header->parent()));
}
//m_color is POD so we don't need to destroy it
//m_value was not constructed so we don't need to destroy it
node_allocator_t::deallocate(this->m_header, 1);
}
protected:
node_pointer m_header;
};
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
class rb_tree
: protected rb_tree_alloc_base<Value, Alloc,
has_convertible_construct<Alloc>::value>
{
private:
typedef rb_tree_alloc_base<Value, Alloc,
has_convertible_construct<Alloc>::value> base_t;
typedef typename base_t::node_pointer node_pointer;
typedef typename base_t::node_val_t node_val_t;
typedef typename node_val_t::basic_node_pointer basic_node_pointer;
typedef rb_tree_algo<node_val_t> rb_tree_algo_t;
typedef rb_tree_func<node_val_t, Key,
KeyOfValue, Compare > rb_tree_func_t;
public:
typedef Key key_type;
typedef Value value_type;
typedef typename base_t::value_ptr_t pointer;
typedef typename base_t::value_cptr_t const_pointer;
typedef typename base_t::value_ref_t reference;
typedef typename base_t::value_cref_t const_reference;
typedef typename base_t::value_allocator_t allocator_type;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef rb_tree_const_iterator<node_val_t> const_iterator;
typedef rb_tree_iterator<node_val_t> iterator;
typedef boost::reverse_iterator<iterator> reverse_iterator;
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
rb_tree(const Compare& comp = Compare(),
const allocator_type& a = allocator_type())
: base_t(a), m_data(comp, 0)
{ }
rb_tree(const rb_tree& x)
: base_t(x),
m_data(x.get_compare(), 0)
{
if (x.root()){
this->m_header->color() = node_val_t::red_color;
this->root()=
this->copy_node(node_val_t::downcast(x.m_header->parent()),
this->m_header);
this->leftmost() =
rb_tree_algo_t::minimum_node(node_val_t::downcast(this->root()));
this->rightmost() =
rb_tree_algo_t::maximum_node(node_val_t::downcast(this->root()));
}
this->m_data.m_node_count = x.m_data.m_node_count;
}
~rb_tree() { this->clear(); }
rb_tree& operator=(const rb_tree& x)
{
if (this != &x) {
// Note that Key may be a constant type.
this->clear();
this->m_data.m_node_count = 0;
this->get_compare() = x.get_compare();
if (!x.root()) {
this->root() = 0;
this->leftmost() = this->m_header;
this->rightmost() = this->m_header;
}
else{
this->root() = this->copy_node(x.root(), this->m_header);
this->leftmost() =
rb_tree_algo_t::minimum_node(node_val_t::downcast(this->root()));
this->rightmost() =
rb_tree_algo_t::maximum_node(node_val_t::downcast(this->root()));
this->m_data.m_node_count = x.m_data.m_node_count;
}
}
return *this;
}
public:
// accessors:
Compare key_comp() const
{ return this->get_compare(); }
allocator_type get_allocator() const
{ return allocator_type(*this); }
iterator begin()
{ return iterator(this->leftmost()); }
const_iterator begin() const
{ return const_iterator(this->leftmost()); }
iterator end()
{ return iterator(this->m_header); }
const_iterator end() const
{ return const_iterator(this->m_header); }
reverse_iterator rbegin()
{ return reverse_iterator(this->end()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(this->end()); }
reverse_iterator rend()
{ return reverse_iterator(this->begin()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(this->begin()); }
bool empty() const
{ return !this->m_data.m_node_count; }
size_type size() const
{ return this->m_data.m_node_count; }
size_type max_size() const
{ return base_t::max_size(); }
void swap(rb_tree& t)
{
detail::do_swap(this->m_data.m_node_count, t.m_data.m_node_count);
detail::do_swap(this->get_compare(), t.get_compare());
base_t::swap(t);
}
public:
// insert/erase
std::pair<iterator,bool> insert_unique(const value_type& v)
{
KeyOfValue key_of_value;
node_pointer out;
typename rb_tree_func_t::insert_unique_context context;
if(!rb_tree_func_t::insert_unique_prepare
(this->m_header, this->m_data, key_of_value(v), out, context)){
return std::pair<iterator,bool>(iterator(out), false);
}
node_pointer new_node = this->allocate_and_construct_node(v);
++this->m_data.m_node_count;
rb_tree_func_t::insert_unique_commit
(this->m_header, this->m_data, new_node, out, context);
return std::pair<iterator,bool>(iterator(out), true);
}
iterator insert_unique(iterator hint, const value_type& v)
{
KeyOfValue key_of_value;
node_pointer out;
typename rb_tree_func_t::insert_unique_context context;
if(!rb_tree_func_t::insert_unique_hint_prepare
(this->m_header, this->m_data, hint.get_ptr(),
key_of_value(v), out, context)){
return iterator(out);
}
node_pointer new_node = this->allocate_and_construct_node(v);
++this->m_data.m_node_count;
rb_tree_func_t::insert_unique_commit(this->m_header, this->m_data, new_node, out, context);
return iterator(out);
}
template <class InputIterator>
void insert_unique(InputIterator first, InputIterator last)
{
for ( ; first != last; ++first)
this->insert_unique(*first);
}
iterator insert_equal(const value_type& v)
{
node_pointer tmp = this->allocate_and_construct_node(v);
rb_tree_func_t::insert_equal(this->m_header, this->m_data, tmp);
++this->m_data.m_node_count;
return iterator(tmp);
}
iterator insert_equal(iterator hint, const value_type& v)
{
node_pointer tmp = this->allocate_and_construct_node(v);
rb_tree_func_t::insert_equal_hint(this->m_header, this->m_data,
hint.get_ptr(), tmp);
++this->m_data.m_node_count;
return iterator(tmp);
}
template <class InputIterator>
void insert_equal(InputIterator first, InputIterator last)
{
for ( ; first != last; ++first)
this->insert_equal(*first);
}
iterator erase(const_iterator position)
{
iterator ret(position.get_ptr());
++ret;
node_pointer y = node_val_t::downcast(rb_tree_func_t::erase_node(this->m_header, position.get_ptr()));
this->destroy_and_deallocate_node(y);
--this->m_data.m_node_count;
return ret;
}
size_type erase(const key_type& x)
{
std::pair<iterator,iterator> p = this->equal_range(x);
size_type n = std::distance(p.first, p.second);
this->erase(p.first, p.second);
return n;
}
iterator erase(const_iterator first, const_iterator last)
{
if (first == this->begin() && last == this->end()){
this->clear();
return begin();
}
else{
while (first != last){
first = this->erase(first);
}
return iterator(last.get_ptr());
}
}
void clear()
{
if (this->m_data.m_node_count) {
this->erase_node(node_val_t::downcast(this->root()));
this->leftmost() = this->m_header;
this->root() = 0;
this->rightmost() = this->m_header;
this->m_data.m_node_count = 0;
}
}
// set operations:
iterator find(const key_type& k)
{ return iterator(rb_tree_func_t::find(this->m_header, this->m_data, k)); }
const_iterator find(const key_type& k) const
{ return const_iterator(rb_tree_func_t::find(this->m_header, this->m_data, k)); }
size_type count(const key_type& k) const
{ return size_type(rb_tree_func_t::count(this->m_header, this->m_data, k)); }
iterator lower_bound(const key_type& k)
{ return iterator(rb_tree_func_t::lower_bound(this->m_header, this->m_data, k)); }
const_iterator lower_bound(const key_type& k) const
{ return const_iterator(rb_tree_func_t::lower_bound(this->m_header, this->m_data, k)); }
iterator upper_bound(const key_type& k)
{ return iterator (rb_tree_func_t::upper_bound(this->m_header, this->m_data, k)); }
const_iterator upper_bound(const key_type& k) const
{ return const_iterator (rb_tree_func_t::upper_bound(this->m_header, this->m_data, k)); }
std::pair<iterator,iterator> equal_range(const key_type& k)
{
node_pointer lower, upper;
rb_tree_func_t::equal_range(this->m_header, this->m_data, k, lower, upper);
return std::pair<iterator, iterator>(iterator(lower), iterator(upper));
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
{
node_pointer lower, upper;
rb_tree_func_t::equal_range(this->m_header, this->m_data, k, lower, upper);
return std::pair<const_iterator, const_iterator>(const_iterator(lower), const_iterator(upper));
}
private:
basic_node_pointer &root() const
{ return this->m_header->parent(); }
basic_node_pointer &leftmost() const
{ return this->m_header->left(); }
basic_node_pointer &rightmost() const
{ return this->m_header->right(); }
node_pointer clone_node(basic_node_pointer x)
{
basic_node_pointer tmp = this->allocate_and_construct_node(node_val_t::downcast(x)->value());
tmp->color() = x->color();
tmp->left() = 0;
tmp->right() = 0;
return node_val_t::downcast(tmp);
}
const Compare & get_compare() const
{ return static_cast<const Compare&>(m_data); }
Compare & get_compare()
{ return static_cast<Compare&>(m_data); }
static const Key& get_node_key(node_pointer x)
{ return KeyOfValue()(x->value()); }
node_pointer copy_node(basic_node_pointer x, basic_node_pointer p)
{
// structural copy. x and p must be non-null.
node_pointer top = this->clone_node(x);
top->parent() = p;
BOOST_TRY {
if (x->right())
top->right() = this->copy_node(x->right(), top);
p = top;
x = x->left();
while (x) {
node_pointer y = this->clone_node(x);
p->left() = y;
y->parent() = p;
if (x->right()){
y->right() = this->copy_node(x->right(), y);
}
p = y;
x = x->left();
}
}
BOOST_CATCH(...){
this->erase_node(top);
BOOST_RETHROW;
}
BOOST_CATCH_END
return top;
}
void erase_node(node_pointer x)
{
// erase without rebalancing
while (x) {
this->erase_node(node_val_t::downcast(x->right()));
node_pointer y = node_val_t::downcast(x->left());
this->destroy_and_deallocate_node(x);
x = y;
}
}
private:
struct Data
: public Compare
{
Data(const Compare &comp, size_type node_count)
: Compare(comp), m_node_count(node_count){}
size_type m_node_count; // keeps track of size of tree
} m_data;
};
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator==(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return x.size() == y.size() &&
std::equal(x.begin(), x.end(), y.begin());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return std::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator!=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return !(x == y);
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return y < x;
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return !(y < x);
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y) {
return !(x < y);
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline void
swap(rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
x.swap(y);
}
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_TREE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,974 @@
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's stl_vector.h file. Modified by Ion Gaztañaga.
// Renaming, isolating and porting to generic algorithms. Pointer typedef
// set to allocator::pointer to allow placing it in shared memory.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_SHMEM_VECTOR_HPP
#define BOOST_SHMEM_VECTOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <cstddef>
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <iterator>
#include <boost/detail/no_exceptions_support.hpp>
namespace boost {
namespace interprocess {
namespace detail {
/*!This struct deallocates and allocated memory */
template <class A>
struct vector_alloc_holder : public A
{
typedef typename A::pointer pointer;
//Constructor, does not throw
vector_alloc_holder(const A &a)
: A(a), m_start(0), m_finish(0), m_end(0)
{}
//Destructor
~vector_alloc_holder()
{ this->priv_deallocate(); }
pointer m_start;
pointer m_finish;
pointer m_end;
private:
void priv_deallocate()
{
if(!m_start) return;
this->deallocate(m_start, m_end - m_start);
m_end = m_start;
}
};
} //namespace detail {
//vector class
template <class T, class A>
class vector : private detail::vector_alloc_holder<A>
{
typedef vector<T, A> self_t;
typedef detail::vector_alloc_holder<A> base_t;
typedef detail::scoped_array_deallocator<A> dealloc_t;
public:
//STL container typedefs
typedef T value_type;
typedef A allocator_type;
typedef typename A::pointer pointer;
typedef typename A::const_pointer const_pointer;
typedef typename A::reference reference;
typedef typename A::const_reference const_reference;
typedef typename A::size_type size_type;
typedef typename A::difference_type difference_type;
//This shouldn't be needed but VC6.0 needs this
typedef typename A::pointer vec_ptr;
typedef typename A::const_pointer vec_cptr;
typedef typename A::reference vec_ref;
typedef typename A::const_reference vec_cref;
typedef typename A::difference_type vec_diff;
private:
typedef range_from_ref_iterator<const T, difference_type> range_from_ref_it;
public:
//Vector const_iterator
class const_iterator
: public boost::iterator<std::random_access_iterator_tag,
value_type, vec_diff,
vec_cptr, vec_cref >
{
private:
vec_ptr get_ptr() const { return m_ptr; }
protected:
vec_ptr m_ptr;
explicit const_iterator(vec_ptr ptr) : m_ptr(ptr){}
public:
friend class vector<T, A>;
typedef vec_diff difference_type;
//Constructors
const_iterator() : m_ptr(0){}
//Pointer like operators
const_reference operator*() const
{ return *m_ptr; }
const_pointer operator->() const
{ return m_ptr; }
const_reference operator[](difference_type off) const
{ return m_ptr[off]; }
//Increment / Decrement
const_iterator& operator++()
{ ++m_ptr; return *this; }
const_iterator operator++(int)
{ vec_ptr tmp = m_ptr; ++*this; return const_iterator(tmp); }
const_iterator& operator--()
{ --m_ptr; return *this; }
const_iterator operator--(int)
{ vec_ptr tmp = m_ptr; --*this; return const_iterator(tmp); }
//Arithmetic
const_iterator& operator+=(difference_type off)
{ m_ptr += off; return *this; }
const_iterator operator+(difference_type off) const
{ return const_iterator(m_ptr+off); }
friend const_iterator operator+(difference_type off, const const_iterator& right)
{ return const_iterator(off + right.m_ptr); }
const_iterator& operator-=(difference_type off)
{ m_ptr -= off; return *this; }
const_iterator operator-(difference_type off) const
{ return const_iterator(m_ptr-off); }
difference_type operator-(const const_iterator& right) const
{ return m_ptr - right.m_ptr; }
//Comparison operators
bool operator== (const const_iterator& r) const
{ return m_ptr == r.m_ptr; }
bool operator!= (const const_iterator& r) const
{ return m_ptr != r.m_ptr; }
bool operator< (const const_iterator& r) const
{ return m_ptr < r.m_ptr; }
bool operator<= (const const_iterator& r) const
{ return m_ptr <= r.m_ptr; }
bool operator> (const const_iterator& r) const
{ return m_ptr > r.m_ptr; }
bool operator>= (const const_iterator& r) const
{ return m_ptr >= r.m_ptr; }
};
//Vector iterator
class iterator : public const_iterator
{
protected:
explicit iterator(vec_ptr ptr) : const_iterator(ptr){}
public:
friend class vector<T, A>;
typedef vec_ptr pointer;
typedef vec_ref reference;
//Constructors
iterator(){}
//Pointer like operators
reference operator*() const
{ return *this->m_ptr; }
pointer operator->() const
{ return this->m_ptr; }
reference operator[](difference_type off) const
{return this->m_ptr[off];}
//Increment / Decrement
iterator& operator++()
{ ++this->m_ptr; return *this; }
iterator operator++(int)
{ pointer tmp = this->m_ptr; ++*this; return iterator(tmp); }
iterator& operator--()
{ --this->m_ptr; return *this; }
iterator operator--(int)
{ iterator tmp = *this; --*this; return iterator(tmp); }
// Arithmetic
iterator& operator+=(difference_type off)
{ this->m_ptr += off; return *this; }
iterator operator+(difference_type off) const
{ return iterator(this->m_ptr+off); }
friend iterator operator+(difference_type off, const iterator& right)
{ return iterator(off + right.m_ptr); }
iterator& operator-=(difference_type off)
{ this->m_ptr -= off; return *this; }
iterator operator-(difference_type off) const
{ return iterator(this->m_ptr-off); }
difference_type operator-(const const_iterator& right) const
{ return *((const_iterator*)this) - right; }
};
//Reverse iterators
typedef typename boost::reverse_iterator<iterator>
reverse_iterator;
typedef typename boost::reverse_iterator<const_iterator>
const_reverse_iterator;
public:
//Constructor
explicit vector(const A& a = A())
: base_t(a)
{}
//Construct and fill with n equal objects
vector(size_type n, const T& value = T(),
const allocator_type& a = allocator_type())
: base_t(a)
{
if(n){
//If there is an exception, the base class will
//deallocate the memory
this->m_start = this->allocate(n, 0);
this->m_end = this->m_start + n;
this->m_finish = this->m_start;
this->priv_uninitialized_fill_n(this->m_start, n, value, *this);
this->m_finish = this->m_end;
}
}
//Copy constructor
vector(const vector<T, A>& x)
: base_t(x.get_allocator())
{
size_type n = x.size();
if(n){
this->m_start = this->allocate(x.size(), 0);
this->m_end = this->m_start + x.size();
this->m_finish = this->m_start;
this->priv_uninitialized_copy(x.m_start, x.m_finish, this->m_start, *this);
this->m_finish = this->m_end;
}
}
//Construct from iterator range
template <class InIt>
vector(InIt first, InIt last,
const allocator_type& a = allocator_type())
: base_t(a)
{
const bool aux_boolean = boost::is_integral<InIt>::value;
typedef boost::mpl::bool_<aux_boolean> Result;
this->priv_initialize_aux(first, last, Result());
}
//Destructor
~vector()
{ this->priv_destroy_all(); }
//Functions: begin, rbegin, end, rend
iterator begin()
{ return iterator(this->m_start); }
iterator end()
{ return iterator(this->m_finish); }
const_iterator begin() const
{ return const_iterator(this->m_start); }
const_iterator end() const
{ return const_iterator(this->m_finish); }
reverse_iterator rbegin()
{ return reverse_iterator(this->end()); }
reverse_iterator rend()
{ return reverse_iterator(this->begin()); }
const_reverse_iterator rbegin()const
{ return const_reverse_iterator(this->end());}
const_reverse_iterator rend() const
{ return const_reverse_iterator(this->begin()); }
//Functions: front, back
reference front()
{ return *this->m_start; }
const_reference front() const
{ return *this->m_start; }
reference back()
{ return *(this->m_finish - 1); }
const_reference back() const
{ return *(this->m_finish - 1); }
//Functions: size, max_size, capacity, empty
size_type size() const
{ return size_type(this->m_finish - this->m_start); }
size_type max_size() const
{ return allocator_type::max_size(); }
size_type capacity() const
{ return size_type(this->m_end - this->m_start); }
bool empty() const
{ return this->m_start == this->m_finish; }
//Functions: operator [], at
reference operator[](size_type n)
{ return this->m_start[n]; }
const_reference operator[](size_type n) const
{ return this->m_start[n]; }
reference at(size_type n)
{ this->priv_check_range(n); return this->m_start[n]; }
const_reference at(size_type n) const
{ this->priv_check_range(n); return this->m_start[n]; }
//Functions: get_allocator, reserve
allocator_type get_allocator() const
{ return allocator_type(*this); }
void reserve(size_type n)
{
if (capacity() < n){
//Allocate new size, copy data and free old buffer
const size_type old_size = size();
pointer tmp = this->priv_allocate_and_copy(n, this->m_start, this->m_finish);
this->priv_destroy_and_deallocate();
this->m_start = tmp;
this->m_finish = tmp + old_size;
this->m_end = this->m_start + n;
}
}
//Assignment
vector<T, A>& operator=(const vector<T, A>& x)
{
if (&x != this){
const size_type xlen = x.size();
if (xlen > this->capacity()){
//There is no memory to hold values from x. Allocate a new buffer,
//copy data from x, and destroy and deallocate previous values
pointer tmp = this->priv_allocate_and_copy(xlen, x.m_start, x.m_finish);
this->priv_destroy_and_deallocate();
this->m_start = tmp;
this->m_end = this->m_start + xlen;
}
else if (size() >= xlen){
//There is enough memory but current buffer has more objects than x.
//Copy all objects from x and destroy the remaining objects
pointer i = std::copy(x.m_start, x.m_finish, this->m_start);
this->priv_destroy_range(i, this->m_finish);
}
else {
//There is enough memory but current buffer has less objects than x.
//Copy the first this->size() objects from x and initialize the
//rest of the buffer with remaining x objects
std::copy(x.m_start, x.m_start + size(), this->m_start);
this->priv_uninitialized_copy(x.m_start + size(), x.m_finish, this->m_finish, *this);
}
this->m_finish = this->m_start + xlen;
}
return *this;
}
void assign(size_type n, const value_type& val = T())
{
this->assign(range_from_ref_it(val, n)
,range_from_ref_it());
/*
if (n > this->capacity()){
//There is not enough memory, create a temporal vector and swap
vector<T, A> tmp(n, val, static_cast<const allocator_type&>(*this));
tmp.swap(*this);
}
else if (n > size()){
//There is enough memory, but we have less objects. Assign current
//objects and initialize the rest.
std::fill(this->m_start, this->m_finish, val);
size_t rest = n - size();
this->priv_uninitialized_fill_n(this->m_finish, rest, val, *this);
this->m_finish += rest;
}
else{
//There is enough memory, but we have more objects. Assign the first
//n objects and destroy the rest
std::fill_n(this->m_start, n, val);
this->erase(iterator(this->m_start + n), iterator(this->m_finish));
}*/
}
template <class InIt>
void assign(InIt first, InIt last)
{
//Dispatch depending on integer/iterator
const bool aux_boolean = boost::is_integral<InIt>::value;
typedef boost::mpl::bool_<aux_boolean> Result;
this->priv_assign_dispatch(first, last, Result());
}
void push_back(const T& x = T())
{
if (this->m_finish != this->m_end){
//There is more memory, just construct a new object at the end
this->construct(this->m_finish, x);
++this->m_finish;
}
else{
//No enough memory, insert a new object at the end
this->insert(this->end(), static_cast<size_type>(1), x);
}
}
void swap(vector<T, A>& x)
{
allocator_type &this_al = *this, &other_al = x;
//Just swap pointers
detail::do_swap(this->m_start, x.m_start);
detail::do_swap(this->m_finish, x.m_finish);
detail::do_swap(this->m_end, x.m_end);
if (this_al != other_al){
detail::do_swap(this_al, other_al);
}
}
iterator insert(iterator position, const T& x = T())
{
//Just call more general insert(pos, size, value) and return iterator
size_type n = position - begin();
this->insert(position, (size_type)1, x);
return iterator(this->m_start + n);
}
template <class InIt>
void insert(iterator pos, InIt first, InIt last)
{
//Dispatch depending on integer/iterator
const bool aux_boolean = boost::is_integral<InIt>::value;
typedef boost::mpl::bool_<aux_boolean> Result;
this->priv_insert_dispatch(pos, first, last, Result());
}
void insert (iterator position, size_type n, const T& x)
{
this->insert(position
,range_from_ref_it(x, n)
,range_from_ref_it());
/*
if (n != 0){
if (size_type(this->m_end - this->m_finish) >= n){
//There is enough memory
const size_type elems_after = this->end() - position;
pointer old_finish = this->m_finish;
if (elems_after > n){
//New elements can be just copied.
//Move to uninitialized memory last objects
this->priv_uninitialized_copy(this->m_finish - n, this->m_finish,
this->m_finish, *this);
this->m_finish += n;
//Copy previous to last objects to the initialized end
std::copy_backward(position.get_ptr(), old_finish - n,
old_finish);
//Insert new objects in the position
std::fill(position.get_ptr(), position.get_ptr() + n, x);
}
else {
//The new elements don't fit in the [position, end()) range. Copy
//to the beginning of the unallocated zone the last new elements.
this->priv_uninitialized_fill_n(this->m_finish, n - elems_after, x, *this);
this->m_finish += n - elems_after;
//Copy old [position, end()) elements to the uninitialized memory
this->priv_uninitialized_copy(position.get_ptr(), old_finish,
this->m_finish, *this);
this->m_finish += elems_after;
//Insert first new elements in position
std::fill(position.get_ptr(), old_finish, x);
}
}
else {
//There is not enough memory, allocate a new buffer
size_type old_size = size();
size_type len = old_size + ((old_size/2 > n) ? old_size/2 : n);
pointer new_start = this->allocate(len, 0);
scoped_ptr<T, dealloc_t> scoped_alloc(new_start, dealloc_t(*this, len));
pointer new_finish = new_start;
//Initialize [begin(), position) old buffer to the start of the new buffer
new_finish = this->priv_uninitialized_copy(this->m_start, position.get_ptr(),
new_start, *this);
//Initialize new n objects, starting from previous point
this->priv_uninitialized_fill_n(new_finish, n, x, *this);
new_finish = new_finish + n;
//Initialize from the rest of the old buffer, starting from previous point
new_finish = this->priv_uninitialized_copy(position.get_ptr(), this->m_finish,
new_finish, *this);
//New data is in the new buffer, release scoped deallocation
scoped_alloc.release();
//Destroy and deallocate old elements
this->priv_destroy_and_deallocate();
this->m_start = new_start;
this->m_finish = new_finish;
this->m_end = new_start + len;
}
}*/
}
void pop_back()
{
//Destroy last element
--this->m_finish;
this->destroy(this->m_finish);
}
// Return type of erase(const_iterator):
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1753.html#130
iterator erase(const_iterator position)
{
if (position + 1 != end()){
//If not the last element, copy left [position, end()) elements
std::copy((position + 1).get_ptr(), this->m_finish, position.get_ptr());
}
--this->m_finish;
//Destroy last element
this->destroy(this->m_finish);
return iterator(position.get_ptr());
}
iterator erase(const_iterator first, const_iterator last)
{
//Overwrite [last, end()) elements to first
pointer i = std::copy(last.get_ptr(), this->m_finish, first.get_ptr());
//Destroy remaining objects
this->priv_destroy_range(i, this->m_finish);
this->m_finish = this->m_finish - (last - first);
return iterator(first.get_ptr());
}
void resize(size_type new_size, const T& x = T())
{
if (new_size < size())
//Destroy last elements
this->erase(iterator(this->m_start + new_size), iterator(this->m_finish));
else
//Insert new elements at the end
this->insert(iterator(this->m_finish), new_size - size(), x);
}
void clear()
{ this->priv_destroy_all(); }
private:
void priv_destroy_all()
{
if(!this->m_start)
return;
pointer start = this->m_start;
for(;start != this->m_finish; ++start)
this->destroy(start);
this->m_finish = this->m_start;
}
template <class InIt>
void priv_range_initialize(InIt first,
InIt last, std::input_iterator_tag)
{
//Just insert all elements at the end
std::copy(first, last, std::back_inserter(*this));
}
template <class FwdIt>
void priv_range_initialize(FwdIt first,
FwdIt last, std::forward_iterator_tag)
{
//Calculate distance, allocate and copy
size_type n = 0;
n = std::distance(first, last);
this->m_start = this->allocate(n, 0);
scoped_ptr<T, dealloc_t> scoped_alloc(this->m_start, dealloc_t(*this, n));
this->m_end = this->m_start + n;
this->m_finish = this->priv_uninitialized_copy(first, last, this->m_start, *this);
scoped_alloc.release();
}
template <class FwdIt>
void priv_range_insert(iterator position, FwdIt first,
FwdIt last, std::forward_iterator_tag)
{
if (first != last){
size_type n = 0;
n = std::distance(first, last);
if (size_type(this->m_end - this->m_finish) >= n){
//There is enough memory
const size_type elems_after = this->m_finish - position.get_ptr();
pointer old_finish = this->m_finish;
if (elems_after > n){
//New elements can be just copied.
//Move to unitialized memory last objects
this->priv_uninitialized_copy(this->m_finish - n, this->m_finish,
this->m_finish, *this);
this->m_finish += n;
//Copy previous to last objects to the initialized end
std::copy_backward(position.get_ptr(), old_finish - n, old_finish);
//Insert new objects in the position
std::copy(first, last, position.get_ptr());
}
else {
//The new elements don't fit in the [position, end()) range. Copy
//to the beginning of the unalocated zone the last new elements.
FwdIt mid = first;
std::advance(mid, elems_after);
this->priv_uninitialized_copy(mid, last, this->m_finish, *this);
this->m_finish += n - elems_after;
//Copy old [position, end()) elements to the unitialized memory
this->priv_uninitialized_copy(position.get_ptr(), old_finish,
this->m_finish, *this);
this->m_finish += elems_after;
//Copy first new elements in position
std::copy(first, mid, position.get_ptr());
}
}
else {
//There is not enough memory, allocate a new buffer
const size_type old_size = size();
const size_type len = old_size + ((old_size/2 > n) ? old_size/2 : n);
pointer new_start = this->allocate(len, 0);
scoped_ptr<T, dealloc_t> scoped_alloc(new_start, dealloc_t(*this, len));
pointer new_finish = new_start;
BOOST_TRY{
//Initialize with [begin(), position) old buffer
//the start of the new buffer
new_finish = this->priv_uninitialized_copy
(this->m_start, position.get_ptr(), new_start, *this);
//Initialize new objects, starting from previous point
new_finish = this->priv_uninitialized_copy
(first, last, new_finish, *this);
//Initialize from the rest of the old buffer,
//starting from previous point
new_finish = this->priv_uninitialized_copy
(position.get_ptr(), this->m_finish, new_finish, *this);
}
BOOST_CATCH(...){
this->priv_destroy_range(new_start, new_finish);
this->deallocate(new_start, len);
BOOST_RETHROW
}
BOOST_CATCH_END
scoped_alloc.release();
//Destroy and deallocate old elements
this->priv_destroy_and_deallocate();
this->m_start = new_start;
this->m_finish = new_finish;
this->m_end = new_start + len;
}
}
}
template <class InIt>
void priv_range_insert(iterator pos,
InIt first, InIt last,
std::input_iterator_tag)
{
//Insert range before the pos position
std::copy(std::inserter(*this, pos), first, last);
}
template <class InIt>
void priv_assign_aux(InIt first, InIt last,
std::input_iterator_tag)
{
//Overwrite all elements we can from [first, last)
iterator cur = begin();
for ( ; first != last && cur != end(); ++cur, ++first){
*cur = *first;
}
if (first == last){
//There are no more elements in the secuence, erase remaining
this->erase(cur, end());
}
else{
//There are more elements in the range, insert the remaining ones
this->insert(end(), first, last);
}
}
template <class FwdIt>
void priv_assign_aux(FwdIt first, FwdIt last,
std::forward_iterator_tag)
{
size_type len = 0;
len = std::distance(first, last);
if (len > capacity()){
//There is no enough memory, allocate and copy new buffer
pointer tmp = this->priv_allocate_and_copy(len, first, last);
//Destroy and deallocate old buffer
this->priv_destroy_and_deallocate();
this->m_start = tmp;
this->m_end = this->m_finish = this->m_start + len;
}
else if (size() >= len){
//There is memory, but there are more old elements than new ones
//Overwrite old elements with new ones
pointer new_finish = std::copy(first, last, this->m_start);
//Destroy remaining old elements
this->priv_destroy_range(new_finish, this->m_finish);
this->m_finish = new_finish;
}
else {
//There is memory, but there are less old elements than new ones
//Overwrite old elements with new ones
FwdIt mid = first;
std::advance(mid, size());
std::copy(first, mid, this->m_start);
//Initialize the remaining new elements in the unitialized memory
this->m_finish = this->priv_uninitialized_copy(mid, last, this->m_finish, *this);
}
}
template <class Integer>
void priv_assign_dispatch(Integer n, Integer val, boost::mpl::true_)
{ this->assign((size_type) n, (T) val); }
template <class InIt>
void priv_assign_dispatch(InIt first, InIt last,
boost::mpl::false_)
{
//Dispatch depending on integer/iterator
typedef typename
std::iterator_traits<InIt>::iterator_category ItCat;
this->priv_assign_aux(first, last, ItCat());
}
template <class Integer>
void priv_insert_dispatch( iterator pos, Integer n,
Integer val, boost::mpl::true_)
{ this->insert(pos, (size_type)n, (T)val); }
template <class InIt>
void priv_insert_dispatch(iterator pos, InIt first,
InIt last, boost::mpl::false_)
{
//Dispatch depending on integer/iterator
typedef typename
std::iterator_traits<InIt>::iterator_category ItCat;
this->priv_range_insert(pos, first, last, ItCat());
}
void priv_destroy_range(pointer p, pointer p2)
{ for(;p != p2; ++p) this->destroy(p); }
template <class Integer>
void priv_initialize_aux(Integer n, Integer value, boost::mpl::true_)
{
//Allocate and initialize integer vector buffer
this->m_start = this->allocate(n, 0);
scoped_ptr<T, dealloc_t> scoped_alloc(this->m_start, dealloc_t(*this, n));
this->m_end = this->m_start + n;
this->m_finish = this->m_start;
this->priv_uninitialized_fill_n(this->m_start, n, value, *this);
this->m_finish = this->m_start + n;
scoped_alloc.release();
}
template <class InIt>
void priv_initialize_aux(InIt first, InIt last,
boost::mpl::false_)
{
//Dispatch depending on integer/iterator
typedef typename
std::iterator_traits<InIt>::iterator_category ItCat;
this->priv_range_initialize(first, last, ItCat());
}
void priv_destroy_and_deallocate()
{
//If there is allocated memory, destroy and deallocate
if(this->m_start != 0){
this->priv_destroy_range(this->m_start, this->m_finish);
this->deallocate(this->m_start, this->m_end - this->m_start);
}
}
template <class FwdIt>
pointer priv_allocate_and_copy(size_type n, FwdIt first,
FwdIt last)
{
//Allocate n element buffer and initialize from range
pointer result = this->allocate(n, 0);
scoped_ptr<T, dealloc_t> scoped_alloc(result, dealloc_t(*this, n));
this->priv_uninitialized_copy(first, last, result, *this);
scoped_alloc.release();
return result;
}
void priv_check_range(size_type n) const
{
//If n is out of range, throw an out_of_range exception
if (n >= size())
throw std::out_of_range("vector::at");
}
template<class InIt, class FwdIt, class alloc> inline
FwdIt priv_uninitialized_copy(InIt first, InIt last,
FwdIt dest, alloc& al)
{
//Save initial destination position
FwdIt dest_init = dest;
BOOST_TRY{
//Try to build objects
for (; first != last; ++dest, ++first){
al.construct(dest, *first);
}
}
BOOST_CATCH(...){
//Call destructors
for (; dest_init != dest; ++dest_init){
al.destroy(dest_init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return (dest);
}
template<class FwdIt, class Count, class Alloc> inline
void priv_uninitialized_fill_n(FwdIt first, Count count,
const T& val, Alloc& al)
{
//Save initial position
FwdIt init = first;
BOOST_TRY{
//Construct objects
for (; count--; ++first){
al.construct(first, val);
}
}
BOOST_CATCH(...){
//Call destructors
for (; init != first; ++init){
al.destroy(init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
}
};
template <class T, class A>
inline bool
operator==(const vector<T, A>& x, const vector<T, A>& y)
{
//Check first size and each element if needed
return x.size() == y.size() &&
std::equal(x.begin(), x.end(), y.begin());
}
template <class T, class A>
inline bool
operator!=(const vector<T, A>& x, const vector<T, A>& y)
{
//Check first size and each element if needed
return x.size() != y.size() ||
!std::equal(x.begin(), x.end(), y.begin());
}
template <class T, class A>
inline bool
operator<(const vector<T, A>& x, const vector<T, A>& y)
{
return std::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end());
}
template <class T, class A>
inline void swap(vector<T, A>& x, vector<T, A>& y)
{
x.swap(y);
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_SHMEM_VECTOR_HPP

View File

@@ -0,0 +1,34 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_CREATION_TAGS_HPP
#define BOOST_INTERPROCESS_CREATION_TAGS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost { namespace interprocess { namespace detail {
struct create_only_t {};
struct open_only_t {};
struct open_or_create_t {};
} //namespace detail {
static const detail::create_only_t create_only = detail::create_only_t();
static const detail::open_or_create_t open_or_create = detail::open_or_create_t();
static const detail::open_only_t open_only = detail::open_only_t();
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP

View File

@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_GENERIC_CAST_HPP
#define BOOST_INTERPROCESS_GENERIC_CAST_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/type_traits/is_pointer.hpp>
//Predeclaration of pointer casts
namespace boost
{
template<class T, class U>
T static_pointer_cast(const U &r);
template<class T, class U>
T const_pointer_cast(const U &r);
template<class T, class U>
T dynamic_pointer_cast(const U &r);
template<class T, class U>
T reinterpret_pointer_cast(const U &r);
} //namespace boost
namespace boost { namespace interprocess { namespace detail {
template<class T, class U>
inline T do_static_cast_impl(const U &r, const boost::false_type)
{
return static_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_static_cast_impl(const U &r, const boost::true_type)
{
return static_cast<T>(r);
}
template<class T, class U>
inline T do_dynamic_cast_impl(const U &r, const boost::false_type)
{
return dynamic_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_dynamic_cast_impl(const U &r, const boost::true_type)
{
return dynamic_cast<T>(r);
}
template<class T, class U>
inline T do_reinterpret_cast_impl(const U &r, const boost::false_type)
{
return reinterpret_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_reinterpret_cast_impl(const U &r, const boost::true_type)
{
return reinterpret_cast<T>(r);
}
template<class T, class U>
inline T do_const_cast_impl(const U &r, const boost::false_type)
{
return const_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_const_cast_impl(const U &r, const boost::true_type)
{
return const_cast<T>(r);
}
} //namespace detail {
template<class T, class U>
inline T do_static_cast(const U &r)
{
return detail::do_static_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
template<class T, class U>
inline T do_dynamic_cast(const U &r)
{
return detail::do_dynamic_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
template<class T, class U>
inline T do_reinterpret_cast(const U &r)
{
return detail::do_reinterpret_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
template<class T, class U>
inline T do_const_cast(const U &r)
{
return detail::do_const_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_GENERIC_CAST_HPP

View File

@@ -0,0 +1,46 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MULTI_SEGMENT_SERVICES_HPP
#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
/*!\file
Describes a named shared memory allocation user class.
*/
namespace boost {
namespace interprocess {
class multi_segment_services
{
public:
virtual std::pair<void *, std::size_t> create_new_segment(std::size_t mem) = 0;
virtual bool update_segments () = 0;
virtual ~multi_segment_services() = 0;
};
inline multi_segment_services::~multi_segment_services()
{}
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP

View File

@@ -0,0 +1,29 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_CAST_TAGS_HPP
#define BOOST_INTERPROCESS_CAST_TAGS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost { namespace interprocess { namespace detail {
struct static_cast_tag {};
struct const_cast_tag {};
struct dynamic_cast_tag {};
struct reinterpret_cast_tag {};
}}} //namespace boost { namespace interprocess { namespace detail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CAST_TAGS_HPP

View File

@@ -0,0 +1,24 @@
#ifdef _MSC_VER
#pragma warning (push)
//
//'function' : resolved overload was found by argument-dependent lookup
//A function found by argument-dependent lookup (Koenig lookup) was eventually
//chosen by overload resolution.
//
//In Visual C++ .NET and earlier compilers, a different function would have
//been called. To pick the original function, use an explicitly qualified name.
//
#pragma warning (disable : 4675)
#pragma warning (disable : 4996)
#pragma warning (disable : 4503)
#pragma warning (disable : 4284) // odd return type for operator->
#pragma warning (disable : 4244) // possible loss of data
#endif
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
# pragma warn -8026 // shut up warning "cannot inline function because ..."
# pragma warn -8027 // shut up warning "cannot inline function because ..."
#endif

View File

@@ -0,0 +1,11 @@
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#if defined _MSC_VER
#pragma warning (pop)
#endif
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
# pragma warn .8026
# pragma warn .8027
#endif

View File

@@ -0,0 +1,34 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_CREATION_TAGS_HPP
#define BOOST_INTERPROCESS_CREATION_TAGS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost { namespace interprocess { namespace detail {
struct create_only_t {};
struct open_only_t {};
struct open_or_create_t {};
} //namespace detail {
static const detail::create_only_t create_only = detail::create_only_t();
static const detail::open_or_create_t open_or_create = detail::open_or_create_t();
static const detail::open_only_t open_only = detail::open_only_t();
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP

View File

@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_GENERIC_CAST_HPP
#define BOOST_INTERPROCESS_GENERIC_CAST_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/type_traits/is_pointer.hpp>
//Predeclaration of pointer casts
namespace boost
{
template<class T, class U>
T static_pointer_cast(const U &r);
template<class T, class U>
T const_pointer_cast(const U &r);
template<class T, class U>
T dynamic_pointer_cast(const U &r);
template<class T, class U>
T reinterpret_pointer_cast(const U &r);
} //namespace boost
namespace boost { namespace interprocess { namespace detail {
template<class T, class U>
inline T do_static_cast_impl(const U &r, const boost::false_type)
{
return static_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_static_cast_impl(const U &r, const boost::true_type)
{
return static_cast<T>(r);
}
template<class T, class U>
inline T do_dynamic_cast_impl(const U &r, const boost::false_type)
{
return dynamic_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_dynamic_cast_impl(const U &r, const boost::true_type)
{
return dynamic_cast<T>(r);
}
template<class T, class U>
inline T do_reinterpret_cast_impl(const U &r, const boost::false_type)
{
return reinterpret_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_reinterpret_cast_impl(const U &r, const boost::true_type)
{
return reinterpret_cast<T>(r);
}
template<class T, class U>
inline T do_const_cast_impl(const U &r, const boost::false_type)
{
return const_pointer_cast<typename T::value_type>(r);
}
template<class T, class U>
inline T do_const_cast_impl(const U &r, const boost::true_type)
{
return const_cast<T>(r);
}
} //namespace detail {
template<class T, class U>
inline T do_static_cast(const U &r)
{
return detail::do_static_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
template<class T, class U>
inline T do_dynamic_cast(const U &r)
{
return detail::do_dynamic_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
template<class T, class U>
inline T do_reinterpret_cast(const U &r)
{
return detail::do_reinterpret_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
template<class T, class U>
inline T do_const_cast(const U &r)
{
return detail::do_const_cast_impl<T>(r, typename boost::is_pointer<U>::type());
}
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_GENERIC_CAST_HPP

View File

@@ -0,0 +1,127 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_DETAIL_GLOBAL_LOCK_HPP
#define BOOST_INTERPROCESS_DETAIL_GLOBAL_LOCK_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h> //O_CREAT, O_*...
# include <unistd.h> //ftruncate, close
# include <semaphore.h> //sem_t* family, SEM_VALUE_MAX
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
# else
# error Unknown platform
# endif
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
namespace boost {
namespace interprocess {
namespace detail {
class global_lock
{
public:
global_lock();
bool acquire();
~global_lock();
void release();
private:
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
void *m_mut;
#else
sem_t *m_sem;
#endif
bool m_acquired;
};
inline global_lock::~global_lock()
{ this->release(); }
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline global_lock::global_lock()
: m_mut(0), m_acquired(false){}
inline bool global_lock::acquire()
{
m_mut = winapi::create_mutex("/boost_shmem_shm_global_mutex");
if(m_mut == 0)
return false;
unsigned long ret = winapi::wait_for_single_object(m_mut, winapi::infinite_time);
//Other thread has abandoned this without closing the handle
if(ret == winapi::wait_abandoned){
ret = winapi::wait_for_single_object(m_mut, winapi::infinite_time);
}
m_acquired = ret == winapi::wait_object_0;
return m_acquired;
}
inline void global_lock::release()
{
if(m_acquired){
winapi::release_mutex(m_mut);
m_acquired = false;
}
if(m_mut){
winapi::close_handle(m_mut);
m_mut = 0;
}
}
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline global_lock::global_lock()
: m_sem((sem_t*)-1), m_acquired(false){}
inline bool global_lock::acquire()
{
mode_t mode = S_IRWXG | S_IRWXO | S_IRWXU;
m_sem = sem_open("/boost_shmem_shm_global_mutex", O_CREAT, mode, 1);
if(m_sem == ((sem_t*)-1))
return false;
m_acquired = sem_wait(m_sem) == 0;
return m_acquired;
}
inline void global_lock::release()
{
if(m_acquired){
sem_post(m_sem);
m_acquired = false;
}
if(m_sem != ((sem_t*)-1)){
sem_close(m_sem);
m_sem = ((sem_t*)-1);
}
}
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_GLOBAL_LOCK_HPP

View File

@@ -0,0 +1,551 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_DETAIL_MANAGED_MEMORY_IMPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_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/mem_algo/simple_seq_fit.hpp>
#include <boost/interprocess/sync/mutex_family.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/segment_manager.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
//
#include <boost/noncopyable.hpp>
#include <boost/ref.hpp>
#include <boost/detail/no_exceptions_support.hpp>
//
#include <utility>
#include <fstream>
#include <new>
#include <assert.h>
/*!\file
Describes a named shared memory allocation user class.
*/
namespace boost {
namespace interprocess {
namespace detail {
/*!
This class is designed to be a base class to classes that manage
creation of objects in a fixed size memory buffer. Apart
from allocating raw memory, the user can construct named objects. To
achieve this, this class uses the reserved space provided by the allocation
algorithm to place a named_allocator_algo, who takes care of name mappings.
The class can be customized with the char type used for object names
and the memory allocation algorithm to be used.*/
template<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_memory_impl
{
public:
typedef segment_manager
<CharType, MemoryAlgorithm, IndexType> segment_manager;
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef typename MemoryAlgorithm::mutex_family mutex_family;
typedef CharType char_t;
typedef std::ptrdiff_t handle_t;
private:
typedef basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType> self_t;
typedef typename
segment_manager::char_ptr_holder_t char_ptr_holder_t;
protected:
/*!Constructor. Allocates basic resources. Never throws.*/
basic_managed_memory_impl()
: mp_header(0){}
/*!Destructor. Calls close. Never throws.*/
~basic_managed_memory_impl()
{ this->close_impl(); }
/*!Places segment manager in the reserved space. This can throw.*/
bool create_impl (void *addr, std::size_t size)
{
if(mp_header) return false;
//Check if there is enough space
if(size < segment_manager::get_min_size())
return false;
//This function should not throw. The index construction can
//throw if constructor allocates memory. So we must catch it.
BOOST_TRY{
//Let's construct the allocator in memory
mp_header = new(addr) segment_manager(size);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
return true;
}
/*!Connects to a segment manager in the reserved buffer. Never throws.*/
bool open_impl (void *addr, std::size_t size)
{
if(mp_header) return false;
mp_header = static_cast<segment_manager*>(addr);
return true;
}
/*!Frees resources. Never throws.*/
bool close_impl()
{
bool ret = mp_header != 0;
mp_header = 0;
return ret;
}
/*!Frees resources and destroys common resources. Never throws.*/
bool destroy_impl()
{
if(mp_header == 0)
return false;
mp_header->~segment_manager();
this->close_impl();
return true;
}
/*!Creates named_xxx_object from file. Never throws.*/
template<class MemCreatorFunc, class CharT>
bool create_from_file (const CharT *filename,
MemCreatorFunc &memcreator)
{
std::basic_ifstream< CharT, std::char_traits<CharT> >
file(filename, std::ios::binary);
//Check file
if(!file) return false;
//Calculate size
file.seekg(0, std::ios::end);
std::size_t size = file.tellg();
file.seekg(0, std::ios::beg);
//Create from stream
return create_from_istream(file, size, memcreator);
}
/*!Creates memory from an istream. Never throws.*/
template<class MemCreatorFunc>
bool create_from_istream (std::istream &instream,
std::size_t size,
MemCreatorFunc &memcreator)
{
if(mp_header) return false;
//Check for minimum size
if(size < MemoryAlgorithm::get_min_size (0))
return false;
mp_header = static_cast<segment_manager*>(memcreator(size));
if(!mp_header) return false;
//Create memory
return instream.read(detail::char_ptr_cast(mp_header),
(std::streamsize)size).good();
}
/*!*/
void grow(std::size_t extra_bytes)
{ mp_header->grow(extra_bytes); }
public:
/*!Returns segment manager. Never throws.*/
segment_manager *get_segment_manager() const
{ return mp_header; }
/*!Returns the base address of the memory in this process. Never throws.*/
void * get_address () const
{ return mp_header; }
/*!Returns the size of memory segment. Never throws.*/
std::size_t get_size () const
{ return mp_header->get_size(); }
/*!Transforms an absolute address into an offset from base address.
The address must belong to the memory segment. Never throws.*/
handle_t get_handle_from_address (const void *ptr) const
{
return detail::char_ptr_cast(ptr) -
detail::char_ptr_cast(this->get_address());
}
/*!Returns true if the address belongs to the managed memory segment*/
bool belongs_to_segment (const void *ptr) const
{
return ptr >= this->get_address() &&
ptr < (detail::char_ptr_cast(ptr) + this->get_size());
}
/*!Transforms previously obtained offset into an absolute address in the
process space of the current process. Never throws.*/
void * get_address_from_handle (handle_t offset) const
{ return detail::char_ptr_cast(this->get_address()) + offset; }
/*!Searches for nbytes of free memory in the segment, marks the
memory as used and return the pointer to the memory. If no
memory is available throws a boost::interprocess::bad_alloc exception*/
void* allocate (std::size_t nbytes)
{ return mp_header->allocate(nbytes); }
/*!Searches for nbytes of free memory in the segment, marks the
memory as used and return the pointer to the memory. If no memory
is available return 0. Never throws.*/
void* allocate (std::size_t nbytes, std::nothrow_t nothrow)
{ return mp_header->allocate(nbytes, std::nothrow); }
/*!Marks previously allocated memory as free. Never throws.*/
void deallocate (void *addr)
{ if (mp_header) mp_header->deallocate(addr); }
/*!Tries to find a previous named allocation address. Returns a memory
buffer and the object count. If not found returned pointer is 0.
Never throws.*/
template <class T>
std::pair<T*, std::size_t> find (char_ptr_holder_t name)
{ return mp_header->find<T>(name); }
/*!Creates a named object or array in memory
Allocates and constructs a T object or an array of T in memory,
associates this with the given name and returns a pointer to the
created object. If an array is being constructed all objects are
created using the same parameters given to this function.
-> If the name was previously used, returns 0.
-> Throws boost::interprocess::bad_alloc if there is no available memory
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and if an
array was being constructed, destructors of created objects are called
before freeing the memory.*/
template <class T>
typename segment_manager::template construct_proxy<T, true>::type
construct(char_ptr_holder_t name)
{ return mp_header->construct<T>(name); }
/*!Finds or creates a named object or array in memory
Tries to find an object with the given name in memory. If
found, returns the pointer to this pointer. If the object is not found,
allocates and constructs a T object or an array of T in memory,
associates this with the given name and returns a pointer to the
created object. If an array is being constructed all objects are
created using the same parameters given to this function.
-> Throws boost::interprocess::bad_alloc if there is no available memory
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and if an
array was being constructed, destructors of created objects are called
before freeing the memory.*/
template <class T>
typename segment_manager::template find_construct_proxy<T, true>::type
find_or_construct(char_ptr_holder_t name)
{ return mp_header->find_or_construct<T>(name); }
/*!Creates a named object or array in memory
Allocates and constructs a T object or an array of T in memory,
associates this with the given name and returns a pointer to the
created object. If an array is being constructed all objects are
created using the same parameters given to this function.
-> If the name was previously used, returns 0.
-> Returns 0 if there is no available memory
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and if an
array was being constructed, destructors of created objects are called
before freeing the memory.*/
template <class T>
typename segment_manager::template construct_proxy<T, false>::type
construct(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->construct<T>(name, nothrow); }
/*!Finds or creates a named object or array in memory
Tries to find an object with the given name in memory. If
found, returns the pointer to this pointer. If the object is not found,
allocates and constructs a T object or an array of T in memory,
associates this with the given name and returns a pointer to the
created object. If an array is being constructed all objects are
created using the same parameters given to this function.
-> Returns 0 if there is no available memory
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and if an
array was being constructed, destructors of created objects are called
before freeing the memory.*/
template <class T>
typename segment_manager::template find_construct_proxy<T, false>::type
find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->find_or_construct<T>(name, nothrow); }
/*!Creates a named array from iterators in memory
Allocates and constructs an array of T in memory,
associates this with the given name and returns a pointer to the
created object. Each element in the array is created using the
objects returned when dereferencing iterators as parameters
and incrementing all iterators for each element.
-> If the name was previously used, returns 0.
-> Throws boost::interprocess::bad_alloc if there is no available memory
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and
destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template construct_iter_proxy<T, true>::type
construct_it(char_ptr_holder_t name)
{ return mp_header->construct_it<T>(name); }
/*!Finds or creates a named array from iterators in memory
Tries to find an object with the given name in memory. If
found, returns the pointer to this pointer. If the object is not found,
allocates and constructs an array of T in memory,
associates this with the given name and returns a pointer to the
created object. Each element in the array is created using the
objects returned when dereferencing iterators as parameters
and incrementing all iterators for each element.
-> If the name was previously used, returns 0.
-> Throws boost::interprocess::bad_alloc if there is no available memory
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and
destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template find_construct_iter_proxy<T, true>::type
find_or_construct_it(char_ptr_holder_t name)
{ return mp_header->find_or_construct_it<T>(name); }
/*!Creates a named array from iterators in memory
Allocates and constructs an array of T in memory,
associates this with the given name and returns a pointer to the
created object. Each element in the array is created using the
objects returned when dereferencing iterators as parameters
and incrementing all iterators for each element.
-> If the name was previously used, returns 0.
-> If there is no available memory, returns 0.
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and
destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template construct_iter_proxy<T, false>::type
construct_it(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->construct_it<T>(name, nothrow); }
/*!Finds or creates a named array from iterators in memory
Tries to find an object with the given name in memory. If
found, returns the pointer to this pointer. If the object is not found,
allocates and constructs an array of T in memory,
associates this with the given name and returns a pointer to the
created object. Each element in the array is created using the
objects returned when dereferencing iterators as parameters
and incrementing all iterators for each element.
-> If the name was previously used, returns 0.
-> If there is no available memory, returns 0.
-> If T's constructor throws, the function throws that exception.
Memory is freed automatically if T's constructor throws and
destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template find_construct_iter_proxy<T, false>::type
find_or_construct_it(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->find_or_construct_it<T>(name, nothrow); }
/*!Calls a functor and guarantees that no new construction, search or
destruction will be executed by any process while executing the object
function call. If the functor throws, this function throws.*/
template <class Func>
void atomic_func(Func &f)
{ mp_header->atomic_func(f); }
/*!Destroys a named memory object or array.
Finds the object with the given name, calls its destructors,
frees used memory and returns true.
-> If the object is not found, it returns false.
Exception Handling:
When deleting a dynamically object or array, the Standard
does not guarantee that dynamically allocated memory, will be released.
Also, when deleting arrays, the Standard doesn't require calling
destructors for the rest of the objects if for one of them the destructor
terminated with an exception.
Destroying an object:
If the destructor throws, the memory will be freed and that exception
will be thrown.
Destroying an array:
When destroying an array, if a destructor throws, the rest of
destructors are called. If any of these throws, the exceptions are
ignored. The name association will be erased, memory will be freed and
the first exception will be thrown. This guarantees the unlocking of
mutexes and other resources.
For all theses reasons, classes with throwing destructors are not
recommended.*/
template <class T>
bool destroy(const CharType *name)
{ return mp_header->destroy<T>(name); }
/*!Destroys the unique instance of type T
Calls the destructor, frees used memory and returns true.
Exception Handling:
When deleting a dynamically object, the Standard does not
guarantee that dynamically allocated memory will be released.
Destroying an object:
If the destructor throws, the memory will be freed and that exception
will be thrown.
For all theses reasons, classes with throwing destructors are not
recommended for memory.*/
template <class T>
bool destroy(const detail::unique_instance_t *const )
{ return mp_header->destroy<T>(unique_instance); }
/*!Destroys the object (named, unique, or anonymous)
Calls the destructor, frees used memory and returns true.
Exception Handling:
When deleting a dynamically object, the Standard does not
guarantee that dynamically allocated memory will be released.
Destroying an object:
If the destructor throws, the memory will be freed and that exception
will be thrown.
For all theses reasons, classes with throwing destructors are not
recommended for memory.*/
template <class T>
bool destroy_ptr(const T *ptr)
{ return mp_header->destroy_ptr<T>(ptr); }
/*!Returns the name of an object created with construct/find_or_construct
functions. Does not throw*/
template<class T>
const char *get_name(const T *ptr)
{ return mp_header->get_name(ptr); }
/*!Returns is the the name of an object created with construct/find_or_construct
functions. Does not throw*/
template<class T>
InstanceType get_type(const T *ptr)
{ return mp_header->get_type(ptr); }
/*!Preallocates needed index resources to optimize the
creation of "num" named objects in the memory segment.
Can throw boost::interprocess::bad_alloc if there is no enough memory.*/
void reserve_named_objects(std::size_t num)
{ mp_header->reserve_named_objects(num); }
/*!Preallocates needed index resources to optimize the
creation of "num" unique objects in the memory segment.
Can throw boost::interprocess::bad_alloc if there is no enough memory.*/
void reserve_unique_objects(std::size_t num)
{ mp_header->reserve_unique_objects(num); }
/*!Saves memory to a file. Never throws.*/
template<class CharT>
bool save_to_file (const CharT *filename)
{
//Open output file
std::basic_ofstream< CharT, std::char_traits<CharT> >
file(filename, std::ios::binary);
//Check and save
return file.is_open() && save_to_ostream (file);
}
/*!Saves memory to a std::ostream. Never throws.*/
bool save_to_ostream (std::ostream &outstream)
{
return outstream.write(char_ptr_cast(mp_header),
(std::streamsize)get_size()).good();
}
protected:
/*!Sets the base address of the memory in this process.
This is very low level, so use it only if you know what are
you doing. Never throws.*/
void set_base (void *addr)
{
assert(addr);
mp_header = static_cast<segment_manager*>(addr);
}
private:
segment_manager *mp_header;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP

View File

@@ -0,0 +1,46 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MULTI_SEGMENT_SERVICES_HPP
#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
/*!\file
Describes a named shared memory allocation user class.
*/
namespace boost {
namespace interprocess {
class multi_segment_services
{
public:
virtual std::pair<void *, std::size_t> create_new_segment(std::size_t mem) = 0;
virtual bool update_segments () = 0;
virtual ~multi_segment_services() = 0;
};
inline multi_segment_services::~multi_segment_services()
{}
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP

View File

@@ -0,0 +1,252 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NAMED_PROXY_HPP
#define BOOST_INTERPROCESS_NAMED_PROXY_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 <new>
#include <boost/config.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/bind.hpp>
/*!\file
Describes a proxy class that implements named allocation syntax.
*/
namespace boost { namespace interprocess {
namespace detail {
/*!Function object that makes placement new without arguments*/
template<class T>
struct Ctor0Arg
{
typedef Ctor0Arg self_t;
typedef T target_t;
enum { is_trivial = boost::has_trivial_constructor<T>::value };
Ctor0Arg(){}
self_t& operator++() { return *this; }
self_t operator++(int) { return *this; }
static inline void construct(T *mem, boost::mpl::false_)
{ new(mem)T; }
static inline void construct(T *mem, boost::mpl::true_)
{}
void operator()(T *mem) const
{
typedef boost::mpl::bool_<is_trivial> Result;
Ctor0Arg<T>::construct(mem, Result());
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
private:
char dummy_; // BCB would by default use 8 B for empty structure
#endif
};
#ifndef BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS
# define BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS 10
#endif
////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2):
//
// template<class T, bool param_or_it, class P1, class P2>
// struct Ctor2Arg
// {
// enum { is_trivial = false };
// typedef Ctor2Arg self_t;
//
// void do_increment(boost::mpl::false_)
// { ++m_p1; ++m_p2; }
//
// void do_increment(boost::mpl::true_){}
//
// self_t& operator++()
// {
// typedef boost::mpl::bool_<param_or_it> Result;
// this->do_increment(Result());
// return *this;
// }
//
// self_t operator++(int) { return ++*this; *this; }
//
// Ctor2Arg(const P1 &p1, const P2 &p2)
// : p1((P1 &)p_1), p2((P2 &)p_2) {}
//
// void operator()(T* mem) const
// { new (mem) T(m_p1, m_p2); }
// private:
// P1 &m_p1; P2 &m_p2;
// };
////////////////////////////////////////////////////////////////
//Note:
//We define template parameters as const references to
//be able to bind temporaries. After that we will un-const them.
//This cast is ugly but it is necessary until "perfect forwarding"
//is achieved in C++0x. Meanwhile, if we want to be able to
//bind rvalues with non-const references, we have to be ugly
#define BOOST_INTERPROCESS_AUX_PARAM_LIST(z, n, data) \
const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \
/**/
#define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \
/**/
#define BOOST_INTERPROCESS_AUX_PARAM_INC(z, n, data) \
BOOST_PP_CAT(++m_p, n) \
/**/
#define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
/**/
#define BOOST_PP_LOCAL_MACRO(n) \
template<class T, bool param_or_it, BOOST_PP_ENUM_PARAMS(n, class P) >\
struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
{ \
enum { is_trivial = false }; \
typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) self_t; \
typedef T target_t; \
\
void do_increment(boost::mpl::false_) \
{ BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INC, _); } \
\
void do_increment(boost::mpl::true_){} \
\
self_t& operator++() \
{ \
typedef boost::mpl::bool_<param_or_it> Result; \
this->do_increment(Result()); \
return *this; \
} \
\
self_t operator++(int) { return ++*this; *this; } \
\
BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_LIST, _) ) \
: BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INIT, _) {} \
\
void operator()(T* mem) const \
{ new (mem) T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \
\
private: \
BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \
}; \
/**/
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
#undef BOOST_INTERPROCESS_AUX_PARAM_LIST
#undef BOOST_INTERPROCESS_AUX_PARAM_INIT
#undef BOOST_INTERPROCESS_AUX_PARAM_DEFINE
#undef BOOST_INTERPROCESS_AUX_PARAM_INC
/*!Describes a proxy class that implements named allocation syntax.
*/
template
< class CharType //char type for the name (char, wchar_t...)
, class T //type of object to build
, class NamedAlloc //class to allocate and construct the object
, bool find //if true, we try to find the object before creating
, bool dothrow //if true, we throw an exception, otherwise, return 0
, bool param_or_it //passing parameters are normal object or iterators?
>
class named_proxy
{
const CharType * mp_name;
NamedAlloc * mp_alloc;
mutable std::size_t m_num;
public:
named_proxy(const CharType *name, NamedAlloc *alloc)
: mp_name(name), mp_alloc(alloc), m_num(1){}
/*!makes a named allocation and calls the default constructor*/
T *operator()() const
{
Ctor0Arg<T> ctor_obj;
return mp_alloc->template
generic_construct<T>(mp_name, m_num, find, dothrow, ctor_obj);
}
/**/
// Boost preprocessor used to create operator() overloads
#define BOOST_INTERPROCESS_AUX_TYPE_LIST(z, n, data) \
BOOST_PP_CAT(P, n) \
/**/
#define BOOST_INTERPROCESS_AUX_PARAM_LIST(z, n, data) \
const BOOST_PP_CAT(P, n) BOOST_PP_CAT(&p, n) \
/**/
#define BOOST_PP_LOCAL_MACRO(n) \
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_AUX_PARAM_LIST, _)) const \
{ \
typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
<T, param_or_it, BOOST_PP_ENUM (n, BOOST_INTERPROCESS_AUX_TYPE_LIST, _)> \
ctor_obj_t; \
ctor_obj_t ctor_obj (BOOST_PP_ENUM_PARAMS(n, p)); \
return mp_alloc->template generic_construct<T> \
(mp_name, m_num, find, dothrow, ctor_obj); \
} \
/**/
#define BOOST_PP_LOCAL_LIMITS ( 1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS )
#include BOOST_PP_LOCAL_ITERATE()
#undef BOOST_INTERPROCESS_AUX_PARAM_LIST
#undef BOOST_INTERPROCESS_AUX_TYPE_LIST
////////////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2)
////////////////////////////////////////////////////////////////////////
//
// template <class P1, class P2>
// T *operator()(P1 &p1, P2 &p2) const
// {
// typedef Ctor2Arg
// <T, param_or_it, P1, P2>
// ctor_obj_t;
// ctor_obj_t ctor_obj(p1, p2);
//
// return mp_alloc->template generic_construct<T>
// (mp_name, m_num, find, dothrow, ctor_obj);
// }
//
//////////////////////////////////////////////////////////////////////////
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
}}} //namespace boost { namespace interprocess { namespace detail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP

View File

@@ -0,0 +1,34 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_DETAIL_NULL_CREATION_FUNCTOR_HPP
#define BOOST_INTERPROCESS_DETAIL_NULL_CREATION_FUNCTOR_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
namespace detail{
/*!No-op functor*/
struct null_func_t
{
bool operator()(const segment_info_t *, bool) const
{ return true; }
};
} //namespace detail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_NULL_CREATION_FUNCTOR_HPP

View File

@@ -0,0 +1,337 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_DETAIL_OS_FILE_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <unistd.h>
# else
# error Unknown platform
# endif
#endif
#include <string.h>
namespace boost {
namespace interprocess {
namespace detail{
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef void * OS_file_handle_t;
inline OS_file_handle_t create_new_file(const char *name)
{
return winapi::create_file
(name, winapi::generic_read | winapi::generic_write, winapi::create_new);
}
inline OS_file_handle_t open_existing_file(const char *name)
{
return winapi::create_file
(name, winapi::generic_read | winapi::generic_write, winapi::open_existing);
}
inline bool truncate_file (OS_file_handle_t hnd, std::size_t size)
{
if(!winapi::set_file_pointer_ex(hnd, size, 0, winapi::file_begin)){
return false;
}
if(!winapi::set_end_of_file(hnd)){
return false;
}
return true;
}
inline OS_file_handle_t invalid_file()
{ return winapi::invalid_handle_value; }
inline bool close_file(OS_file_handle_t hnd)
{ return 0 != winapi::close_handle(hnd); }
inline bool acquire_file_lock(OS_file_handle_t hnd)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
memset(&overlapped, 0, sizeof(overlapped));
return winapi::lock_file_ex
(hnd, winapi::lockfile_exclusive_lock, 0, len, len, &overlapped);
}
inline bool try_acquire_file_lock(OS_file_handle_t hnd, bool &acquired)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
memset(&overlapped, 0, sizeof(overlapped));
if(!winapi::lock_file_ex
(hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately,
0, len, len, &overlapped)){
return winapi::get_last_error() == winapi::error_lock_violation ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool timed_acquire_file_lock
(OS_file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
{
//Obtain current count and target time
boost::posix_time::ptime now =
boost::posix_time::microsec_clock::universal_time();
using namespace boost::detail;
if(now >= abs_time) return false;
do{
if(!try_acquire_file_lock(hnd, acquired))
return false;
if(acquired)
return true;
else{
now = boost::posix_time::microsec_clock::universal_time();
if(now >= abs_time){
acquired = false;
return true;
}
// relinquish current time slice
winapi::sched_yield();
}
}while (true);
}
inline bool release_file_lock(OS_file_handle_t hnd)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
memset(&overlapped, 0, sizeof(overlapped));
return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped);
}
inline bool acquire_file_lock_sharable(OS_file_handle_t hnd)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
memset(&overlapped, 0, sizeof(overlapped));
return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped);
}
inline bool try_acquire_file_lock_sharable(OS_file_handle_t hnd, bool &acquired)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
memset(&overlapped, 0, sizeof(overlapped));
if(!winapi::lock_file_ex
(hnd, winapi::lockfile_fail_immediately, 0, len, len, &overlapped)){
return winapi::get_last_error() == winapi::error_lock_violation ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool timed_acquire_file_lock_sharable
(OS_file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
{
//Obtain current count and target time
boost::posix_time::ptime now =
boost::posix_time::microsec_clock::universal_time();
using namespace boost::detail;
if(now >= abs_time) return false;
do{
if(!try_acquire_file_lock_sharable(hnd, acquired))
return false;
if(acquired)
return true;
else{
now = boost::posix_time::microsec_clock::universal_time();
if(now >= abs_time){
acquired = false;
return true;
}
// relinquish current time slice
winapi::sched_yield();
}
}while (true);
}
inline bool release_file_lock_sharable(OS_file_handle_t hnd)
{ return release_file_lock(hnd); }
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef int OS_file_handle_t;
inline OS_file_handle_t create_new_file(const char *name)
{
::mode_t mode = S_IRWXG | S_IRWXO | S_IRWXU;
return ::open(name, O_RDWR | O_EXCL | O_CREAT, mode);
}
inline OS_file_handle_t open_existing_file(const char *name)
{
::mode_t mode = S_IRWXG | S_IRWXO | S_IRWXU;
return ::open(name, O_RDWR, mode);
}
inline bool truncate_file (OS_file_handle_t hnd, std::size_t size)
{ return 0 == ::ftruncate(hnd, size); }
inline OS_file_handle_t invalid_file()
{ return -1; }
inline bool close_file(OS_file_handle_t hnd)
{ return ::close(hnd) == 0; }
inline bool acquire_file_lock(OS_file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLKW, &lock);
}
inline bool try_acquire_file_lock(OS_file_handle_t hnd, bool &acquired)
{
struct ::flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
int ret = ::fcntl(hnd, F_SETLK, &lock);
if(ret == -1){
return (errno != EAGAIN && errno != EACCES) ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool timed_acquire_file_lock
(OS_file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
{
//Obtain current count and target time
boost::posix_time::ptime now =
boost::posix_time::microsec_clock::universal_time();
using namespace boost::detail;
if(now >= abs_time) return false;
do{
if(!try_acquire_file_lock(hnd, acquired))
return false;
if(acquired)
return true;
else{
now = boost::posix_time::microsec_clock::universal_time();
if(now >= abs_time){
acquired = false;
return true;
}
// relinquish current time slice
sleep(0);
}
}while (true);
}
inline bool release_file_lock(OS_file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLK, &lock);
}
inline bool acquire_file_lock_sharable(OS_file_handle_t hnd)
{
struct ::flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
return -1 != ::fcntl(hnd, F_SETLKW, &lock);
}
inline bool try_acquire_file_lock_sharable(OS_file_handle_t hnd, bool &acquired)
{
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
int ret = ::fcntl(hnd, F_SETLK, &lock);
if(ret == -1){
return (errno != EAGAIN && errno != EACCES) ?
acquired = false, true : false;
}
return (acquired = true);
}
inline bool timed_acquire_file_lock_sharable
(OS_file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
{
//Obtain current count and target time
boost::posix_time::ptime now =
boost::posix_time::microsec_clock::universal_time();
using namespace boost::detail;
if(now >= abs_time) return false;
do{
if(!try_acquire_file_lock_sharable(hnd, acquired))
return false;
if(acquired)
return true;
else{
now = boost::posix_time::microsec_clock::universal_time();
if(now >= abs_time){
acquired = false;
return true;
}
// relinquish current time slice
::sleep(0);
}
}while (true);
}
inline bool release_file_lock_sharable(OS_file_handle_t hnd)
{ return release_file_lock(hnd); }
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
} //namespace detail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP

View File

@@ -0,0 +1,543 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_DETAIL_UTILITIES_HPP
#define BOOST_INTERPROCESS_DETAIL_UTILITIES_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/get_pointer.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/type_traits/has_nothrow_destructor.hpp>
#include <boost/noncopyable.hpp>
#include <boost/call_traits.hpp>
#include <algorithm>
#include <functional>
#include <utility>
#include <stdexcept>
#include <boost/iterator/iterator_facade.hpp>
namespace boost { namespace interprocess {
template<class T>
class offset_ptr;
namespace detail {
/*!Overload for smart pointers to avoid ADL problems with get_pointer*/
template<class Ptr>
inline typename Ptr::value_type *get_pointer(const Ptr &ptr)
{ using boost::get_pointer; return get_pointer(ptr); }
/*!Overload for raw pointers to avoid ADL problems with get_pointer*/
template<class T>
inline T *get_pointer(T *ptr)
{ return ptr; }
/*!To avoid ADL problems with swap*/
template <class T>
inline void do_swap(T& x, T& y)
{
using std::swap;
swap(x, y);
}
/*!A deleter for scoped_ptr that deallocates the memory
allocated for an object using a STL allocator.*/
template <class Allocator>
struct scoped_deallocator
{
typedef typename Allocator::pointer pointer;
Allocator& m_alloc;
scoped_deallocator(Allocator& a)
: m_alloc(a) {}
void operator()(pointer ptr)
{ if (ptr) m_alloc.deallocate(ptr, 1); }
};
/*!A deleter for scoped_ptr that deallocates the memory
allocated for an array of objects using a STL allocator.*/
template <class Allocator>
struct scoped_array_deallocator
{
typedef typename Allocator::pointer pointer;
scoped_array_deallocator(Allocator& a, std::size_t length)
: m_alloc(a), m_length(length) {}
void operator()(pointer &ptr)
{ m_alloc.deallocate(ptr, m_length); }
private:
Allocator& m_alloc;
std::size_t m_length;
};
/*!A deleter for scoped_ptr that destroys
an object using a STL allocator.*/
template <class Allocator>
struct scoped_destructor
{
typedef typename Allocator::pointer pointer;
Allocator& m_alloc;
scoped_destructor(Allocator& a)
: m_alloc(a){}
void operator()(pointer &ptr)
{ m_alloc.destroy(ptr); }
};
/*!A deleter for scoped_ptr that destroys
an object using a STL allocator.*/
template <class Allocator>
struct scoped_destructor_n
{
typedef typename Allocator::pointer pointer;
typedef typename Allocator::size_type size_type;
Allocator& m_alloc;
size_type m_n;
scoped_destructor_n(Allocator& a, size_type n)
: m_alloc(a), m_n(n){}
void operator()(pointer &ptr)
{
for(size_type i = 0; i < m_n; ++i, ++ptr)
m_alloc.destroy(ptr);
}
};
/*!Forces a cast from any pointer to char * pointer*/
template<class T>
inline char* char_ptr_cast(T *ptr)
{
//This is nasty, but we like it a lot!
return (char*)(ptr);
}
inline char* char_ptr_cast()
{
//This is nasty, but we like it a lot!
return (char*)(0);
}
template <class Pair>
struct select1st
: public std::unary_function<Pair, typename Pair::first_type>
{
const typename Pair::first_type& operator()(const Pair& x) const
{ return x.first; }
};
// identity is an extension: it is not part of the standard.
template <class T>
struct identity
: public std::unary_function<T,T>
{
const T& operator()(const T& x) const
{ return x; }
};
//Rounds "orig_size" by excess to round_to bytes
inline std::size_t get_rounded_size(std::size_t orig_size, std::size_t round_to)
{
return ((orig_size-1)/round_to+1)*round_to;
}
template <std::size_t OrigSize, std::size_t RoundTo>
struct ct_rounded_size
{
enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo };
};
/*!Obtains a generic pointer of the same type that
can point to other pointed type: Ptr<?> -> Ptr<NewValueType>*/
template<class T, class U>
struct pointer_to_other;
template<class T, class U,
template<class> class Sp>
struct pointer_to_other< Sp<T>, U >
{
typedef Sp<U> type;
};
template<class T, class T2, class U,
template<class, class> class Sp>
struct pointer_to_other< Sp<T, T2>, U >
{
typedef Sp<U, T2> type;
};
template<class T, class T2, class T3, class U,
template<class, class, class> class Sp>
struct pointer_to_other< Sp<T, T2, T3>, U >
{
typedef Sp<U, T2, T3> type;
};
template<class T, class U>
struct pointer_to_other< T*, U >
{
typedef U* type;
};
//Anti-exception node eraser
template<class Cont>
class value_eraser : boost::noncopyable
{
public:
value_eraser(Cont & cont, typename Cont::iterator it)
: m_map(cont), m_index_it(it), m_erase(true){}
~value_eraser()
{
if(boost::has_nothrow_destructor<typename Cont::value_type>::value){
if(m_erase) m_map.erase(m_index_it);
}
else{
//value_eraser is used in exceptions, so we
//disable double-exception danger
BOOST_TRY{ if(m_erase) m_map.erase(m_index_it); }
BOOST_CATCH(...){}
BOOST_CATCH_END
}
}
void release() { m_erase = false; }
private:
Cont &m_map;
typename Cont::iterator m_index_it;
bool m_erase;
};
} //namespace detail {
/*!Trait class to detect if an allocator has
a templatized construct function. If this is the case
in node containers we only need just one allocator
instead of three*/
template <class Allocator>
struct has_convertible_construct
{
enum { value = false };
};
/*!Trait classes to detect if an index is a node
index. This allows more efficient operations
when deallocating named objects.*/
template <class Index>
struct is_node_index
{
enum { value = false };
};
/*!Trait class to detect if an smart pointer has
multi-segment addressing capabilities.*/
template <class Ptr>
struct is_multisegment_ptr
{
enum { value = false };
};
/*!A Interprocess shared pointer deleter that uses the segment manager's
destroy_ptr function to destroy the shared resource.*/
template<class T, class SegmentManager>
class deleter
{
public:
typedef typename detail::pointer_to_other
<typename SegmentManager::void_pointer, T>::type pointer;
private:
typedef typename detail::pointer_to_other
<pointer, SegmentManager>::type segment_manager_pointer;
segment_manager_pointer mp_deleter;
public:
deleter(const segment_manager_pointer &pdeleter)
: mp_deleter(pdeleter)
{}
void operator()(const pointer &p)
{ mp_deleter->destroy_ptr(detail::get_pointer(p)); }
};
template <class T, class Difference = std::ptrdiff_t>
class constant_iterator
: public boost::iterator_facade
< constant_iterator<T, Difference>
, T
, boost::random_access_traversal_tag
, const T &
, Difference>
{
typedef boost::iterator_facade
< constant_iterator<T, Difference>
, T
, boost::random_access_traversal_tag
, const T &
, Difference> super_t;
typedef constant_iterator<T, Difference> this_type;
//Give access to private core functions
friend class boost::iterator_core_access;
public:
explicit constant_iterator(const T &ref, Difference range_size)
: m_ptr(&ref), m_num(range_size){}
//Constructors
constant_iterator()
: m_ptr(0), m_num(0){}
private:
const T * m_ptr;
Difference m_num;
void increment()
{ --m_num; }
void decrement()
{ ++m_num; }
bool equal(const this_type &other) const
{ return m_num == other.m_num; }
const T & dereference() const
{ return *m_ptr; }
void advance(Difference n)
{ m_num -= n; }
Difference distance_to(const this_type &other)const
{ return m_num - other.m_num; }
};
template<class FwdIt, class Count, class T, class Alloc> inline
void uninitialized_fill_n(FwdIt first, Count count,
const T& val, Alloc& al)
{
//Save initial position
FwdIt init = first;
BOOST_TRY{
//Construct objects
for (; count--; ++first){
al.construct(first, val);
}
}
BOOST_CATCH(...){
//Call destructors
for (; init != first; ++init){
al.destroy(init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
}
template<class InIt, class OutIt>
InIt copy_n(InIt first, typename std::iterator_traits<InIt>::difference_type length, OutIt dest)
{
for (; length--; ++dest, ++first)
*dest = *first;
return first;
}
template<class InIt, class FwdIt, class Alloc> inline
typename std::iterator_traits<InIt>::difference_type
n_uninitialized_copy(InIt first, InIt last,
FwdIt dest, Alloc& al)
{
//Save initial destination position
FwdIt dest_init = dest;
typename std::iterator_traits<InIt>::difference_type constructed = 0;
BOOST_TRY{
//Try to build objects
for (; first != last; ++dest, ++first, ++constructed){
al.construct(dest, *first);
}
}
BOOST_CATCH(...){
//Call destructors
for (; dest_init != dest; ++dest_init){
al.destroy(dest_init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return (constructed);
}
template<class InIt, class FwdIt, class Alloc> inline
FwdIt
uninitialized_copy(InIt first, InIt last,
FwdIt dest, Alloc& al)
{
//Save initial destination position
FwdIt dest_init = dest;
typename std::iterator_traits<InIt>::difference_type constructed = 0;
BOOST_TRY{
//Try to build objects
for (; first != last; ++dest, ++first, ++constructed){
al.construct(dest, *first);
}
}
BOOST_CATCH(...){
//Call destructors
for (; dest_init != dest; ++dest_init){
al.destroy(dest_init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return (dest);
}
template<class InIt, class FwdIt, class Alloc> inline
InIt n_uninitialized_copy_n
(InIt first,
typename std::iterator_traits<InIt>::difference_type count,
FwdIt dest, Alloc& al)
{
//Save initial destination position
FwdIt dest_init = dest;
typename std::iterator_traits<InIt>::difference_type new_count = count+1;
BOOST_TRY{
//Try to build objects
for (; --new_count; ++dest, ++first){
al.construct(dest, *first);
}
}
BOOST_CATCH(...){
//Call destructors
new_count = count - new_count;
for (; new_count--; ++dest_init){
al.destroy(dest_init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return first;
}
// uninitialized_copy_copy
// Copies [first1, last1) into [result, result + (last1 - first1)), and
// copies [first2, last2) into
// [result + (last1 - first1), result + (last1 - first1) + (last2 - first2)).
template <class InpIt1, class InpIt2, class FwdIt, class Alloc>
FwdIt uninitialized_copy_copy(InpIt1 first1, InpIt1 last1,
InpIt2 first2, InpIt2 last2,
FwdIt result, Alloc &alloc)
{
FwdIt mid = uninitialized_copy(first1, last1, result, alloc);
BOOST_TRY {
return uninitialized_copy(first2, last2, mid, alloc);
}
BOOST_CATCH(...){
for(;result != mid; ++result){
alloc.destroy(&*result);
}
BOOST_RETHROW
}
BOOST_CATCH_END
}
// uninitialized_copy_n_copy_n
// Copies [first1, first1 + n1) into [result, result + n1), and
// copies [first2, first2 + n2) into
// [result + n1, result + n1 + n2).
template <class InpIt1, class InpIt2, class FwdIt, class Alloc>
InpIt2 uninitialized_copy_n_copy_n
(InpIt1 first1,
typename std::iterator_traits<InpIt1>::difference_type n1,
InpIt2 first2,
typename std::iterator_traits<InpIt2>::difference_type n2,
FwdIt result,
Alloc &alloc)
{
typename std::iterator_traits<InpIt1>::difference_type c1 = n1+1;
typename std::iterator_traits<InpIt2>::difference_type c2 = n2+1;
FwdIt dest_init = result;
BOOST_TRY{
//Try to build objects
for (; --c1; ++result, ++first1){
alloc.construct(result, *first1);
}
for (; --c2; ++result, ++first2){
alloc.construct(result, *first2);
}
}
BOOST_CATCH(...){
//Call destructors
typename std::iterator_traits<FwdIt>::
difference_type c = (n1 - c1) + (n2 - c2);
for (; c--; ++dest_init){
alloc.destroy(dest_init);
}
BOOST_RETHROW;
}
BOOST_CATCH_END
return first2;
}
template<class T>
T max_value(const T &a, const T &b)
{ return a > b ? a : b; }
template<class T>
T min_value(const T &a, const T &b)
{ return a < b ? a : b; }
template <class SizeType>
SizeType
get_next_capacity(const SizeType max_size
,const SizeType capacity
,const SizeType n)
{/*
if (n > max_size - capacity)
throw std::length_error("get_next_capacity");
*/
const SizeType m3 = max_size/3;
if (capacity < m3)
return capacity + max_value(3*(capacity+1)/5, n);
if (capacity < m3*2)
return capacity + max_value((capacity+1)/2, n);
return max_size;
}
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP

View File

@@ -0,0 +1,137 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This code comes from N1953 document by Howard E. Hinnant
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP
#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP
/*
#include <boost/type_traits/integral_constant.hpp>
namespace boost{
namespace interprocess{
namespace detail{
template <class T, unsigned V>
struct version_type
: public boost::integral_constant<unsigned, V>
{
typedef T type;
version_type(const version_type<T, 0>&);
};
template <class T>
struct version
: public boost::integral_constant<unsigned, 1>
{};
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
*/
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost{
namespace interprocess{
namespace detail{
//using namespace boost;
template <class T, unsigned V>
struct version_type
: public boost::integral_constant<unsigned, V>
{
typedef T type;
version_type(const version_type<T, 0>&);
};
namespace impl{
template <class T,
bool = boost::is_convertible<version_type<T, 0>, typename T::version>::value>
struct extract_version
{
static const unsigned value = 1;
};
template <class T>
struct extract_version<T, true>
{
static const unsigned value = T::version::value;
};
template <class T>
struct has_version
{
private:
struct two {char _[2];};
template <class U> static two test(...);
template <class U> static char test(typename U::version*);
public:
static const bool value = sizeof(test<T>(0)) == 1;
};
template <class T, bool = has_version<T>::value>
struct version
{
static const unsigned value = 1;
};
template <class T>
struct version<T, true>
{
static const unsigned value = extract_version<T>::value;
};
} //namespace impl
template <class T>
struct version
: public boost::integral_constant<unsigned, impl::version<T>::value>
{
};
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
/*
#include <iostream>
#include <boost/interprocess/detail/version_type.hpp>
struct A
{
typedef boost::interprocess::detail::version_type<A, 2> version;
};
struct B
{
struct version {static unsigned const value = 3;};
};
int main()
{
boost::interprocess::detail::
std::cout << boost::interprocess::detail::version<int>::value << '\n';
std::cout << boost::interprocess::detail::version<A>::value << '\n';
std::cout << boost::interprocess::detail::version<B>::value << '\n';
}
*/
#endif //#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP

View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_PTR_WRKRND_HPP
#define BOOST_INTERPROCESS_PTR_WRKRND_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#ifndef BOOST_INTERPROCESS_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
#if defined (BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS) || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
#define BOOST_INTERPROCESS_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS
#endif
#endif
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
// old Dinkumware
# include <boost/compatibility/cpp_c_headers/cstddef>
#else
# include <cstddef>
#endif
#if !((defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)) && \
((defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || \
defined(_XOPEN_VERSION) && _XOPEN_VERSION >= 500)
#define BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
#endif
namespace boost {
namespace interprocess {
namespace workaround
{
//-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*//
// //
// We want generally const_shm_ptr to inherit//
// from iterator class but for void this //
// doesn't work, so we must inherit from //
// other class. //
// //
//-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*//
//Empty class
struct empty_type{};
template<class T>
struct random_it
: public boost::iterator<std::random_access_iterator_tag,
T, std::ptrdiff_t, T*, T&>
{
typedef const T* const_pointer;
typedef const T& const_reference;
};
template<> struct random_it<void>
{
typedef void * pointer;
typedef const void * const_pointer;
typedef empty_type& reference;
typedef const empty_type& const_reference;
typedef void value_type;
typedef empty_type difference_type;
typedef empty_type iterator_category;
};
template<> struct random_it<const void>
{
typedef const void * pointer;
typedef const void * const_pointer;
typedef const empty_type & reference;
typedef const empty_type & const_reference;
typedef const void value_type;
typedef empty_type difference_type;
typedef empty_type iterator_category;
};
template<> struct random_it<volatile void>
{
typedef volatile void * pointer;
typedef const volatile void * const_pointer;
typedef empty_type& reference;
typedef const empty_type& const_reference;
typedef volatile void value_type;
typedef empty_type difference_type;
typedef empty_type iterator_category;
};
template<> struct random_it<const volatile void>
{
typedef const volatile void * pointer;
typedef const volatile void * const_pointer;
typedef const empty_type & reference;
typedef const empty_type & const_reference;
typedef const volatile void value_type;
typedef empty_type difference_type;
typedef empty_type iterator_category;
};
} //namespace workaround
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PTR_WRKRND_HPP

View File

@@ -0,0 +1,228 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
// Parts of this code are taken from boost::filesystem library
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 2002 Beman Dawes
// Copyright © 2001 Dietmar Kühl
// Use, modification, and distribution is subject to 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 library home page at http://www.boost.org/libs/filesystem
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ERRORS_HPP
#define BOOST_INTERPROCESS_ERRORS_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 <stdarg.h>
#include <string>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <errno.h> //Errors
# else //ifdef BOOST_HAS_UNISTD_H
# error Unknown platform
# endif //ifdef BOOST_HAS_UNISTD_H
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes the error numbering of interprocess classes
*/
namespace boost {
namespace interprocess {
static inline int system_error_code() // artifact of POSIX and WINDOWS error reporting
{
#ifdef BOOST_WINDOWS
return winapi::get_last_error();
#else
return errno; // GCC 3.1 won't accept ::errno
#endif
}
# ifdef BOOST_WINDOWS
void fill_system_message(int sys_err_code, std::string &str)
{
void *lpMsgBuf;
winapi::format_message(
winapi::format_message_allocate_buffer |
winapi::format_message_from_system |
winapi::format_message_ignore_inserts,
0,
sys_err_code,
winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language
(char *) &lpMsgBuf,
0,
0
);
str += static_cast<const char*>(lpMsgBuf);
winapi::local_free( lpMsgBuf ); // free the buffer
while ( str.size()
&& (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') )
str.erase( str.size()-1 );
}
# else
void fill_system_message( int system_error, std::string &str)
{ str = std::strerror(system_error); }
# endif
enum error_code_t
{
no_error = 0,
system_error, // system generated error; if possible, is translated
// to one of the more specific errors below.
other_error, // library generated error
security_error, // includes access rights, permissions failures
read_only_error,
io_error,
path_error,
not_found_error,
// not_directory_error,
busy_error, // implies trying again might succeed
already_exists_error,
not_empty_error,
is_directory_error,
out_of_space_error,
out_of_memory_error,
out_of_resource_error,
lock_error,
sem_error,
mode_error,
size_error,
bad_sharable_lock
};
typedef int native_error_t;
struct ec_xlate
{
native_error_t sys_ec;
error_code_t ec;
};
static const ec_xlate ec_table[] =
{
#ifdef BOOST_WINDOWS
{ /*ERROR_ACCESS_DENIED*/5L, security_error },
{ /*ERROR_INVALID_ACCESS*/12L, security_error },
{ /*ERROR_SHARING_VIOLATION*/32L, security_error },
{ /*ERROR_LOCK_VIOLATION*/33L, security_error },
{ /*ERROR_LOCKED*/212L, security_error },
{ /*ERROR_NOACCESS*/998L, security_error },
{ /*ERROR_WRITE_PROTECT*/19L, read_only_error },
{ /*ERROR_NOT_READY*/21L, io_error },
{ /*ERROR_SEEK*/25L, io_error },
{ /*ERROR_READ_FAULT*/30L, io_error },
{ /*ERROR_WRITE_FAULT*/29L, io_error },
{ /*ERROR_CANTOPEN*/1011L, io_error },
{ /*ERROR_CANTREAD*/1012L, io_error },
{ /*ERROR_CANTWRITE*/1013L, io_error },
{ /*ERROR_DIRECTORY*/267L, path_error },
{ /*ERROR_INVALID_NAME*/123L, path_error },
{ /*ERROR_FILE_NOT_FOUND*/2L, not_found_error },
{ /*ERROR_PATH_NOT_FOUND*/3L, not_found_error },
{ /*ERROR_DEV_NOT_EXIST*/55L, not_found_error },
{ /*ERROR_DEVICE_IN_USE*/2404L, busy_error },
{ /*ERROR_OPEN_FILES*/2401L, busy_error },
{ /*ERROR_BUSY_DRIVE*/142L, busy_error },
{ /*ERROR_BUSY*/170L, busy_error },
{ /*ERROR_FILE_EXISTS*/80L, already_exists_error },
{ /*ERROR_ALREADY_EXISTS*/183L, already_exists_error },
{ /*ERROR_DIR_NOT_EMPTY*/145L, not_empty_error },
{ /*ERROR_HANDLE_DISK_FULL*/39L, out_of_space_error },
{ /*ERROR_DISK_FULL*/112L, out_of_space_error },
{ /*ERROR_OUTOFMEMORY*/14L, out_of_memory_error },
{ /*ERROR_NOT_ENOUGH_MEMORY*/8L, out_of_memory_error },
{ /*ERROR_TOO_MANY_OPEN_FILES*/4L, out_of_resource_error }
#else //#ifdef BOOST_WINDOWS
{ EACCES, security_error },
{ EROFS, read_only_error },
{ EIO, io_error },
{ ENAMETOOLONG, path_error },
{ ENOENT, not_found_error },
// { ENOTDIR, not_directory_error },
{ EAGAIN, busy_error },
{ EBUSY, busy_error },
{ ETXTBSY, busy_error },
{ EEXIST, already_exists_error },
{ ENOTEMPTY, not_empty_error },
{ EISDIR, is_directory_error },
{ ENOSPC, out_of_space_error },
{ ENOMEM, out_of_memory_error },
{ EMFILE, out_of_resource_error }
#endif //#ifdef BOOST_WINDOWS
};
static inline error_code_t lookup_error(native_error_t err)
{
const ec_xlate *cur = &ec_table[0],
*end = cur + sizeof(ec_table)/sizeof(ec_xlate);
for (;cur != end; ++cur ){
if ( err == cur->sys_ec ) return cur->ec;
}
return system_error; // general system error code
}
struct error_info
{
error_info(error_code_t ec = other_error )
: m_nat(0), m_ec(ec)
{}
error_info(native_error_t sys_err_code)
: m_nat(sys_err_code), m_ec(lookup_error(sys_err_code))
{}
error_info & operator =(error_code_t ec)
{
m_nat = 0;
m_ec = ec;
return *this;
}
error_info & operator =(native_error_t sys_err_code)
{
m_nat = sys_err_code;
m_ec = lookup_error(sys_err_code);
return *this;
}
native_error_t get_native_error()const
{ return m_nat; }
error_code_t get_error_code()const
{ return m_ec; }
private:
native_error_t m_nat;
error_code_t m_ec;
};
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_ERRORS_HPP

View File

@@ -0,0 +1,142 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gazta<74>ga 2005-2006. 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_EXCEPTIONS_HPP
#define BOOST_INTERPROCESS_EXCEPTIONS_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/errors.hpp>
#include <stdexcept>
#include <new>
/*!\file
Describes exceptions thrown by interprocess classes
*/
namespace boost {
namespace interprocess {
/*!This class is the base class of all exceptions
thrown by boost::interprocess*/
class interprocess_exception : public std::exception
{
public:
interprocess_exception(error_code_t ec = other_error )
: m_err(ec)
{
try { m_str = "boost::interprocess_exception::library_error"; }
catch (...) {}
}
interprocess_exception(native_error_t sys_err_code)
: m_err(sys_err_code)
{
try { fill_system_message(m_err.get_native_error(), m_str); }
catch (...) {}
}
interprocess_exception(const error_info &err_info)
: m_err(err_info)
{
try{
if(m_err.get_native_error() != 0){
fill_system_message(m_err.get_native_error(), m_str);
}/*
else{
m_str = "boost::interprocess_exception::library_error";
}*/
}
catch(...){}
}
virtual ~interprocess_exception() throw(){}
virtual const char * what() const throw()
{ return m_str.c_str(); }
native_error_t get_native_error()const { return m_err.get_native_error(); }
// Note: a value of other_error implies a library (rather than system) error
error_code_t get_error_code() const { return m_err.get_error_code(); }
private:
error_info m_err;
std::string m_str;
};
/*!This is the exception thrown by shared interprocess_mutex family when a deadlock situation
is detected or when using a interprocess_condition the interprocess_mutex is not locked*/
class lock_exception : public interprocess_exception
{
public:
lock_exception()
: interprocess_exception(lock_error)
{}
virtual const char* what() const throw()
{ return "boost::interprocess::lock_exception"; }
};
/*!This is the exception thrown by named interprocess_semaphore when a deadlock situation
is detected or when an error is detected in the post/wait operation*/
/*
class sem_exception : public interprocess_exception
{
public:
sem_exception()
: interprocess_exception(lock_error)
{}
virtual const char* what() const throw()
{ return "boost::interprocess::sem_exception"; }
};
*/
/*!This is the exception thrown by synchronization objects when there is
an error in a wait() function*/
/*
class wait_exception : public interprocess_exception
{
public:
virtual const char* what() const throw()
{ return "boost::interprocess::wait_exception"; }
};
*/
/*!This exception is thrown when a named object is created
in "open_only" mode and the resource was not already created*/
/*
class not_previously_created : public interprocess_exception
{
public:
virtual const char* what() const throw()
{ return "boost::interprocess::not_previously_created"; }
};
*/
/*!This exception is thrown when a memory request can't be fulfilled.*/
class bad_alloc : public interprocess_exception
{
public:
virtual const char* what() const throw()
{ return "boost::interprocess::bad_alloc"; }
};
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_EXCEPTIONS_HPP

View File

@@ -0,0 +1,443 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_FULLY_MAPPED_FILE_HPP
#define BOOST_INTERPROCESS_FULLY_MAPPED_FILE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/global_lock.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <memory> //std::auto_ptr
#include <fstream> //std::fstream
#include <string> //std::string
#include <cstdio> //std::remove
//#include <unistd.h> //close
/*!\file
Describes mapped_file class
*/
namespace boost {
namespace interprocess {
/*!A class that wraps basic file-mapping management*/
class mapped_file : private boost::noncopyable
{
public:
class mapped_file_info_t
{
friend class shared_memory;
public:
mapped_file_info_t(void* addr, std::size_t size)
: m_addr(addr), m_size(size)
{}
/*!Returns pointer to the shared memory fragment
the user can overwrite*/
void * get_address() const;
/*!Returns the size of the shared memory fragment
the user can overwrite*/
std::size_t get_size()const;
private:
void* m_addr;
std::size_t m_size;
};
/*!No-op functor*/
struct null_func_t
{
bool operator()(const mapped_file_info_t *, bool) const
{ return true; }
};
/*!Creates a memory mapped file with name "name", and size "size".
If the file was previously created it throws an error.
The mapping can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user can also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
mapped_file(detail::create_only_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr = 0);
/*!Creates a memory mapped file with name "name", and size "size" if
the file was not previously created. If it was previously
created it tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user can also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
mapped_file(detail::open_only_t,
const char *name,
// file_mapping::accessmode_t mode,
const void *addr = 0);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created it tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user can specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
mapped_file(detail::open_or_create_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr = 0);
/*!Creates a shared memory segment with name "name", with size "size".
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user must specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes a copy of the functor "construct_func" atomically if
the segment is created. The functor must have the following signature:
bool operator()(const mapped_file_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
must be "true". If the functor returns "false", or throws an error
is supposed and the shared memory won't be created.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const mapped_file_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
mapped_file(detail::create_only_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user must specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes a copy of the functor "construct_func" atomically
if the segment is opened. The functor must have the following signature:
bool operator()(const mapped_file_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
must be "false". If the functor returns "false", or throws an error
is supposed and the shared memory won't be opened.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const mapped_file_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
mapped_file(detail::open_only_t,
const char *name,
// file_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created it tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user must specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes the functor "construct_func" atomically if the segment is
created or opened. The functor must have the following signature:
bool operator()(const mapped_file_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
will be "true" if the shared memory was created. If the functor
returns "false", or throws an error is supposed and the
shared memory won't be opened.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const mapped_file_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
mapped_file(detail::open_or_create_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Destructor. Unmaps the file from process' address space.
It also executes the destruction functor atomically if
the user has registered that the destruction functor
in the constructor of this class.
Never throws.*/
~mapped_file();
/*!Returns the size of the file mapping. Never throws.*/
std::size_t get_size() const;
/*!Returns the base address of the file mapping. Never throws.*/
void* get_address() const;
/*!Flushes to the disk a byte range within the mapped file.
Never throws*/
bool flush();
/*!Returns the name of the shared memory segment used in the
constructor. Never throws.*/
const char *get_name() const;
private:
enum type_t { DoCreate, DoOpen, DoCreateOrOpen };
template <class ConstructFunc>
bool
priv_open_or_create(type_t type,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr,
ConstructFunc construct_func);
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef void * OS_handle_t;
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef int OS_handle_t;
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
//Members
std::auto_ptr<mapped_region> mp_mapped_region;
std::string m_name;
};
inline void *mapped_file::mapped_file_info_t::get_address() const
{ return this->m_addr; }
inline std::size_t mapped_file::mapped_file_info_t::get_size() const
{ return this->m_size; }
inline
mapped_file::mapped_file
(detail::create_only_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr)
{
this->priv_open_or_create(DoCreate, name, size, /*mode, */addr, null_func_t());
}
inline
mapped_file::mapped_file
(detail::open_only_t,
const char *name,
// file_mapping::accessmode_t mode,
const void *addr)
{
this->priv_open_or_create(DoOpen, name, 0, /*mode, */addr, null_func_t());
}
inline
mapped_file::mapped_file
(detail::open_or_create_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr)
{
this->priv_open_or_create(DoCreateOrOpen, name, size, /*mode, */addr, null_func_t());
}
template <class ConstructFunc> inline
mapped_file::mapped_file(detail::create_only_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoCreate, name, size, /*mode, */addr, construct_func);
}
template <class ConstructFunc> inline
mapped_file::mapped_file(detail::open_only_t,
const char *name,
// file_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoOpen, name, 0, /*mode, */addr, construct_func);
}
template <class ConstructFunc> inline
mapped_file::mapped_file(detail::open_or_create_t,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoCreateOrOpen, name, size, /*mode, */addr, construct_func);
}
inline
mapped_file::~mapped_file()
{
}
std::size_t mapped_file::get_size() const
{ return mp_mapped_region->get_size(); }
void* mapped_file::get_address() const
{ return mp_mapped_region->get_address(); }
bool mapped_file::flush()
{ return mp_mapped_region->flush(); }
inline const char *mapped_file::get_name() const
{ return m_name.c_str(); }
template <class ConstructFunc> inline
bool
mapped_file::priv_open_or_create(mapped_file::type_t type,
const char *name,
std::size_t size,
// file_mapping::accessmode_t mode,
const void *addr,
ConstructFunc construct_func)
{
error_info err;
bool created = true;
m_name = name;
//This global interprocess_mutex guarantees synchronized creation/open logic
detail::global_lock mut;
if(!mut.acquire()){
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
boost::shared_ptr<file_mapping> p_mapped_file;
if(type == DoOpen){
//Open existing shared memory
created = false;
}
else if(type == DoCreateOrOpen || type == DoCreate){
OS_handle_t hnd = detail::create_new_file(name);
if(hnd != detail::invalid_file()){
if(!detail::close_file(hnd)){
err = system_error_code();
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
std::fstream file;
file.open(name, std::ios::binary | std::ios::out | std::ios::trunc);
file.seekp(static_cast<std::fstream::off_type>(size-1), std::ios::beg);
file.write("", 1);
if(!file.good()){
file.close();
std::remove(name);
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
}
else if(type == DoCreate){
err = system_error_code();
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
}
else{
throw interprocess_exception(err);
}
//Open file mapping
p_mapped_file.reset(new file_mapping(name, file_mapping::rw_mode/*mode*/));
mp_mapped_region.reset(new mapped_region
(p_mapped_file, 0, size, file_mapping::rw_mode/*mode */,addr));
//Execute atomic functor
mapped_file_info_t info(mp_mapped_region->get_address(), size);
construct_func(&info, created);
return true;
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_FULLY_MAPPED_FILE_HPP

View File

@@ -0,0 +1,71 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_FLAT_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
/*!\file
Describes index adaptor of boost::map container, to use it
as name/shared memory index
*/
namespace boost { namespace interprocess {
/*!Helper class to define typedefs from IndexTraits*/
template <class MapConfig>
struct flat_map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef typename MapConfig::segment_manager segment_manager;
typedef std::less<key_type> key_less;
typedef std::pair<key_type, mapped_type> value_type;
typedef allocator<value_type, segment_manager> allocator_type;
typedef flat_map<key_type, mapped_type,
key_less, allocator_type> index_t;
};
/*!Index type based in flat_map. Just derives from flat_map and
defines the interface needed by the shared named object creation class*/
template <class MapConfig>
class flat_map_index
//Derive class from map specialization
: public flat_map_index_aux<MapConfig>::index_t
{
typedef flat_map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename index_aux::segment_manager segment_manager;
public:
/*!Constructor. Takes a pointer to the
segment manager. Can throw*/
flat_map_index(segment_manager *segment_mngr)
: base_type(typename index_aux::key_less(),
typename index_aux::allocator_type(segment_mngr))
{}
/*!This reserves memory to optimize the insertion of n
elements in the index*/
void reserve(std::size_t n)
{ base_type::reserve(n); }
};
}} //namespace boost { namespace interprocess
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP

View File

@@ -0,0 +1,83 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/private_node_allocator.hpp>
/*!\file
Describes index adaptor of boost::map container, to use it
as name/shared memory index
*/
namespace boost { namespace interprocess {
/*!Helper class to define typedefs from IndexTraits*/
template <class MapConfig>
struct map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef std::less<key_type> key_less;
typedef std::pair<const key_type, mapped_type> value_type;
typedef private_node_allocator
<value_type,
64,
typename MapConfig::segment_manager> allocator_type;
typedef boost::interprocess::map<key_type, mapped_type,
key_less, allocator_type> index_t;
};
/*!Index type based in boost::interprocess::map. Just derives from boost::interprocess::map
and defines the interface needed by the shared named object creation class*/
template <class MapConfig>
class map_index
//Derive class from map specialization
: public map_index_aux<MapConfig>::index_t
{
typedef map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename MapConfig::segment_manager segment_manager;
public:
/*!Constructor. Takes a pointer to the
segment manager. Can throw*/
map_index(segment_manager *segment_mngr)
: base_type(typename index_aux::key_less(),
segment_mngr){}
/*!This reserves memory to optimize the insertion of n
elements in the index*/
void reserve(std::size_t n)
{ /*Does nothing, map has not reserve or rehash*/ }
};
/*!Trait classes to detect if an index is a node
index. This allows more efficient operations
when deallocating named objects.*/
template<class MapConfig>
struct is_node_index
<boost::interprocess::map_index<MapConfig> >
{
enum { value = true };
};
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MAP_INDEX_HPP

View File

@@ -0,0 +1,42 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NULL_INDEX_HPP
#define BOOST_INTERPROCESS_NULL_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/offset_ptr.hpp>
/*!\file
Describes a null index adaptor, so that if we don't want to construct
named objects, we can use this null index type to save resources.
*/
namespace boost { namespace interprocess {
/*!Null index type*/
template <class MapConfig>
class null_index
{
typedef typename MapConfig::segment_manager segment_manager;
public:
/*!Dummy function*/
null_index(segment_manager *segment_mngr_hdr){}
};
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NULL_INDEX_HPP

View File

@@ -0,0 +1,97 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_UNORDERED_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/unordered_map.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/allocators/private_node_allocator.hpp>
/*!\file
Describes index adaptor of boost::unordered_map container, to use it
as name/shared memory index
*/
namespace boost { namespace interprocess {
/*!Helper class to define typedefs from IndexTraits*/
template <class MapConfig>
struct unordered_map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef std::equal_to<key_type> key_equal;
typedef std::pair<const key_type, mapped_type> value_type;
typedef private_node_allocator
<value_type,
64,
typename MapConfig::segment_manager> allocator_type;
struct hasher
: std::unary_function<key_type, std::size_t>
{
std::size_t operator()(const key_type &val) const
{
typedef typename key_type::char_type char_type;
const char_type *beg = detail::get_pointer(val.mp_str),
*end = beg + val.m_len;
return boost::hash_range(beg, end);
}
};
typedef unordered_map<key_type, mapped_type, hasher,
key_equal, allocator_type> index_t;
};
/*!Index type based in unordered_map. Just derives from unordered_map and
defines the interface needed by the shared named object creation class*/
template <class MapConfig>
class unordered_map_index
//Derive class from unordered_map specialization
: public unordered_map_index_aux<MapConfig>::index_t
{
typedef unordered_map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename MapConfig::segment_manager segment_manager;
public:
/*!Constructor. Takes a pointer to the
segment manager. Can throw*/
unordered_map_index(segment_manager *segment_mngr)
: base_type(0,
typename index_aux::hasher(),
typename index_aux::key_equal(),
segment_mngr){}
/*!This reserves memory to optimize the insertion of n
elements in the index*/
void reserve(std::size_t n)
{ base_type::rehash(n); }
};
/*!Trait classes to detect if an index is a node
index. This allows more efficient operations
when deallocating named objects.*/
template<class MapConfig>
struct is_node_index
<boost::interprocess::unordered_map_index<MapConfig> >
{
enum { value = true };
};
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP

View File

@@ -0,0 +1,428 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_FWD_HPP
#define BOOST_INTERPROCESS_FWD_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
// old Dinkumware
# include <boost/compatibility/cpp_c_headers/cstddef>
#else
# include <cstddef>
#endif
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
namespace std {
template <class T>
class allocator;
template <class T>
struct less;
template <class T1, class T2>
struct pair;
template <class CharType>
struct char_traits;
} //namespace std {
namespace boost { namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
// shared_memory
//////////////////////////////////////////////////////////////////////////////
class shared_memory;
//////////////////////////////////////////////////////////////////////////////
// mapped file/mapped region/mapped_file
//////////////////////////////////////////////////////////////////////////////
class file_mapping;
class mapped_region;
class mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Mutexes
//////////////////////////////////////////////////////////////////////////////
class null_mutex;
class interprocess_mutex;
class interprocess_recursive_mutex;
class named_mutex;
class named_recursive_mutex;
class interprocess_semaphore;
class named_semaphore;
//////////////////////////////////////////////////////////////////////////////
// Mutex families
//////////////////////////////////////////////////////////////////////////////
struct mutex_family;
struct null_mutex_family;
//////////////////////////////////////////////////////////////////////////////
// Other synchronization classes
//////////////////////////////////////////////////////////////////////////////
class barrier;
class interprocess_sharable_mutex;
class interprocess_condition;
//////////////////////////////////////////////////////////////////////////////
// Locks
//////////////////////////////////////////////////////////////////////////////
template <class Mutex>
class scoped_lock;
template <class SharableMutex>
class sharable_lock;
//////////////////////////////////////////////////////////////////////////////
// STL compatible allocators
//////////////////////////////////////////////////////////////////////////////
template<class T, class SegmentManager>
class allocator;
template<class T, std::size_t N, class SegmentManager>
class node_allocator;
template<class T, std::size_t N, class SegmentManager>
class private_node_allocator;
template<class T, class SegmentManager>
class cached_node_allocator;
//////////////////////////////////////////////////////////////////////////////
// offset_ptr
//////////////////////////////////////////////////////////////////////////////
template <class T>
class offset_ptr;
//////////////////////////////////////////////////////////////////////////////
// intersegment_ptr
//////////////////////////////////////////////////////////////////////////////
template <class Mutex>
struct flat_map_intersegment;
template <class T/*, class PT = flat_map_intersegment<interprocess_mutex> */>
class intersegment_ptr;
//////////////////////////////////////////////////////////////////////////////
// Memory allocation algorithms
//////////////////////////////////////////////////////////////////////////////
//Single segment memory allocation algorithms
template<class MutexFamily, class VoidMutex = offset_ptr<void> >
class seq_fit;
template<class MutexFamily, class VoidMutex = offset_ptr<void> >
class simple_seq_fit;
//Single segment memory allocation algorithms
template<class MutexFamily, class VoidMutex = intersegment_ptr<void> >
class multi_seq_fit;
template<class MutexFamily, class VoidMutex = intersegment_ptr<void> >
class multi_simple_seq_fit;
//////////////////////////////////////////////////////////////////////////////
// Index Types
//////////////////////////////////////////////////////////////////////////////
template<class IndexConfig> class flat_map_index;
template<class IndexConfig> class map_index;
template<class IndexConfig> class null_index;
//////////////////////////////////////////////////////////////////////////////
// Segment manager
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class segment_manager;
//////////////////////////////////////////////////////////////////////////////
// External buffer front-ends
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_external_buffer;
typedef basic_managed_external_buffer
<char
,simple_seq_fit<null_mutex_family>
,flat_map_index>
managed_external_buffer;
typedef basic_managed_external_buffer
<wchar_t
,simple_seq_fit<null_mutex_family>
,flat_map_index>
wmanaged_external_buffer;
//////////////////////////////////////////////////////////////////////////////
// Shared memory front-ends
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_shared_memory;
typedef basic_managed_shared_memory
<char
,simple_seq_fit<mutex_family>
,flat_map_index>
managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,simple_seq_fit<mutex_family>
,flat_map_index>
wmanaged_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Fixed address shared memory
//////////////////////////////////////////////////////////////////////////////
typedef basic_managed_shared_memory
<char
,simple_seq_fit<mutex_family, void *>
,flat_map_index>
fixed_managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,simple_seq_fit<mutex_family, void *>
,flat_map_index>
wfixed_managed_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Heap memory front-ends
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_heap_memory;
typedef basic_managed_heap_memory
<char
,simple_seq_fit<null_mutex_family>
,flat_map_index>
managed_heap_memory;
typedef basic_managed_heap_memory
<wchar_t
,simple_seq_fit<null_mutex_family>
,flat_map_index>
wmanaged_heap_memory;
//////////////////////////////////////////////////////////////////////////////
// Mapped file front-ends
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_mapped_file;
typedef basic_managed_mapped_file
<char
,simple_seq_fit<mutex_family>
,flat_map_index>
managed_mapped_file;
typedef basic_managed_mapped_file
<wchar_t
,simple_seq_fit<mutex_family>
,flat_map_index>
wmanaged_mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Exceptions
//////////////////////////////////////////////////////////////////////////////
class interprocess_exception;
class lock_exception;
class bad_alloc;
//////////////////////////////////////////////////////////////////////////////
// Bufferstream
//////////////////////////////////////////////////////////////////////////////
//bufferstream
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferbuf;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_ibufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_obufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferstream;
//////////////////////////////////////////////////////////////////////////////
// Vectorstream
//////////////////////////////////////////////////////////////////////////////
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorbuf;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ivectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ovectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorstream;
//////////////////////////////////////////////////////////////////////////////
// Smart pointers
//////////////////////////////////////////////////////////////////////////////
template<class T, class Deleter>
class scoped_ptr;
template<class T, class VoidPointer>
class intrusive_ptr;
//////////////////////////////////////////////////////////////////////////////
// IPC
//////////////////////////////////////////////////////////////////////////////
class message_queue;
//////////////////////////////////////////////////////////////////////////////
// Containers
//////////////////////////////////////////////////////////////////////////////
//vector class
template <class T
,class A = std::allocator<T> >
class vector;
//list class
template <class T
,class A = std::allocator<T> >
class list;
//slist class
template <class T
,class Alloc = std::allocator<T> >
class slist;
//set class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class set;
//multiset class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class multiset;
//map class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<const Key, T> > >
class map;
//multimap class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<const Key, T> > >
class multimap;
//flat_set class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class flat_set;
//flat_multiset class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class flat_multiset;
//flat_map class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<Key, T> > >
class flat_map;
//flat_multimap class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<Key, T> > >
class flat_multimap;
//basic_string class
template <class CharT
,class Traits = std::char_traits<CharT>
,class Alloc = std::allocator<CharT> >
class basic_string;
//string class
typedef basic_string
<char
,std::char_traits<char>
,std::allocator<char> >
string;
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP

View File

@@ -0,0 +1,875 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_INTERSEGMENT_PTR_HPP
#define BOOST_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/cast_tags.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <limits.h>
/*!\file
*/
namespace boost {
namespace interprocess {
/*!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
{
typedef flat_map_intersegment<Mutex> self_t;
typedef std::size_t offset_t;
typedef std::size_t segment_t;
/*!Returns true if object represents null pointer*/
bool is_null() const
{ return m_offset == ~offset_t(0); }
/*!Sets the object to represent the null pointer*/
void set_null()
{ m_offset = ~offset_t(0); }
/*!Sets the object internals to represent the address pointed by ptr*/
void set_from_pointer(const void *ptr)
{
if(!ptr){
set_null();
}
else{
segment_t id1, id2;
offset_t offset1, offset2;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(ptr, id1, offset1);
get_segment_and_offset(this, id2, offset2);
}
m_distance = id1 - id2;
m_offset = offset1;
}
}
/*!Sets the object internals to represent the address pointed
by another flat_map_intersegment*/
void set_from_other(const self_t &other)
{
if(other.is_null()){
set_null();
}
else{
segment_t id1, id2;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
offset_t off;
get_segment_and_offset(&other, id1, off);
get_segment_and_offset(this, id2, off);
}
m_distance = id1 + other.m_distance - id2;
m_offset = other.m_offset;
}
}
/*!Obtains the address pointed by the object*/
void *get_pointer() const
{
segment_t id1;
offset_t off;
void * base_addr = 0;
if(is_null()){
return base_addr;
}
else{
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(this, id1, off);
segment_t target_segment = segment_t(id1+m_distance);
base_addr = get_base_address(target_segment);
}
return detail::char_ptr_cast(base_addr) + m_offset;
}
}
/*!Swaps two objects efficiently*/
void swap(self_t &other)
{
//This specialized swap avoids some costly operations
segment_t id1, id2, id;
offset_t off;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(&other, id1, off);
get_segment_and_offset(this, id2, off);
}
//Swap offset value
off = m_offset; m_offset = other.m_offset; other.m_offset = off;
//Calculate new segment distance. Let overflow do its work
id = m_distance;
m_distance = id1 + other.m_distance - id2;
other.m_distance = id2 + id - id1;
}
/*!Increments internal offset*/
void inc_offset(offset_t bytes)
{ m_offset += bytes; }
/*!Decrements internal offset*/
void dec_offset(offset_t bytes)
{ m_offset -= bytes; }
/*!Calculates the distance between two basic_intersegment_ptr-s.
This only works with two basic_intersegment_ptr pointing
to the same segment. Otherwise undefined*/
offset_t diff(const self_t &other) const
{ return m_offset - other.m_offset; }
/*!Returns true if both point to the same object*/
bool equal(const self_t &y) const
{
if(m_offset != y.m_offset){
return false;
}
else{
segment_t id1, id2;
offset_t off;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(this, id1, off);
get_segment_and_offset(&y, id2, off);
}
return segment_t(id1 + m_distance) == segment_t(id2 + y.m_distance);
}
}
/*!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
{
segment_t id1, id2;
offset_t off;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(this, id1, off);
get_segment_and_offset(&y, id2, off);
}
id1 = segment_t(id1 + m_distance);
id2 = segment_t(id2 + y.m_distance);
return (id1 < id2) || (id1 == id2 && m_offset < y.m_offset);
}
//--------------------------------------------------------------------------
static void get_group_and_id(void *addr, std::size_t &group, std::size_t &id)
{
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
get_segment_and_offset(addr, group, id);
}
group = group >> s_shift;
}
/*!Returns the polymorphic multi-segment creator associated with a
segment-group. Returns 0 if not found or an error occurs.*/
static void* find_group_data(std::size_t group)
{
typedef typename mappings_t::group_to_data_t::iterator it_t;
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
it_t it(s_map.group_to_data.find(group));
if(it == s_map.group_to_data.end()){
return 0;
}
return it->second;
}
/*!Reserves a segment-group, installs the associated polymorphic
segment-creator, and the segment passed as (base, size) as
the segment id = 0 of the new group. Returns the group that will
be associated with this segment. Returns 0 if there are no available
groups or an error occurs.*/
static std::size_t new_group(void *group_data)
{
typedef typename mappings_t::group_to_data_t::iterator it_t;
typedef typename mappings_t::group_to_data_t::value_type value_type;
typedef std::pair<it_t, bool> insert_ret;
std::size_t group = 0;
BOOST_TRY{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
//Check if there are too many groups
if(s_map.group_to_data.size() >= (s_max_value - 1) ){
return 0;
}
//Check if there are no registered groups or the first one
//is not group 1, assign id 1 to the new group.
else if(s_map.group_to_data.empty() ||
s_map.group_to_data.begin()->first != 1){
group = 1;
}
//If not, take a not used number
else{
it_t it1(s_map.group_to_data.begin()),
it2(it1),
itend(s_map.group_to_data.end());
for(++it2; it2 != itend; ++it1, ++it2){
if(it2->first - it1->first > 1){
break;
}
}
group = it1->first+1;
}
insert_ret ret =
s_map.group_to_data.insert(value_type(group, group_data));
//This insertion must succeed
assert(ret.second);
if(!ret.second) return false;
return group;
}
BOOST_CATCH(const std::bad_alloc &){}
BOOST_CATCH_END
return 0;
}
/*!Erases the mapping between a group and the associated polymorphic pointer.
Returns false if the group is not found or there is an error*/
static bool delete_group(std::size_t group)
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
typedef typename mappings_t::segment_to_ptr_t::iterator it_t;
//Find the range of the group
it_t first_of_group(s_map.segment_to_ptr.lower_bound(group << s_shift));
it_t one_past_group(s_map.segment_to_ptr.lower_bound((group+1)<< s_shift));
//Erase all info related to the group
for(it_t it(first_of_group); it != one_past_group; ++it){
//Erase entry from addr-segment
if(!s_map.ptr_to_segment.erase(it->second)){
//This can't be possible since both indexes should be synchronized
assert(false);
return false;
}
}
//Erase all info from groups
s_map.segment_to_ptr.erase(first_of_group, one_past_group);
//Erase the group info
bool ret = s_map.group_to_data.erase(group) == 1;
assert(ret);
if(!ret) return false;
//Erase all mappings of this group
return true;
}
/*!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 bool insert_mapping(std::size_t group, std::size_t id,
void *base_address, std::size_t size)
{
//Check limits
if(group > s_max_value || id > s_max_value){
return false;
}
BOOST_TRY{
typedef typename mappings_t::ptr_to_segment_t::value_type ptr_to_segment_val_t;
typedef typename mappings_t::segment_to_ptr_t::value_type segment_to_ptr_val_t;
typedef typename mappings_t::ptr_to_segment_t::iterator ptr_to_segment_it_t;
typedef typename mappings_t::segment_to_ptr_t::iterator segment_to_ptr_it_t;
typedef std::pair<ptr_to_segment_it_t, bool> ptr_to_segment_ret_t;
typedef std::pair<segment_to_ptr_it_t, bool> segment_to_ptr_ret_t;
//Compose segment identification
segment_t segment = (group << s_shift) | id;
typename mappings_t:: segment_info_t segment_info;
segment_info.segment = segment;
segment_info.size = size;
{
//------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
//This can throw
ptr_to_segment_ret_t ptr_to_segment_ret =
s_map.ptr_to_segment.insert(ptr_to_segment_val_t(base_address, segment_info));
if(!ptr_to_segment_ret.second)
return false;
//Node eraser will erase the node if an exception occurs
detail::value_eraser<typename mappings_t::ptr_to_segment_t>
value_eraser(s_map.ptr_to_segment, ptr_to_segment_ret.first);
//This can throw
segment_to_ptr_ret_t segment_to_ptr_ret =
s_map.segment_to_ptr.insert(segment_to_ptr_val_t(segment, base_address));
if(!segment_to_ptr_ret.second){
//This should never occur, since both maps must have
//the same elements indexed by different key
assert(!segment_to_ptr_ret.second);
return false;
}
//Insertion ok, release value_eraser
value_eraser.release();
return true;
}
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
}
static bool erase_mapping(void *base_address)
{
typedef typename mappings_t::ptr_to_segment_t::iterator ptr_to_segment_it_t;
typedef typename mappings_t::segment_to_ptr_t::iterator segment_to_ptr_it_t;
{ //------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
ptr_to_segment_it_t ptr_to_segment_it = s_map.ptr_to_segment.find(base_address);
if(ptr_to_segment_it == s_map.ptr_to_segment.end()){
//This group/id is not an valid entry
assert(ptr_to_segment_it == s_map.ptr_to_segment.end());
return false;
}
//Obtain segment
segment_t segment = ptr_to_segment_it->second.segment;
//Erase node from map
s_map.ptr_to_segment.erase(ptr_to_segment_it);
//Erase entry in the second map
if(!s_map.segment_to_ptr.erase(segment)){
//This can't be possible since both indexes should be synchronized
assert(false);
return false;
}
}
return true;
}
static bool erase_mapping(std::size_t group, std::size_t id)
{
//Check limits
if(group > s_max_value || id > s_max_value){
return false;
}
typedef typename mappings_t::ptr_to_segment_t::iterator ptr_to_segment_it_t;
typedef typename mappings_t::segment_to_ptr_t::iterator segment_to_ptr_it_t;
//Compose segment identification
segment_t segment = (group << s_shift) | id;
{ //------------------------------------------------------------------
boost::interprocess::scoped_lock<typename mappings_t::mutex_t> lock(s_map);
//------------------------------------------------------------------
segment_to_ptr_it_t segment_to_ptr_it = s_map.segment_to_ptr.find(segment);
if(segment_to_ptr_it == s_map.segment_to_ptr.end()){
//This group/id is not an valid entry
assert(segment_to_ptr_it != s_map.segment_to_ptr.end());
return false;
}
//Obtain address
void *address = segment_to_ptr_it->second;
//Erase node from map
s_map.segment_to_ptr.erase(segment_to_ptr_it);
//Erase entry in the second map
if(!s_map.ptr_to_segment.erase(address)){
//This can't be possible since both indexes should be synchronized
assert(false);
return false;
}
}
return true;
}
private:
/*!Half of the bits are for group id and the
other half for the index inside the group
unsigned group : sizeof(std::size_t)/2;
unsigned index : sizeof(std::size_t)/2;*/
segment_t m_distance;
offset_t m_offset;
struct mappings_t : Mutex
{
struct segment_info_t
{
std::size_t size;
segment_t segment;
};
/*!Mutex to preserve integrity in multi-threaded enviroments*/
typedef Mutex mutex_t;
/*!Maps base addresses and segment information
(size and segment group and id)*/
typedef boost::interprocess::flat_map
<const void *
,segment_info_t
,std::less<const void *> > ptr_to_segment_t;
/*!Maps segment group/id with base addresses*/
typedef boost::interprocess::flat_map
<segment_t, void *> segment_to_ptr_t;
/*!Maps segment group with a polymorphic multi-segment creator
that knows how to create new segments*/
typedef boost::interprocess::flat_map
<segment_t, void*> group_to_data_t;
ptr_to_segment_t ptr_to_segment;
segment_to_ptr_t segment_to_ptr;
group_to_data_t group_to_data;
~mappings_t()
{
//Check that all mappings have been erased
assert(ptr_to_segment.empty());
assert(segment_to_ptr.empty());
assert(group_to_data.empty());
}
};
//Static members
static mappings_t s_map;
static const std::size_t s_shift = sizeof(std::size_t)*CHAR_BIT/2;
static const std::size_t s_max_value = std::size_t(1) << s_shift;
private:
/*!Returns the segment and offset of an address*/
static void get_segment_and_offset(const void *ptr, segment_t &segment, offset_t &offset)
{
if(s_map.ptr_to_segment.empty()){
segment = 0;
offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast();
}
//Find the first base address greater than ptr
typename mappings_t::ptr_to_segment_t::iterator it
= s_map.ptr_to_segment.upper_bound(ptr);
if(it == s_map.ptr_to_segment.begin()){
segment = 0;
offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast();
}
//Go to the previous one
--it;
char * segment_base = detail::char_ptr_cast(it->first);
std::size_t segment_size = it->second.size;
if(segment_base <= detail::char_ptr_cast(ptr) &&
(segment_base + segment_size) >= detail::char_ptr_cast(ptr)){
segment = it->second.segment;
offset = detail::char_ptr_cast(ptr) - segment_base;
}
else{
segment = 0;
offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast();
}
}
/*!Returns the base address of a segment*/
static void *get_base_address(segment_t segment)
{
typename mappings_t::segment_to_ptr_t::iterator it
= s_map.segment_to_ptr.find(segment);
if(it == s_map.segment_to_ptr.end()){
return 0;
}
else{
return it->second;
}
}
};
/*!Static map-group associated with flat_map_intersegment<>*/
template <class Mutex>
typename flat_map_intersegment<Mutex>::mappings_t
flat_map_intersegment<Mutex>::s_map;
/*!Static constant that shows the number of bits to shift to obtain the
group part of segment_t type*/
template <class Mutex>
const std::size_t flat_map_intersegment<Mutex>::s_shift;
/*!Static constant that shows the number of bits to shift to obtain the
group part of segment_t type*/
template <class Mutex>
const std::size_t flat_map_intersegment<Mutex>::s_max_value;
/*!
A smart pointer that can point to a pointee that resides in another memory
memory mapped or shared memory segment.
*/
template <class T/*, class PT*/>
class intersegment_ptr : public flat_map_intersegment<interprocess_mutex> //: public PT
{
typedef flat_map_intersegment<interprocess_mutex> PT;
typedef boost::interprocess::workaround::random_it<T> random_it_t;
// typedef intersegment_ptr<T, PT> self_t;
typedef intersegment_ptr<T> self_t;
typedef PT base_t;
typedef typename random_it_t::const_pointer const_pointer_t;
typedef typename random_it_t::const_reference const_reference_t;
void unspecified_bool_type_func() const {}
typedef void (self_t::*unspecified_bool_type)() const;
public:
typedef typename random_it_t::pointer pointer;
typedef typename random_it_t::reference reference;
typedef typename random_it_t::value_type value_type;
typedef typename random_it_t::difference_type difference_type;
typedef typename random_it_t::iterator_category 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 */
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/*, PT*/> &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/*, PT*/> &r, detail::static_cast_tag)
//{ base_t::set_from_pointer(static_cast<T*>(r.get())); }
{
if(r.is_null()){
base_t::set_from_pointer(0);
}
else{
//Some dirty tricks to safe segment operations.
//Calculate pointer adjustment and adjust offset.
pointer ptr = reinterpret_cast<pointer>(this);
std::ptrdiff_t difference = detail::char_ptr_cast(static_cast<T*>(ptr)) -
detail::char_ptr_cast(ptr);
base_t::set_from_other(r);
base_t::inc_offset(difference*sizeof(T));
}
}
/*!Emulates const_cast operator. Never throws.*/
template<class U>
intersegment_ptr(const intersegment_ptr<U/*, PT*/> &r, detail::const_cast_tag)
{ base_t::set_from_pointer(const_cast<T*>(r.get())); }
/*
{
//Make sure const conversion is correct
pointer p = const_cast<pointer>((U*)0); (void)p;
base_t::set_from_other(r);
}*/
/*!Emulates dynamic_cast operator. Never throws.*/
template<class U>
intersegment_ptr(const intersegment_ptr<U/*, PT*/> &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/*, PT*/> &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 (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/*, PT*/> & 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>
bool _diff(const intersegment_ptr<T2/*, PT*/> &other) const
{ return base_t::less(other); }
/*!Returns true if both point to the same object*/
template <class T2>
bool _equal(const intersegment_ptr<T2/*, PT*/> &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/*, PT*/> &other) const
{ return base_t::less(other); }
};
/*!Compares the equality of two intersegment_ptr-s.
Never throws.*/
template <class T1, class T2/*, class PT1*/> inline
bool operator ==(const intersegment_ptr<T1/*, PT1*/> &left,
const intersegment_ptr<T2/*, PT1*/> &right)
{
//Make sure both pointers can be compared
bool e = typename intersegment_ptr<T1/*, PT1*/>::pointer(0) ==
typename intersegment_ptr<T2/*, PT1*/>::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/*, class PT1*/> inline
bool operator <(const intersegment_ptr<T1/*, PT1*/> &left,
const intersegment_ptr<T2/*, PT1*/> &right)
{
//Make sure both pointers can be compared
bool e = typename intersegment_ptr<T1/*, PT1*/>::pointer(0) <
typename intersegment_ptr<T2/*, PT1*/>::pointer(0);
(void)e;
return left._less(right);
}
template<class T1, class T2/*, class PT*/> inline
bool operator!= (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return !(pt1 ==pt2); }
/*!intersegment_ptr<T1> <= intersegment_ptr<T2, PT>. Never throws.*/
template<class T1, class T2/*, class PT*/> inline
bool operator<= (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return !(pt1 > pt2); }
/*!intersegment_ptr<T1> > intersegment_ptr<T2, PT>. Never throws.*/
template<class T1, class T2/*, class PT*/> inline
bool operator> (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return (pt2 < pt1); }
/*!intersegment_ptr<T1> >= intersegment_ptr<T2, PT>. Never throws.*/
template<class T1, class T2/*, class PT*/> inline
bool operator>= (const intersegment_ptr<T1/*, PT*/> &pt1,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return !(pt1 < pt2); }
/*!operator<< */
template<class E, class T, class U/*, class PT*/> inline
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, const intersegment_ptr<U/*, PT*/> & p)
{ return os << p.get(); }
/*!operator>> */
template<class E, class T, class U/*, class PT*/> inline
std::basic_istream<E, T> & operator>>
(std::basic_istream<E, T> & os, intersegment_ptr<U/*, PT*/> & 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/*, class PT*/> inline
intersegment_ptr<T/*, PT*/> operator+
(std::ptrdiff_t diff, const intersegment_ptr<T/*, PT*/>& 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/*, class PT*/> inline
std::ptrdiff_t operator- (const intersegment_ptr<T/*, PT*/> &pt,
const intersegment_ptr<T2/*, PT*/> &pt2)
{ return pt._diff(pt2); }
/*! swap specialization */
template<class T/*, class PT*/> inline
void swap (boost::interprocess::intersegment_ptr<T/*, PT*/> &pt,
boost::interprocess::intersegment_ptr<T/*, PT*/> &pt2)
{ pt.swap(pt2); }
/*!get_pointer() enables boost::mem_fn to recognize intersegment_ptr.
Never throws.*/
template<class T/*, class PT*/> inline
T * get_pointer(boost::interprocess::intersegment_ptr<T/*, PT*/> const & p)
{ return p.get(); }
/*!Simulation of static_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> static_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::static_cast_tag()); }
/*!Simulation of const_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> const_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::const_cast_tag()); }
/*!Simulation of dynamic_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::dynamic_cast_tag()); }
/*!Simulation of reinterpret_cast between pointers. Never throws.*/
template<class T, class U/*, class PT*/> inline
boost::interprocess::intersegment_ptr<T/*, PT*/> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U/*, PT*/> &r)
{ return boost::interprocess::intersegment_ptr<T/*, PT*/>(r, boost::interprocess::detail::reinterpret_cast_tag()); }
/*!Trait class to detect if an smart pointer has
multi-segment addressing capabilities.*/
template <class T/*, class PT*/>
struct is_multisegment_ptr
<boost::interprocess::intersegment_ptr<T/*, PT*/> >
{
enum { value = true };
};
} //namespace interprocess {
/*!has_trivial_constructor<> == true_type specialization for optimizations*/
template <class T/*, class PT*/>
struct has_trivial_constructor
< boost::interprocess::intersegment_ptr<T/*, PT*/> >
: public true_type{};
/*!has_trivial_destructor<> == true_type specialization for optimizations*/
template <class T/*, class PT*/>
struct has_trivial_destructor
< boost::interprocess::intersegment_ptr<T/*, PT*/> >
: public true_type{};
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERSEGMENT_PTR_HPP

View File

@@ -0,0 +1,616 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MESSAGE_QUEUE_HPP
#define BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <algorithm> //std::lower_bound
#include <cstddef> //std::size_t
#include <string.h> //memcpy
/*!\file
Describes an inter-process message queue. This class allows sending
messages between processes and allows blocking, non-blocking and timed
sending and receiving.
*/
namespace boost{ namespace interprocess{
/*!A class that allows sending messages between processes.*/
class message_queue
{
//Blocking modes
enum block_t { blocking, timed, non_blocking };
message_queue();
public:
/*!Result types when sending or receiving messages*/
enum result_t {
ok,
internal_error,
empty,
full,
too_small_buffer,
timeout,
too_big_buffer,
};
/*!Creates a process shared message queue with name "name". For this message queue,
the maximum number of messages will be "max_num_msg" and the maximum message size
will be "max_msg_size".*/
message_queue(detail::create_only_t create_only,
const char *name,
std::size_t max_num_msg,
std::size_t max_msg_size);
/*!Opens or creates a process shared message queue with name "name".
If the queue is created, the maximum number of messages will be "max_num_msg"
and the maximum message size will be "max_msg_size". If queue was previously
created the queue will be opened and "max_num_msg" and "max_msg_size" parameters
are ignored.*/
message_queue(detail::open_or_create_t open_or_create,
const char *name,
std::size_t max_num_msg,
std::size_t max_msg_size);
/*!Opens a previously created process shared message queue with name "name".
If the was not previously created or there are no free resources, the
function returns false.*/
message_queue(detail::open_only_t open_only,
const char *name);
/*!Destructor. Never throws*/
~message_queue();
/*!Sends a message stored in buffer "buffer" with size "buffer_size" in the
message queue with priority "priority". If the message queue is full
the sender is blocked. Returns "ok" if message is placed in the message
queue, "internal_error" if message queue is corrupted, or "too_big_buffer"
if parameter "buffer_size" is bigger than the maximum message size allowed
in the queue. Never throws*/
result_t send (const void *buffer, std::size_t buffer_size,
unsigned int priority);
/*!Sends a message stored in buffer "buffer" with size "buffer_size" in the
message queue with priority "priority". If the message queue is full
the sender is not blocked. Returns "ok" if message is placed in the message
queue, "internal_error" if message queue is corrupted, "too_big_buffer"
if parameter "buffer_size" is bigger than the maximum message size allowed
in the queue and "full" if message queue is full and message can't be
placed there. Never throws*/
result_t try_send (const void *buffer, std::size_t buffer_size,
unsigned int priority);
/*!Sends a message stored in buffer "buffer" with size "buffer_size" in the
message queue with priority "priority". If the message queue is full
the sender is retries until time "abs_time" is reached. Returns "ok" if message
is placed in the message queue, "internal_error" if message queue is corrupted,
"too_big_buffer" if parameter "buffer_size" is bigger than the maximum message
size allowed in the queue and "timeout" if message can't be placed and time
"abs_time" is reached. Never throws*/
result_t timed_send (const void *buffer, std::size_t buffer_size,
unsigned int priority, const boost::posix_time::ptime& abs_time);
/*!Receives a message from the message queue. The message is stored in buffer
"buffer", which has size "buffer_size". The received message has size
"recvd_size" and priority "priority". If the message queue is empty
the receiver is blocked. Returns "ok" if a message is received from the
message queue, "internal_error" if message queue is corrupted, or
"too_small_buffer" if parameter "buffer_size" is smaller than the maximum
message size allowed in the queue. Never throws*/
result_t receive (void *buffer, std::size_t buffer_size,
std::size_t &recvd_size,unsigned int &priority);
/*!Receives a message from the message queue. The message is stored in buffer
"buffer", which has size "buffer_size". The received message has size
"recvd_size" and priority "priority". If the message queue is empty
the receiver is not blocked. Returns "ok" if a message is received from the
message queue, "internal_error" if message queue is corrupted,
"too_small_buffer" if parameter "buffer_size" is smaller than the maximum
message size allowed in the queue or "empty" is message queue is empty.
Never throws*/
result_t try_receive (void *buffer, std::size_t buffer_size,
std::size_t &recvd_size,unsigned int &priority);
/*!Receives a message from the message queue. The message is stored in buffer
"buffer", which has size "buffer_size". The received message has size
"recvd_size" and priority "priority". If the message queue is empty
the receiver retries until time "abs_time" is reached. Returns "ok" if a message is
received from the message queue, "internal_error" if message queue is
corrupted, "too_small_buffer" if parameter "buffer_size" is smaller than the
maximum message size allowed in the queue or "timeout" is message queue is
empty. Never throws*/
result_t timed_receive (void *buffer, std::size_t buffer_size,
std::size_t &recvd_size,unsigned int &priority,
const boost::posix_time::ptime &abs_time);
/*!Returns the maximum number of messages allowed by the queue. The message
queue must be opened or created previously. Otherwise, returns 0.
Never throws*/
std::size_t get_max_num_msg() const;
/*!Returns the maximum size of message allowed by the queue. The message
queue must be opened or created previously. Otherwise, returns 0.
Never throws*/
std::size_t get_max_msg_size() const;
/*!Removes the message queue from the system. Never throws*/
static bool remove(const char *name);
private:
typedef boost::posix_time::ptime ptime;
result_t receive(block_t block,
void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority,
const ptime &abs_time = ptime());
result_t send(block_t block,
const void *buffer, std::size_t buffer_size,
unsigned int priority, const ptime &abs_time = ptime());
/*!Returns the needed memory size for the shared message queue. Never throws*/
static std::size_t get_mem_size(std::size_t max_msg_size, std::size_t max_num_msg);
/*!This header is the prefix of each message in the queue*/
class msg_hdr_t;
friend class msg_hdr_t;
/*!This functor is the predicate to order stored messages by priority*/
class priority_functor;
friend class priority_functor;
class mq_hdr_t;
friend class mq_hdr_t;
/*!This is the atomic functor to be executed when creating or opening
shared memory. Never throws*/
class initialization_func_t;
friend class initialization_func_t;
shared_memory m_shmem;
};
/*!This header is the prefix of each message in the queue*/
class message_queue::msg_hdr_t
{
public:
std::size_t len; // Message length
unsigned int priority;// Message priority
/*!Returns the data buffer associated with this this message*/
void * data(){ return this+1; } //
};
/*!This functor is the predicate to order stored messages by priority*/
class message_queue::priority_functor
{
public:
bool operator()(const offset_ptr<msg_hdr_t> &msg1,
const offset_ptr<msg_hdr_t> &msg2) const
{ return msg1->priority < msg2->priority; }
};
/*!This header is placed in the beginning of the shared memory and contains
the data to control the queue. This class initializes the shared memory
in the following way in ascending memory address with proper alignment
fillings (title is a c pseudo-code to explain better the structure):
-> mq_hdr_t:
Main control block that controls the rest of the elements
-> offset_ptr<msg_hdr_t> index [max_num_msg]
An array of pointers with size "max_num_msg" called index. Each pointer
points to a preallocated message. The elements of this array are
reordered in runtime in the following way:
When the current number of messages is "cur_num_msg", the first
"cur_num_msg" pointers point to inserted messages and the rest
point to free messages. The first "cur_num_msg" pointers are
ordered by the priority of the pointed message and by insertion order
if two messages have the same priority. So the next message to be
used in a "receive" is pointed by index [cur_num_msg-1] and the first free
message ready to be used in a "send" operation is index [cur_num_msg].
This transforms index in a fixed size priority queue with an embedded free
message queue.
-> struct message_t
{
msg_hdr_t header;
char[max_msg_size] data;
} messages [max_num_msg];
An array of buffers of preallocated messages, each one prefixed with the
msg_hdr_t structure. Each of this message is pointed by one pointer of
the index structure.
*/
class message_queue::mq_hdr_t
: public priority_functor
{
typedef offset_ptr<msg_hdr_t> msg_hdr_ptr_t;
public:
/*!Constructor. This object must be constructed in the beginning of the
shared memory of the size returned by the function "get_mem_size".
This constructor initializes the needed resources and creates
the internal structures like the priority index. This can throw.*/
mq_hdr_t(std::size_t max_num_msg, std::size_t max_msg_size)
: m_max_num_msg(max_num_msg),
m_max_msg_size(max_msg_size),
m_cur_num_msg(0)
{ this->initialize_memory(); }
/*!Returns the inserted message with top priority*/
msg_hdr_t * top_msg()
{ return mp_index[m_cur_num_msg-1].get(); }
/*!Frees the top priority message and saves it in the free message list*/
void free_top_msg()
{ --m_cur_num_msg; }
/*!Returns the first free msg of the free message queue*/
msg_hdr_t * free_msg()
{ return mp_index[m_cur_num_msg].get(); }
/*!Inserts the first free message in the priority queue*/
void queue_free_msg()
{
//Get free msg
msg_hdr_ptr_t free = mp_index[m_cur_num_msg];
//Get priority queue's range
msg_hdr_ptr_t *it = &mp_index[0], *it_end = &mp_index[m_cur_num_msg];
//Check where the free message should be placed
it = std::lower_bound(it, it_end, free, static_cast<priority_functor&>(*this));
//Make room in that position
std::copy_backward(it, it_end, it_end+1);
//Insert the free message in correct position
*it = free;
++m_cur_num_msg;
}
/*!Returns the number of bytes needed to construct a message queue with
"max_num_size" maximum number of messages and "max_msg_size" maximum
message size. Never throws.*/
static std::size_t get_mem_size
(std::size_t max_msg_size, std::size_t max_num_msg)
{
const std::size_t
msg_hdr_align = boost::alignment_of<msg_hdr_t>::value,
index_align = boost::alignment_of<msg_hdr_ptr_t>::value,
r_hdr_size = detail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
r_index_size = detail::get_rounded_size(sizeof(msg_hdr_ptr_t)*max_num_msg, msg_hdr_align),
r_max_msg_size = detail::get_rounded_size(max_msg_size, msg_hdr_align) + sizeof(msg_hdr_t);
return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size);
}
/*!Initializes the memory structures to preallocate messages and constructs the
message index. Never throws.*/
void initialize_memory()
{
const std::size_t
msg_hdr_align = boost::alignment_of<msg_hdr_t>::value,
index_align = boost::alignment_of<msg_hdr_ptr_t>::value,
r_hdr_size = detail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
r_index_size = detail::get_rounded_size(sizeof(msg_hdr_ptr_t)*m_max_num_msg, msg_hdr_align),
r_max_msg_size = detail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(msg_hdr_t);
//Pointer to the index
msg_hdr_ptr_t *index = reinterpret_cast<msg_hdr_ptr_t*>
(detail::char_ptr_cast(this)+r_hdr_size);
//Pointer to the first message header
msg_hdr_t *msg_hdr = reinterpret_cast<msg_hdr_t*>
(detail::char_ptr_cast(this)+r_hdr_size+r_index_size);
//Initialize the pointer to the index
mp_index = index;
//Initialize the index so each slot points to a preallocated message
for(std::size_t i = 0; i < m_max_num_msg; ++i){
index[i] = msg_hdr;
msg_hdr = reinterpret_cast<msg_hdr_t*>
(detail::char_ptr_cast(msg_hdr)+r_max_msg_size);
}
}
public:
//Pointer to the index
offset_ptr<msg_hdr_ptr_t> mp_index;
//Maximum number of messages of the queue
const std::size_t m_max_num_msg;
//Maximum size of messages of the queue
const std::size_t m_max_msg_size;
//Current number of messages
std::size_t m_cur_num_msg;
//Mutex to protect data structures
interprocess_mutex m_mutex;
//Condition block receivers when there are no messages
interprocess_condition m_cond_recv;
//Condition block senders when the queue is full
interprocess_condition m_cond_send;
};
/*!This is the atomic functor to be executed when creating or opening
shared memory. Never throws*/
class message_queue::initialization_func_t
{
public:
initialization_func_t(std::size_t maxmsg = 0,
std::size_t maxmsgsize = 0)
: m_maxmsg (maxmsg), m_maxmsgsize(maxmsgsize) {}
bool operator()(const mapped_region &region, bool created)
{
char *mptr;
if(created){
mptr = reinterpret_cast<char*>(region.get_address());
//Construct the message queue header at the beginning
BOOST_TRY{
new (mptr) mq_hdr_t(m_maxmsg, m_maxmsgsize);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
}
return true;
}
const std::size_t m_maxmsg;
const std::size_t m_maxmsgsize;
};
inline message_queue::~message_queue()
{}
inline std::size_t message_queue::get_mem_size
(std::size_t max_msg_size, std::size_t max_num_msg)
{ return mq_hdr_t::get_mem_size(max_msg_size, max_num_msg); }
inline message_queue::message_queue(detail::create_only_t create_only,
const char *name,
std::size_t max_num_msg,
std::size_t max_msg_size)
//Create shared memory and execute functor atomically
: m_shmem(create_only,
name,
get_mem_size(max_msg_size, max_num_msg),
memory_mapping::rw_mode,
(void*)0,
//Prepare initialization functor
initialization_func_t (max_num_msg, max_msg_size))
{}
/*!Opens or creates a process shared message queue with name "name".
If the queue is created, the maximum number of messages will be "max_num_msg"
and the maximum message size will be "max_msg_size". If queue was previously
created the queue will be opened and "max_num_msg" and "max_msg_size" parameters
are ignored. If there are no free resources, the function returns false.*/
inline message_queue::message_queue(detail::open_or_create_t open_or_create,
const char *name,
std::size_t max_num_msg,
std::size_t max_msg_size)
//Create shared memory and execute functor atomically
: m_shmem(open_or_create,
name,
get_mem_size(max_msg_size, max_num_msg),
memory_mapping::rw_mode,
(void*)0,
//Prepare initialization functor
initialization_func_t (max_num_msg, max_msg_size))
{}
/*!Opens a previously created process shared message queue with name "name".
If the was not previously created or there are no free resources, the
function returns false.*/
inline message_queue::message_queue(detail::open_only_t open_only,
const char *name)
//Create shared memory and execute functor atomically
: m_shmem(open_only,
name,
memory_mapping::rw_mode,
(void*)0,
//Prepare initialization functor
initialization_func_t ())
{}
inline message_queue::result_t
message_queue::send(const void *buffer, std::size_t buffer_size,
unsigned int priority)
{ return this->send(blocking, buffer, buffer_size, priority); }
inline message_queue::result_t
message_queue::try_send(const void *buffer, std::size_t buffer_size,
unsigned int priority)
{ return this->send(non_blocking, buffer, buffer_size, priority); }
inline message_queue::result_t
message_queue::timed_send(const void *buffer, std::size_t buffer_size,
unsigned int priority, const boost::posix_time::ptime &abs_time)
{ return this->send(timed, buffer, buffer_size, priority, abs_time); }
inline message_queue::result_t
message_queue::send(block_t block,
const void *buffer, std::size_t buffer_size,
unsigned int priority, const boost::posix_time::ptime &abs_time)
{
mq_hdr_t *p_hdr = static_cast<mq_hdr_t*>(m_shmem.get_address());
//Check if buffer is smaller than maximum allowed
if (buffer_size > p_hdr->m_max_msg_size) {
return too_big_buffer;
}
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
{
//If the queue is full execute blocking logic
if (p_hdr->m_cur_num_msg >= p_hdr->m_max_num_msg) {
switch(block){
case non_blocking :
return full;
break;
case blocking :
while (p_hdr->m_cur_num_msg >= p_hdr->m_max_num_msg){
p_hdr->m_cond_send.wait(lock);
}
break;
case timed :
while (p_hdr->m_cur_num_msg >= p_hdr->m_max_num_msg){
if(!p_hdr->m_cond_send.timed_wait(lock, abs_time))
return timeout;
}
break;
default:
return internal_error;
}
}
//Get the first free message from free message queue
msg_hdr_t *free_msg = p_hdr->free_msg();
if (free_msg == 0) {
return internal_error;
}
//Copy control data to the free message
free_msg->priority = priority;
free_msg->len = buffer_size;
//Copy user buffer to the message
memcpy(free_msg->data(), buffer, buffer_size);
//Insert the first free message in the priority queue
p_hdr->queue_free_msg();
//If this message changes the queue empty state, notify it to receivers
if (p_hdr->m_cur_num_msg == 1){
p_hdr->m_cond_recv.notify_one();
}
} // Lock end
return ok;
}
inline message_queue::result_t
message_queue::receive(void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority)
{ return this->receive(blocking, buffer, buffer_size, recvd_size, priority); }
inline message_queue::result_t
message_queue::try_receive(void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority)
{ return this->receive(non_blocking, buffer, buffer_size, recvd_size, priority); }
inline message_queue::result_t
message_queue::timed_receive(void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority,
const boost::posix_time::ptime &abs_time)
{ return this->receive(timed, buffer, buffer_size, recvd_size, priority, abs_time); }
inline message_queue::result_t
message_queue::receive(block_t block,
void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority,
const boost::posix_time::ptime &abs_time)
{
mq_hdr_t *p_hdr = static_cast<mq_hdr_t*>(m_shmem.get_address());
//Check if buffer is big enough for any message
if (buffer_size < p_hdr->m_max_msg_size) {
return too_small_buffer;
}
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
{
//If there are no messages execute blocking logic
if (p_hdr->m_cur_num_msg == 0) {
switch(block){
case non_blocking :
return empty;
break;
case blocking :
while (p_hdr->m_cur_num_msg == 0){
p_hdr->m_cond_recv.wait(lock);
}
break;
case timed :
while (p_hdr->m_cur_num_msg == 0){
if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time))
return timeout;
}
break;
//Paranoia check
default:
return internal_error;
}
}
//Thre is at least message ready to pick, get the top one
msg_hdr_t *top_msg = p_hdr->top_msg();
//Paranoia check
if (top_msg == 0) {
return internal_error;
}
//Get data from the message
recvd_size = top_msg->len;
priority = top_msg->priority;
//Copy data to receiver's bufers
memcpy(buffer, top_msg->data(), recvd_size);
//Free top message and put it in the free message list
p_hdr->free_top_msg();
//If this reception changes the queue full state, notify senders
if (p_hdr->m_cur_num_msg == (p_hdr->m_max_num_msg-1)){
p_hdr->m_cond_send.notify_one();
}
} //Lock end
return ok;
}
inline std::size_t message_queue::get_max_num_msg() const
{
mq_hdr_t *p_hdr = static_cast<mq_hdr_t*>(m_shmem.get_address());
return p_hdr ? p_hdr->m_max_msg_size : 0; }
inline std::size_t message_queue::get_max_msg_size() const
{
mq_hdr_t *p_hdr = static_cast<mq_hdr_t*>(m_shmem.get_address());
return p_hdr ? p_hdr->m_max_msg_size : 0;
}
inline bool message_queue::remove(const char *name)
{ return shared_memory::remove(name); }
}} //namespace boost{ namespace interprocess{
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP

View File

@@ -0,0 +1,21 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NAMED_FIFO_HPP
#define BOOST_NAMED_FIFO_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
//TO-DO
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_NAMED_FIFO_HPP

View File

@@ -0,0 +1,70 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MANAGED_EXTERNAL_BUFFER_HPP
#define BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_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/detail/managed_memory_impl.hpp>
#include <string.h> //for memcpy
/*!\file
Describes a named user memory allocation user class.
*/
namespace boost {
namespace interprocess {
/*!A basic user memory named object creation class. Inherits all
basic functionality from
basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_external_buffer
: public detail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
{
typedef detail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType> base_t;
public:
/*!Creates and places the segment manager. This can throw*/
bool create (void *addr, std::size_t size)
{ return base_t::create_impl(addr, size); }
/*!Connects to a created the segment manager. Never throws.*/
bool open (void *addr, std::size_t size)
{ return base_t::open_impl(addr, size); }
/*!Frees resources. Never throws.*/
void close()
{ base_t::close_impl(); }
void grow(std::size_t extra_bytes)
{ base_t::grow(extra_bytes); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP

View File

@@ -0,0 +1,194 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MANAGED_HEAP_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_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/detail/creation_tags.hpp>
#include <vector>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/detail/no_exceptions_support.hpp>
/*!\file
Describes a named heap memory allocation user class.
*/
namespace boost {
namespace interprocess {
namespace detail {
/*!This class defines an operator() that creates a heap memory
ofthe requested size. The rest of the parameters are
passed in the constructor. The class a template parameter
to be used with create_from_file/create_from_istream functions
of basic_named_object classes*/
class heap_mem_creator_t
{
public:
heap_mem_creator_t(std::vector<char> &heapmem)
: m_heapmem(heapmem){}
void *operator()(std::size_t size)
{
BOOST_TRY{
m_heapmem.resize(size, char(0));
}
BOOST_CATCH(...){
return 0;
}
BOOST_CATCH_END
return &m_heapmem[0];
}
private:
std::vector<char> &m_heapmem;
};
} //namespace detail {
/*!A basic heap memory named object creation class. Initializes the
heap memory segment. Inherits all basic functionality from
basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_heap_memory
: public detail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
{
private:
typedef detail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType> base_t;
public: //functions
/*!Constructor. Allocates basic resources. Never throws.*/
// basic_managed_heap_memory(){}
/*!Destructor. Calls priv_close. Never throws.*/
~basic_managed_heap_memory()
{ this->priv_close(); }
/*!Creates heap memory and initializes the segment manager.
This can throw.*/
basic_managed_heap_memory(std::size_t size)
: m_heapmem(size, char(0))
{
if(!base_t::create_impl(&m_heapmem[0], size)){
this->priv_close();
throw interprocess_exception();//return false;
}
// return true;
}
/*!Creates the object from file. Never throws.*/
/*
template<class CharT>
bool create_from_file (const CharT *filename)
{
detail::heap_mem_creator_t mem_creator(m_heapmem);
return base_t::create_from_file(filename, mem_creator);
}
*/
/*!Creates the object from a an istream. Never throws.*/
/*
bool create_from_istream (std::istream &instream, std::size_t size)
{
detail::heap_mem_creator_t mem_creator(m_heapmem);
return base_t::create_from_istream(instream, size, mem_creator);
}
*/
/*!Creates heap memory from file. Never throws.*/
/*
template<class CharT>
bool create_from_file (const CharT *filename, const char *mem_name,
const void *addr = 0)
{
std::basic_ifstream< CharT, std::char_traits<CharT> >
file(filename, std::ios::binary);
//Check file
if(!file) return false;
//Calculate size
file.seekg(0, std::ios::end);
std::size_t size = file.tellg();
file.seekg(0, std::ios::beg);
//Create from stream
return create_from_istream(file, size, mem_name, addr);
}
*/
/*!Creates heap memory from an istream. Never throws.*/
/*
bool create_from_istream (std::istream &instream, std::size_t size,
const char *mem_name, const void *addr = 0)
{
return priv_resize_vector(size) &&
instream.read (reinterpret_cast<char*>(&m_heapmem[0])
,(std::streamsize)size).good();
}
*/
/*!Tries to resize internal heap memory so that
we have room for more objects.
WARNING: If memory is reallocated, all the objects will
be binary-copied to the new buffer. To be able to use
this function, all pointers constructed in this buffer
must be offset pointers. Otherwise, the result is undefined.
Returns true if the growth has been successful, so you will
have some extra bytes to allocate new objects. If returns
false, the heap allocation has failed.*/
bool grow(std::size_t extra_bytes)
{
//If memory is reallocated, data will
//be automatically copied
BOOST_TRY{
m_heapmem.resize(m_heapmem.size()+extra_bytes);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
//Grow always works
base_t::close_impl();
base_t::open_impl(&m_heapmem[0], m_heapmem.size());
base_t::grow(extra_bytes);
return true;
}
private:
/*!Frees resources. Never throws.*/
void priv_close()
{
base_t::destroy_impl();
std::vector<char>().swap(m_heapmem);
}
std::vector<char> m_heapmem;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP

View File

@@ -0,0 +1,229 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MANAGED_MAPPED_FILE_HPP
#define BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_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/detail/managed_memory_impl.hpp>
#include <boost/interprocess/mapped_file.hpp>
#include <string>
#include <fstream>
/*!\file
Describes a named shared memory object allocation user class.
*/
namespace boost {
namespace interprocess {
/*!A basic shared memory named object creation class. Initializes the
shared memory segment. Inherits all basic functionality from
basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_mapped_file
: public detail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType>
{
private:
typedef detail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType> base_t;
struct create_open_func
{
enum type_t { DoCreate, DoOpen, DoCreateOrOpen };
create_open_func(basic_managed_mapped_file * const frontend, type_t type)
: m_frontend(frontend), m_type(type){}
bool operator()(const mapped_region &region, bool created) const
{
if(((m_type == DoOpen) && created) ||
((m_type == DoCreate) && !created))
return false;
if(created)
return m_frontend->create_impl(region.get_address(), region.get_size());
else
return m_frontend->open_impl (region.get_address(), region.get_size());
}
basic_managed_mapped_file *m_frontend;
type_t m_type;
};
basic_managed_mapped_file *get_this_pointer()
{ return this; }
public: //functions
typedef enum {
ro_mode = file_mapping::ro_mode,
rw_mode = file_mapping::rw_mode,
} accessmode_t;
/*!Creates shared memory and creates and places the segment manager.
This can throw.*/
basic_managed_mapped_file(detail::create_only_t create_only, const char *name,
std::size_t size, const void *addr = 0)
: m_mfile(create_only, name, size, memory_mapping::rw_mode, addr,
create_open_func(get_this_pointer(), create_open_func::DoCreate))
{}
/*!Creates shared memory and creates and places the segment manager if
segment was not created. If segment was created it connects to the
segment.
This can throw.*/
basic_managed_mapped_file (detail::open_or_create_t open_or_create,
const char *name, std::size_t size,
const void *addr = 0)
: m_mfile(open_or_create, name, size, memory_mapping::rw_mode, addr,
create_open_func(get_this_pointer(),
create_open_func::DoCreateOrOpen))
{}
/*!Connects to a created shared memory and it's the segment manager.
Never throws.*/
basic_managed_mapped_file (detail::open_only_t open_only, const char* name,
const void *addr = 0)
: m_mfile(open_only, name, memory_mapping::rw_mode, addr,
create_open_func(get_this_pointer(),
create_open_func::DoOpen))
{}
/*!Destructor. Never throws.*/
~basic_managed_mapped_file()
{}
/*
bool create(const char *name, std::size_t size)
{
//Create file with given size
std::ofstream file(name, std::ios::binary | std::ios::trunc);
file.seekp(static_cast<std::streamoff>(size-1));
file.write("", 1);
file.close();
//Create mapped file
if(!m_mfile.open(name, 0, size, (file_mapping::accessmode_t)rw_mode)){
return false;
}
//Create Interprocess machinery
if(!base_t::create_impl(m_mfile.get_address(), size)){
close();
return false;
}
m_filename = name;
return true;
}
bool open(const char *name, accessmode_t mode = rw_mode)
{
//Open file and get size
std::ifstream file(name, std::ios::binary);
std::size_t size = file.seekg(0, std::ios::end).tellg();
file.close();
//Create mapped file
if(!m_mfile.open(name, 0, size, (file_mapping::accessmode_t)mode)){
return false;
}
//Open Interprocess machinery
if(!base_t::open_impl(m_mfile.get_address(), size)){
close();
return false;
}
m_filename = name;
return true;
}
*/
/*!Flushes cached data to file. Never throws*/
bool flush()
{ return m_mfile.flush(); }
/*!Frees resources. Never throws.*/
/*
void close()
{
base_t::close_impl();
m_mfile.close();
}
*/
/*!Tries to resize mapped file so that we have room for
more objects.
WARNING: The memory mapping can change. To be able to use
this function, all pointers constructed in this buffer
must be offset pointers. Otherwise, the result is undefined.
Returns true if the growth has been successful, so you will
have some extra bytes to allocate new objects. If returns
false, the heap allocation has failed.*/
/*
bool grow(std::size_t extra_bytes)
{
//If memory is reallocated, data will
//be automatically copied
std::size_t old_size = m_mfile.get_size();
std::size_t new_size = old_size + extra_bytes;
m_mfile.close();
//Increase file size
{
std::ofstream file(m_filename.c_str(),
std::ios::binary |std::ios::in | std::ios::out);
if(!file){
return false;
}
if(!file.seekp(static_cast<std::streamoff>(new_size - 1))){
return false;
}
if(!file.write("", 1)){
return false;
}
}
if(!m_mfile.open(m_filename.c_str(), 0, new_size,
(file_mapping::accessmode_t)rw_mode)){
return false;
}
//Grow always works
base_t::close_impl();
base_t::open_impl(m_mfile.get_address(), new_size);
base_t::grow(extra_bytes);
return true;
}
*/
private:
mapped_file m_mfile;
std::string m_filename;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP

View File

@@ -0,0 +1,376 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MANAGED_MULTI_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_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/detail/managed_memory_impl.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
#include <boost/detail/no_exceptions_support.hpp>
//#include <boost/interprocess/detail/multi_segment_services.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/shared_memory.hpp>
#include <list>
#include <new>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/streams/vectorstream.hpp>
#include <memory>
/*!\file
Describes a named shared memory object allocation user class.
*/
namespace boost {
namespace interprocess {
/*!A basic shared memory named object creation class. Initializes the
shared memory segment. Inherits all basic functionality from
basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>*/
template
<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_multi_shared_memory
: public detail::basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType>
{
typedef basic_managed_multi_shared_memory
<CharType, MemoryAlgorithm, IndexType> self_t;
typedef typename self_t::void_pointer void_pointer;
////////////////////////////////////////////////////////////////////////
//
// Some internal helper structs/functors
//
////////////////////////////////////////////////////////////////////////
/*!This class defines an operator() that creates a shared memory
of the requested size. The rest of the parameters are
passed in the constructor. The class a template parameter
to be used with create_from_file/create_from_istream functions
of basic_named_object classes*/
/*
class segment_creator
{
public:
segment_creator(shared_memory &shmem,
const char *mem_name,
const void *addr)
: m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
void *operator()(std::size_t size)
{
if(!m_shmem.create(m_mem_name, size, m_addr))
return 0;
return m_shmem.get_address();
}
private:
shared_memory &m_shmem;
const char *m_mem_name;
const void *m_addr;
};
*/
class group_services
{
public:
typedef std::pair<void *, std::size_t> result_type;
typedef basic_managed_multi_shared_memory frontend_t;
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
group_services(frontend_t *const frontend)
: mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
virtual std::pair<void *, std::size_t> create_new_segment(std::size_t alloc_size)
{
//We should allocate an extra byte so that the
//[base_addr + alloc_size] byte belongs to this segment
alloc_size += 1;
//If requested size is less than minimum, update that
alloc_size = (m_min_segment_size > alloc_size) ?
m_min_segment_size : alloc_size;
if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
alloc_size, 0)){
shmem_list_t::value_type &p_shm = *mp_frontend->m_shmem_list.rbegin();
return result_type(p_shm->get_address(), p_shm->get_size()-1);
}
return result_type(0, 0);
}
virtual ~group_services(){}
void set_group(std::size_t group)
{ m_group = group; }
std::size_t get_group() const
{ return m_group; }
void set_min_segment_size(std::size_t min_segment_size)
{ m_min_segment_size = min_segment_size; }
std::size_t get_min_segment_size() const
{ return m_min_segment_size; }
private:
frontend_t * const mp_frontend;
std::size_t m_group;
std::size_t m_min_segment_size;
};
/*!Functor to execute atomically when opening or creating a shared memory
segment.*/
struct create_open_func
{
enum type_t { DoCreate, DoOpen, DoOpenOrCreate };
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
create_open_func(self_t * const frontend,
type_t type, std::size_t segment_number)
: mp_frontend(frontend), m_type(type), m_segment_number(segment_number){}
bool operator()(const mapped_region &region, bool created) const
{
if(((m_type == DoOpen) && created) ||
((m_type == DoCreate) && !created))
return false;
void *addr = region.get_address();
std::size_t size = region.get_size();
std::size_t group = mp_frontend->m_group_services.get_group();
bool mapped = false;
bool impl_done = false;
//Associate this newly created segment as the
//segment id = 0 of this group
if((mapped = void_pointer::insert_mapping(group, m_segment_number, addr, size))){
//Check if this is the master segment
if(!m_segment_number){
//Create or open the Interprocess machinery
if(impl_done = created ?
mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size)){
return true;
}
}
else{
return true;
}
}
//This is the cleanup part
//---------------
if(impl_done){
mp_frontend->close_impl();
}
if(mapped){
bool ret = void_pointer::erase_mapping(group, 0);
assert(ret);(void)ret;
}
return false;
}
self_t * const mp_frontend;
type_t m_type;
std::size_t m_segment_number;
};
/*!Functor to execute atomically when closing a shared memory segment.*/
struct close_func
{
typedef typename
basic_managed_multi_shared_memory::void_pointer void_pointer;
close_func(self_t * const frontend)
: mp_frontend(frontend){}
void operator()(const mapped_region &region, bool last) const
{
if(last) mp_frontend->destroy_impl();
else mp_frontend->close_impl();
}
self_t * const mp_frontend;
};
typedef detail::basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType> base_t;
//Friend declarations
friend struct basic_managed_multi_shared_memory::create_open_func;
friend struct basic_managed_multi_shared_memory::close_func;
friend class basic_managed_multi_shared_memory::group_services;
typedef std::list<shared_memory*> shmem_list_t;
basic_managed_multi_shared_memory *get_this_pointer()
{ return this; }
public:
basic_managed_multi_shared_memory(detail::create_only_t,
const char *name,
std::size_t size)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoCreate,name, size);
}
basic_managed_multi_shared_memory(detail::open_or_create_t,
const char *name,
std::size_t size)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpenOrCreate, name, size);
}
basic_managed_multi_shared_memory(detail::open_only_t,
const char *name)
: m_group_services(get_this_pointer())
{
priv_open_or_create(create_open_func::DoOpen, name, 0);
}
~basic_managed_multi_shared_memory()
{ this->priv_close(); }
private:
bool priv_open_or_create(typename create_open_func::type_t type,
const char *name,
std::size_t size)
{
if(!m_shmem_list.empty())
return false;
std::size_t group = 0;
BOOST_TRY{
m_root_name = name;
//Insert multi segment services and get a group identifier
group = void_pointer::new_group(static_cast<void*>(&m_group_services));
m_group_services.set_group(group);
m_group_services.set_min_segment_size(size);
if(group){
if(this->priv_new_segment(type, size, 0)){
return true;
}
}
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
if(group){
void_pointer::delete_group(group);
}
return false;
}
bool priv_new_segment(typename create_open_func::type_t type,
std::size_t size,
const void *addr)
{
BOOST_TRY{
//Get the number of groups of this multi_segment group
std::size_t segment_id = m_shmem_list.size();
//Format the name of the shared memory: append segment number.
boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
formatter.seekp(std::ios::beg);
//Pre-reserve string size
std::size_t str_size = m_root_name.length()+10;
if(formatter.vector().size() < str_size){
//This can throw.
formatter.reserve(str_size);
}
//Format segment's name
formatter << m_root_name
<< static_cast<unsigned int>(segment_id) << std::ends;
//This functor will be executed when constructing
create_open_func func(this, type, segment_id);
const char *name = formatter.vector().c_str();
//This can throw.
std::auto_ptr<shared_memory> shm;
switch(type){
case create_open_func::DoCreate:
shm.reset(new shared_memory(create_only, name, size
,memory_mapping::rw_mode, addr, func));
break;
case create_open_func::DoOpen:
shm.reset(new shared_memory(open_only, name
,memory_mapping::rw_mode, addr, func));
break;
case create_open_func::DoOpenOrCreate:
shm.reset(new shared_memory( boost::interprocess::open_or_create
, name, size, memory_mapping::rw_mode
, addr, func));
break;
default:
return false;
break;
}
//This can throw.
m_shmem_list.push_back(shm.get());
//Anti-exception rollback
detail::value_eraser<shmem_list_t>
value_eraser(m_shmem_list, --m_shmem_list.end());
shm.release();
value_eraser.release();
return true;
}
BOOST_CATCH(const std::bad_alloc&){
}
BOOST_CATCH_END
return false;
}
/*!Frees resources. Never throws.*/
void priv_close()
{
if(!m_shmem_list.empty()){
bool ret;
//Obtain group identifier
std::size_t group = m_group_services.get_group();
//Erase main segment and its resources
shmem_list_t::iterator itbeg = m_shmem_list.begin(),
itend = m_shmem_list.end(),
it = itbeg;
//(*itbeg)->close_with_func(close_func(this));
//Delete group. All mappings are erased too.
ret = void_pointer::delete_group(group);
assert(ret);
//Now destroy all shared_memory segments so they
//are unmapped from the process
for(it = itbeg; it != itend; ++it) delete *it;
m_shmem_list.clear();
}
}
private:
shmem_list_t m_shmem_list;
group_services m_group_services;
std::string m_root_name;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,181 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MANAGED_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_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/detail/managed_memory_impl.hpp>
#include <boost/interprocess/shared_memory.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
/*!\file
Describes a named shared memory object allocation user class.
*/
namespace boost {
namespace interprocess {
/*!A basic shared memory named object creation class. Initializes the
shared memory segment. Inherits all basic functionality from
basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_shared_memory
: public detail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
{
////////////////////////////////////////////////////////////////////////
//
// Some internal helper structs/functors
//
////////////////////////////////////////////////////////////////////////
/*!This class defines an operator() that creates a shared memory
of the requested size. The rest of the parameters are
passed in the constructor. The class a template parameter
to be used with create_from_file/create_from_istream functions
of basic_named_object classes*/
/*
class segment_creator
{
public:
segment_creator(shared_memory &shmem,
const char *mem_name,
const void *addr)
: m_shmem(shmem), m_mem_name(mem_name), m_addr(addr){}
void *operator()(std::size_t size)
{
if(!m_shmem.create(m_mem_name, size, m_addr))
return 0;
return m_shmem.get_address();
}
private:
shared_memory &m_shmem;
const char *m_mem_name;
const void *m_addr;
};
*/
/*!Functor to execute atomically when opening or creating a shared memory
segment.*/
struct create_open_func
{
enum type_t { DoCreate, DoOpen, DoCreateOrOpen };
create_open_func(basic_managed_shared_memory * const frontend, type_t type)
: m_frontend(frontend), m_type(type){}
bool operator()(const mapped_region &region, bool created) const
{
if(((m_type == DoOpen) && created) ||
((m_type == DoCreate) && !created))
return false;
if(created)
return m_frontend->create_impl(region.get_address(), region.get_size());
else
return m_frontend->open_impl (region.get_address(), region.get_size());
}
basic_managed_shared_memory *m_frontend;
type_t m_type;
};
typedef detail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType> base_t;
//Friend declarations
friend struct basic_managed_shared_memory::create_open_func;
basic_managed_shared_memory();
basic_managed_shared_memory *get_this_pointer()
{ return this; }
public: //functions
/*!Destructor. Calls close. Never throws.*/
~basic_managed_shared_memory()
{}
/*!Creates shared memory and creates and places the segment manager.
This can throw.*/
basic_managed_shared_memory(detail::create_only_t create_only, const char *name,
std::size_t size, const void *addr = 0)
: m_shmem(create_only, name, size, memory_mapping::rw_mode, addr,
create_open_func(get_this_pointer(), create_open_func::DoCreate))
{}
/*!Creates shared memory and creates and places the segment manager if
segment was not created. If segment was created it connects to the
segment.
This can throw.*/
basic_managed_shared_memory (detail::open_or_create_t open_or_create,
const char *name, std::size_t size,
const void *addr = 0)
: m_shmem(open_or_create, name, size, memory_mapping::rw_mode, addr,
create_open_func(get_this_pointer(),
create_open_func::DoCreateOrOpen))
{}
/*!Connects to a created shared memory and it's the segment manager.
Never throws.*/
basic_managed_shared_memory (detail::open_only_t open_only, const char* name,
const void *addr = 0)
: m_shmem(open_only, name, memory_mapping::rw_mode, addr,
create_open_func(get_this_pointer(),
create_open_func::DoOpen))
{}
static bool remove(const char *name)
{ return shared_memory::remove(name); }
/*!Creates shared memory from file. Never throws.*/
/*
template<class CharT>
bool create_from_file (const CharT *filename, const char *mem_name,
const void *addr = 0)
{
segment_creator mem_creator(m_shmem, mem_name, addr);
return base_t::create_from_file(filename, mem_creator);
}
*/
/*!Creates shared memory from an istream. Never throws.*/
/*
bool create_from_istream (std::istream &instream, std::size_t size,
const char *mem_name, const void *addr = 0)
{
segment_creator mem_creator(m_shmem, mem_name, addr);
return base_t::create_from_istream(instream, size, mem_creator);
}
*/
private:
shared_memory m_shmem;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,541 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MAPPED_FILE_HPP
#define BOOST_INTERPROCESS_MAPPED_FILE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
#include <boost/interprocess/memory_mapping.hpp>
#include <boost/interprocess/detail/global_lock.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <memory> //std::auto_ptr
#include <fstream> //std::fstream
#include <string> //std::string
#include <cstdio> //std::remove
#include <boost/noncopyable.hpp>
#include <string>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <sys/mman.h> //mmap, off64_t
# include <unistd.h>
# include <sys/stat.h>
# else
# error Unknown platform
# endif
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes file_mapping and mapped region classes
*/
namespace boost {
namespace interprocess {
/*!A class that wraps a file-mapping that can be used to
create mapped regions from the mapped files*/
class file_mapping : public memory_mapping
{
public:
typedef memory_mapping::accessmode_t accessmode_t;
typedef memory_mapping::mapping_handle_t mapping_handle_t;
/*!Opens a file mapping of file "filename", starting in offset
"file_offset", and the mapping's size will be "size". The mapping
can be opened for read-only "ro_mode" or read-write "rw_mode. modes.*/
file_mapping(const char *filename, accessmode_t mode);
/*!Calls close. Does not throw*/
~file_mapping();
/*!Returns the name of the file.*/
const char *get_name() const;
private:
/*!Closes a previously opened file mapping. Never throws.*/
void priv_close();
std::string m_filename;
accessmode_t m_mode;
};
inline file_mapping::~file_mapping()
{ this->priv_close(); }
/*!Returns the name of the file.*/
inline const char *file_mapping::get_name() const
{ return m_filename.c_str(); }
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline file_mapping::file_mapping
(const char *filename, memory_mapping::accessmode_t mode)
: memory_mapping()
, m_filename(filename)
, m_mode(mode)
{
unsigned long file_access = 0;
unsigned long file_creation_flags = 0;
//Set accesses
if (mode == rw_mode){
file_access |= winapi::generic_read | winapi::generic_write;
}
else if (mode == ro_mode){
file_access |= winapi::generic_read;
}
file_creation_flags = winapi::open_existing;
//Open file using windows API since we need the handle
memory_mapping::mapping_handle_t hnd =
winapi::create_file(filename, file_access, file_creation_flags);
//Check for error
if(hnd == winapi::invalid_handle_value){
error_info err = winapi::get_last_error();
this->priv_close();
throw interprocess_exception(err);
}
memory_mapping::assign_data(hnd, mode);
}
inline void file_mapping::priv_close()
{
if(memory_mapping::get_mapping_handle() != winapi::invalid_handle_value){
winapi::close_handle(memory_mapping::get_mapping_handle());
memory_mapping::assign_data
(winapi::invalid_handle_value, memory_mapping::get_mode());
}
}
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline file_mapping::file_mapping
(const char *filename, memory_mapping::accessmode_t mode)
: m_filename(filename)
, m_mode(mode)
{
//Create new mapping
int oflag = O_CREAT;
if(mode == ro_mode){
oflag |= O_RDONLY;
}
else if(mode == rw_mode){
oflag |= O_RDWR;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
//Open file and get handle
int hnd = ::open(filename, // filename
oflag, // read/write access
S_IRWXO | S_IRWXG | S_IRWXU); // permissions
if(hnd == -1){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
memory_mapping::assign_data(hnd, mode);
}
inline void file_mapping::priv_close()
{
if(memory_mapping::get_mapping_handle() != -1){
::close(memory_mapping::get_mapping_handle());
memory_mapping::assign_data(-1, memory_mapping::get_mode());
}
}
#endif //##if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!A class that wraps basic file-mapping management*/
class mapped_file : private boost::noncopyable
{
public:
/*!Creates a memory mapped file with name "name", and size "size".
If the file was previously created it throws an error.
The mapping can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user can also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
mapped_file(detail::create_only_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode = memory_mapping::rw_mode,
const void *addr = 0);
/*!Creates a memory mapped file with name "name", and size "size" if
the file was not previously created. If it was previously
created it tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user can also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
mapped_file(detail::open_only_t,
const char *name,
memory_mapping::accessmode_t mode = memory_mapping::rw_mode,
const void *addr = 0);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created it tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user can specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
mapped_file(detail::open_or_create_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode = memory_mapping::rw_mode,
const void *addr = 0);
/*!Creates a shared memory segment with name "name", with size "size".
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user must specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes a copy of the functor "construct_func" atomically if
the segment is created. The functor must have the following signature:
bool operator()(const mapped_file_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
must be "true". If the functor returns "false", or throws an error
is supposed and the shared memory won't be created.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const mapped_file_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
mapped_file(detail::create_only_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user must specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes a copy of the functor "construct_func" atomically
if the segment is opened. The functor must have the following signature:
bool operator()(const mapped_file_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
must be "false". If the functor returns "false", or throws an error
is supposed and the shared memory won't be opened.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const mapped_file_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
mapped_file(detail::open_only_t,
const char *name,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created it tries to open it.
The file can be opened in read-only "ro_mode" or read-write "rw_mode" modes.
The user must specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes the functor "construct_func" atomically if the segment is
created or opened. The functor must have the following signature:
bool operator()(const mapped_file_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
will be "true" if the shared memory was created. If the functor
returns "false", or throws an error is supposed and the
shared memory won't be opened.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const mapped_file_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
mapped_file(detail::open_or_create_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Destructor. Unmaps the file from process' address space.
It also executes the destruction functor atomically if
the user has registered that the destruction functor
in the constructor of this class.
Never throws.*/
~mapped_file();
/*!Returns the size of the file mapping. Never throws.*/
std::size_t get_size() const;
/*!Returns the base address of the file mapping. Never throws.*/
void* get_address() const;
/*!Flushes to the disk the whole file.
Never throws*/
bool flush();
/*!Returns the name of the shared memory segment used in the
constructor. Never throws.*/
const char *get_name() const;
private:
enum type_t { DoCreate, DoOpen, DoCreateOrOpen };
template <class ConstructFunc>
bool priv_open_or_create(type_t type,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
ConstructFunc construct_func);
//Members
mapped_region m_mapped_region;
std::string m_name;
};
inline
mapped_file::mapped_file
(detail::create_only_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr)
{
this->priv_open_or_create(DoCreate, name, size, mode, addr, null_mapped_region_function());
}
inline
mapped_file::mapped_file
(detail::open_only_t,
const char *name,
memory_mapping::accessmode_t mode,
const void *addr)
{
this->priv_open_or_create(DoOpen, name, 0, mode, addr, null_mapped_region_function());
}
inline
mapped_file::mapped_file
(detail::open_or_create_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr)
{
this->priv_open_or_create(DoCreateOrOpen, name, size, mode, addr, null_mapped_region_function());
}
template <class ConstructFunc> inline
mapped_file::mapped_file(detail::create_only_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoCreate, name, size, mode, addr, construct_func);
}
template <class ConstructFunc> inline
mapped_file::mapped_file(detail::open_only_t,
const char *name,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoOpen, name, 0, mode, addr, construct_func);
}
template <class ConstructFunc> inline
mapped_file::mapped_file(detail::open_or_create_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoCreateOrOpen, name, size, mode, addr, construct_func);
}
inline
mapped_file::~mapped_file()
{}
std::size_t mapped_file::get_size() const
{ return m_mapped_region.get_size(); }
void* mapped_file::get_address() const
{ return m_mapped_region.get_address(); }
bool mapped_file::flush()
{ return m_mapped_region.flush(); }
inline const char *mapped_file::get_name() const
{ return m_name.c_str(); }
template <class ConstructFunc> inline
bool mapped_file::priv_open_or_create
(mapped_file::type_t type, const char *name,
std::size_t size, memory_mapping::accessmode_t mode,
const void *addr, ConstructFunc construct_func)
{
error_info err;
bool created = true;
m_name = name;
//This global interprocess_mutex guarantees synchronized creation/open logic
detail::global_lock mut;
if(!mut.acquire()){
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
if(type == DoOpen){
//Open existing shared memory
created = false;
}
else if(type == DoCreateOrOpen || type == DoCreate){
detail::OS_file_handle_t hnd = detail::create_new_file(name);
if(hnd != detail::invalid_file()){
if(!detail::truncate_file(hnd, size)){
err = system_error_code();
detail::close_file(hnd);
std::remove(name);
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
//Free resources
if(!detail::close_file(hnd)){
err = system_error_code();
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
}
else if(type == DoCreate){
err = system_error_code();
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
}
else{
throw interprocess_exception(err);
}
//Open file mapping
file_mapping mapping(name, /*file_mapping::rw_mode*/mode);
mapped_region mapped(mapping, 0, size, /*file_mapping::rw_mode*/mode, addr);
//Now swap mapped region
m_mapped_region.swap(mapped);
//Execute atomic functor
construct_func(m_mapped_region, created);
return true;
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MAPPED_FILE_HPP

View File

@@ -0,0 +1,61 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MULTI_SIMPLE_SEQ_FIT_HPP
#define BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_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/mem_algo/detail/simple_seq_fit_impl.hpp>
#include <boost/interprocess/intersegment_ptr.hpp>
/*!\file
Describes sequential fit algorithm used to allocate objects in shared memory.
*/
namespace boost {
namespace interprocess {
/*!This class implements the simple sequential fit algorithm with a simply
linked list of free buffers.*/
template<class MutexFamily, class VoidPtr>
class multi_simple_seq_fit
: public detail::simple_seq_fit_impl<MutexFamily, VoidPtr>
{
typedef detail::simple_seq_fit_impl<MutexFamily, VoidPtr> base_t;
public:
/*!Constructor. "size" is the total size of the fixed size memory segment,
"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(multi_simple_seq_fit)
offset that the allocator should not use at all.*/
multi_simple_seq_fit (std::size_t size, std::size_t extra_hdr_bytes)
: base_t(size, extra_hdr_bytes){}
/*!Allocates bytes from existing segments. If there is no memory, it uses
the growing functor associated with the group to allocate a new segment.
If this fails, returns 0.*/
void* allocate (std::size_t nbytes)
{ return base_t::multi_allocate(nbytes); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP

View File

@@ -0,0 +1,871 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
#define BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_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/allocators/allocation_type.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/multi_segment_services.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <algorithm>
#include <utility>
#include <assert.h>
#include <new>
/*!\file
Describes sequential fit algorithm used to allocate objects in shared memory.
This class is intended as a base class for single segment and multi-segment
implementations.
*/
namespace boost {
namespace interprocess {
namespace detail {
/*!This class implements the simple sequential fit algorithm with a simply
linked list of free buffers.
This class is intended as a base class for single segment and multi-segment
implementations.*/
template<class MutexFamily, class VoidPointer>
class simple_seq_fit_impl : private boost::noncopyable
{
public:
/*!Shared interprocess_mutex family used for the rest of the Interprocess framework*/
typedef MutexFamily mutex_family;
/*!Pointer type to be used with the rest of the Interprocess framework*/
typedef VoidPointer void_pointer;
private:
struct block_ctrl;
typedef typename detail::
pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr;
/*!Block control structure*/
struct block_ctrl
{
/*!Offset pointer to the next block.*/
block_ctrl_ptr m_next;
/*!This block's memory size (including block_ctrl
header) in BasicSize units*/
std::size_t m_size;
std::size_t get_user_bytes() const
{ return this->m_size*Alignment - BlockCtrlBytes; }
std::size_t get_total_bytes() const
{ return this->m_size*Alignment; }
static block_ctrl *get_block_from_addr(void *addr)
{
return reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(addr) - BlockCtrlBytes);
}
void *get_addr() const
{
return reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(this) + BlockCtrlBytes);
}
};
/*!Shared interprocess_mutex to protect memory allocate/deallocate*/
typedef typename MutexFamily::mutex_t interprocess_mutex;
/*!This struct includes needed data and derives from
interprocess_mutex to allow EBO when using null interprocess_mutex*/
struct header_t : public interprocess_mutex
{
/*!Pointer to the first free block*/
block_ctrl m_root;
/*!Allocated bytes for internal checking*/
std::size_t m_allocated;
/*!The size of the memory segment*/
std::size_t m_size;
} m_header;
public:
/*!Constructor. "size" is the total size of the fixed size memory segment,
"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit_impl)
offset that the allocator should not use at all.*/
simple_seq_fit_impl (std::size_t size, std::size_t extra_hdr_bytes);
/*!Destructor.*/
~simple_seq_fit_impl();
/*!Obtains the minimum size needed by the algorithm*/
static std::size_t get_min_size (std::size_t extra_hdr_bytes);
//Functions for single segment management
/*!Allocates bytes, returns 0 if there is not more memory*/
void* allocate (std::size_t nbytes);
/*!Deallocates previously allocated bytes*/
void deallocate (void *addr);
/*!Returns the size of the memory segment*/
std::size_t get_size() const;
/*!Increases managed memory in extra_size bytes more*/
void grow(std::size_t extra_size);
/*!Returns true if all allocated memory has been deallocated*/
bool all_memory_deallocated();
/*!Makes an internal sanity check and returns true if success*/
bool check_sanity();
std::pair<void *, bool>
allocation_command (allocation_type command, std::size_t limit_size,
std::size_t preferred_size,std::size_t &received_size,
void *reuse_ptr = 0);
/*!Returns the size of the buffer previously allocated pointed by ptr*/
std::size_t size(void *ptr) const;
/*!Allocates bytes, if there is no more memory, it executes functor
f(std::size_t) to allocate a new segment to manage. The functor returns
std::pair<void*, std::size_t> indicating the base address and size of
the new segment. If the new segment can't be allocated, allocate
it will return 0.*/
void* multi_allocate(std::size_t nbytes);
private:
/*!Real allocation algorithm with min allocation option*/
std::pair<void *, bool> priv_allocate(allocation_type command
,std::size_t min_size
,std::size_t preferred_size
,std::size_t &received_size
,void *reuse_ptr = 0);
/*!Returns next block if it's free.
Returns 0 if next block is not free.*/
block_ctrl *priv_next_block_if_free(block_ctrl *ptr);
/*!Returns previous block's if it's free.
Returns 0 if previous block is not free.*/
std::pair<block_ctrl*, block_ctrl*>priv_prev_block_if_free(block_ctrl *ptr);
/*!Real expand function implementation*/
bool priv_expand(void *ptr
,std::size_t min_size, std::size_t preferred_size
,std::size_t &received_size);
/*!Real expand to both sides implementation*/
void* priv_expand_both_sides(allocation_type command
,std::size_t min_size
,std::size_t preferred_size
,std::size_t &received_size
,void *reuse_ptr
,bool only_preferred_backwards);
/*!Real shrink function implementation*/
bool priv_shrink(void *ptr
,std::size_t max_size, std::size_t preferred_size
,std::size_t &received_size);
/*!Checks if block has enough memory and splits/unlinks the block
returning the address to the users*/
void* priv_check_and_allocate(std::size_t units
,block_ctrl* prev
,block_ctrl* block
,std::size_t &received_size);
/*!Real deallocation algorithm*/
void priv_deallocate(void *addr);
/*!Makes a new memory portion available for allocation*/
void priv_add_segment(void *addr, std::size_t size);
enum { Alignment = boost::alignment_of<boost::detail::max_align>::value };
enum { BlockCtrlBytes = detail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value };
enum { BlockCtrlSize = BlockCtrlBytes/Alignment };
enum { MinBlockSize = BlockCtrlSize + Alignment };
};
template<class MutexFamily, class VoidPointer>
inline simple_seq_fit_impl<MutexFamily, VoidPointer>::
simple_seq_fit_impl(std::size_t size, std::size_t extra_hdr_bytes)
{
//Initialize sizes and counters
m_header.m_allocated = 0;
m_header.m_size = size;
//Initialize pointers
std::size_t block1_off = detail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment);
m_header.m_root.m_next = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(this) + block1_off);
m_header.m_root.m_next->m_size = (size - block1_off)/Alignment;
m_header.m_root.m_next->m_next = &m_header.m_root;
}
template<class MutexFamily, class VoidPointer>
inline simple_seq_fit_impl<MutexFamily, VoidPointer>::~simple_seq_fit_impl()
{
//There is a memory leak!
// assert(m_header.m_allocated == 0);
// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root));
}
template<class MutexFamily, class VoidPointer>
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::grow(std::size_t extra_size)
{
//Old highest address block's end offset
std::size_t old_end = m_header.m_size/Alignment*Alignment;
//Update managed buffer's size
m_header.m_size += extra_size;
//We need at least MinBlockSize blocks to create a new block
if((m_header.m_size - old_end) < MinBlockSize){
return;
}
//We'll create a new free block with extra_size bytes
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(this) + old_end);
new_block->m_next = 0;
new_block->m_size = (m_header.m_size - old_end)/Alignment;
m_header.m_allocated += new_block->m_size*Alignment;
this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes);
}
template<class MutexFamily, class VoidPointer>
inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, std::size_t size)
{
//Check size
assert(!(size < MinBlockSize));
if(size < MinBlockSize)
return;
//Construct big block using the new segment
block_ctrl *new_block = static_cast<block_ctrl *>(addr);
new_block->m_size = size/Alignment;
new_block->m_next = 0;
//Simulate this block was previously allocated
m_header.m_allocated += new_block->m_size*Alignment;
//Return block and insert it in the free block list
this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes);
}
template<class MutexFamily, class VoidPointer>
inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::get_size() const
{ return m_header.m_size; }
template<class MutexFamily, class VoidPointer>
inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
get_min_size (std::size_t extra_hdr_bytes)
{
return detail::get_rounded_size(sizeof(simple_seq_fit_impl)+extra_hdr_bytes
,Alignment)
+ MinBlockSize;
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
all_memory_deallocated()
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
return m_header.m_allocated == 0 &&
detail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root;
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
check_sanity()
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
block_ctrl *block = detail::get_pointer(m_header.m_root.m_next);
std::size_t free_memory = 0;
//Iterate through all blocks obtaining their size
do{
//Free blocks's next must be always valid
block_ctrl *next = detail::get_pointer(block->m_next);
if(!next){
return false;
}
free_memory += block->m_size*Alignment;
block = next;
}
while(block != &m_header.m_root);
//Check allocated bytes are less than size
if(m_header.m_allocated > m_header.m_size){
return false;
}
//Check free bytes are less than size
if(free_memory > m_header.m_size){
return false;
}
return true;
}
template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
allocate(std::size_t nbytes)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
std::size_t ignore;
return priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
}
template<class MutexFamily, class VoidPointer>
inline std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
allocation_command (allocation_type command, std::size_t min_size,
std::size_t preferred_size,std::size_t &received_size,
void *reuse_ptr)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr);
}
template<class MutexFamily, class VoidPointer>
inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
size(void *ptr) const
{
//We need no synchronization since this block is not going
//to be modified
//Obtain the real size of the block
block_ctrl *block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(ptr) - BlockCtrlBytes);
return block->m_size*Alignment - BlockCtrlBytes;
}
template<class MutexFamily, class VoidPointer>
inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
multi_allocate(std::size_t nbytes)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
//Multisegment pointer. Let's try first the normal allocation
//since it's faster.
std::size_t ignore;
void *addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
if(!addr){
//If this fails we will try the allocation through the segment
//creator.
std::size_t group, id;
//Obtain the segment group of this segment
void_pointer::get_group_and_id(this, group, id);
if(group == 0){
//Ooops, group 0 is not valid.
return 0;
}
//Now obtain the polymorphic functor that creates
//new segments and try to allocate again.
boost::interprocess::multi_segment_services *p_services =
static_cast<boost::interprocess::multi_segment_services*>
(void_pointer::find_group_data(group));
assert(p_services);
std::pair<void *, std::size_t> ret =
p_services->create_new_segment(MinBlockSize > nbytes ? MinBlockSize : nbytes);
if(ret.first){
priv_add_segment(ret.first, ret.second);
addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
}
}
return addr;
}
template<class MutexFamily, class VoidPointer>
void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_expand_both_sides(allocation_type command
,std::size_t min_size
,std::size_t preferred_size
,std::size_t &received_size
,void *reuse_ptr
,bool only_preferred_backwards)
{
typedef std::pair<block_ctrl *, block_ctrl *> prev_block_t;
block_ctrl *reuse = block_ctrl::get_block_from_addr(reuse_ptr);
received_size = 0;
if(this->size(reuse_ptr) > min_size){
received_size = this->size(reuse_ptr);
return reuse_ptr;
}
if(command & expand_fwd){
if(priv_expand(reuse_ptr, min_size, preferred_size, received_size))
return reuse_ptr;
}
else{
received_size = this->size(reuse_ptr);
}
if(command & expand_bwd){
std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes;
prev_block_t prev_pair = priv_prev_block_if_free(reuse);
block_ctrl *prev = prev_pair.second;
if(!prev){
return 0;
}
std::size_t needs_backwards =
detail::get_rounded_size(preferred_size - extra_forward, Alignment);
if(!only_preferred_backwards){
needs_backwards =
max_value(detail::get_rounded_size(min_size - extra_forward, Alignment)
,min_value(prev->get_user_bytes(), needs_backwards));
}
//Check if previous block has enough size
if((prev->get_user_bytes()) >= needs_backwards){
//Now take all next space. This will succeed
if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){
assert(0);
}
//We need a minimum size to split the previous one
if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){
block_ctrl *new_block = reinterpret_cast<block_ctrl *>
(detail::char_ptr_cast(reuse) - needs_backwards - BlockCtrlBytes);
new_block->m_next = 0;
new_block->m_size =
BlockCtrlSize + (needs_backwards + extra_forward)/Alignment;
prev->m_size =
(prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlSize;
received_size = needs_backwards + extra_forward;
m_header.m_allocated += needs_backwards + BlockCtrlBytes;
return new_block->get_addr();
}
else{
//Just merge the whole previous block
block_ctrl *prev_2_block = prev_pair.first;
//Update received size and allocation
received_size = extra_forward + prev->get_user_bytes();
m_header.m_allocated += prev->get_total_bytes();
//Now unlink it from previous block
prev_2_block->m_next = prev->m_next;
prev->m_size = reuse->m_size + prev->m_size;
prev->m_next = 0;
return prev->get_addr();
}
}
}
return 0;
}
template<class MutexFamily, class VoidPointer>
std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_allocate(allocation_type command
,std::size_t limit_size
,std::size_t preferred_size
,std::size_t &received_size
,void *reuse_ptr)
{
if(command & shrink_in_place){
bool success =
this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size);
return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
}
typedef std::pair<void *, bool> return_type;
received_size = 0;
if(limit_size > preferred_size)
return return_type(0, false);
//Number of units to request (including block_ctrl header)
std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlSize;
//Get the root and the first memory block
block_ctrl *prev = &m_header.m_root;
block_ctrl *block = detail::get_pointer(prev->m_next);
block_ctrl *root = &m_header.m_root;
block_ctrl *biggest_block = 0;
block_ctrl *prev_biggest_block = 0;
std::size_t biggest_size = limit_size;
//Expand in place
//reuse_ptr, limit_size, preferred_size, received_size
//
if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
void *ret = priv_expand_both_sides
(command, limit_size, preferred_size, received_size, reuse_ptr, true);
if(ret)
return return_type(ret, true);
}
if(command & allocate_new){
received_size = 0;
while(block != root){
//Update biggest block pointers
if(block->m_size > biggest_size){
prev_biggest_block = prev;
biggest_size = block->m_size;
biggest_block = block;
}
void *addr = this->priv_check_and_allocate(nunits, prev, block, received_size);
if(addr) return return_type(addr, false);
//Bad luck, let's check next block
prev = block;
block = detail::get_pointer(block->m_next);
}
//Bad luck finding preferred_size, now if we have any biggest_block
//try with this block
if(biggest_block){
received_size = biggest_block->m_size*Alignment - BlockCtrlSize;
nunits = detail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlSize;
void *ret = this->priv_check_and_allocate
(nunits, prev_biggest_block, biggest_block, received_size);
if(ret)
return return_type(ret, false);
}
}
//Now try to expand both sides with min size
if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
return return_type(priv_expand_both_sides
(command, limit_size, preferred_size, received_size, reuse_ptr, false), true);
}
return return_type(0, false);
}
template<class MutexFamily, class VoidPointer>
inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_next_block_if_free
(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
{
//Take the address where the next block should go
block_ctrl *next_block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(ptr) + ptr->m_size*Alignment);
//Check if the adjacent block is in the managed segment
std::size_t distance = (detail::char_ptr_cast(next_block) - detail::char_ptr_cast(this))/Alignment;
if(distance >= (m_header.m_size/Alignment)){
//"next_block" does not exist so we can't expand "block"
return 0;
}
if(!next_block->m_next)
return 0;
return next_block;
}
template<class MutexFamily, class VoidPointer>
inline
std::pair<typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *>
simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_prev_block_if_free
(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
{
typedef std::pair<block_ctrl *, block_ctrl *> prev_pair_t;
//Take the address where the previous block should go
block_ctrl *root = &m_header.m_root;
block_ctrl *prev_2_block = root;
block_ctrl *prev_block = detail::get_pointer(root->m_next);
while((detail::char_ptr_cast(prev_block) + prev_block->m_size*Alignment)
!= (detail::char_ptr_cast(ptr))
&& prev_block != root){
prev_2_block = prev_block;
prev_block = detail::get_pointer(prev_block->m_next);
}
if(prev_block == root || !prev_block->m_next)
return prev_pair_t(0, 0);
//Check if the previous block is in the managed segment
std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment;
if(distance >= (m_header.m_size/Alignment)){
//"previous_block" does not exist so we can't expand "block"
return prev_pair_t(0, 0);
}
return prev_pair_t(prev_2_block, prev_block);
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_expand (void *ptr
,std::size_t min_size
,std::size_t preferred_size
,std::size_t &received_size)
{
//Obtain the real size of the block
block_ctrl *block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(ptr) - BlockCtrlBytes);
std::size_t old_block_size = block->m_size;
//All used blocks' next is marked with 0 so check it
assert(block->m_next == 0);
//Put this to a safe value
received_size = old_block_size*Alignment - BlockCtrlBytes;
//Now translate it to Alignment units
min_size = detail::get_rounded_size(min_size, Alignment)/Alignment;
preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment;
//Some parameter checks
if(min_size > preferred_size)
return false;
std::size_t data_size = old_block_size - BlockCtrlSize;
if(data_size >= min_size)
return true;
block_ctrl *next_block = priv_next_block_if_free(block);
if(!next_block){
return false;
}
//Is "block" + "next_block" big enough?
std::size_t merged_size = old_block_size + next_block->m_size;
//Now we can expand this block further than before
received_size = merged_size*Alignment - BlockCtrlBytes;
if(merged_size < (min_size + BlockCtrlSize)){
return false;
}
//We can fill expand. Merge both blocks,
block->m_next = next_block->m_next;
block->m_size = merged_size;
//Find the previous free block of next_block
block_ctrl *prev = &m_header.m_root;
while(detail::get_pointer(prev->m_next) != next_block){
prev = detail::get_pointer(prev->m_next);
}
//Now insert merged block in the free list
//This allows reusing allocation logic in this function
m_header.m_allocated -= old_block_size*Alignment;
prev->m_next = block;
//Now use check and allocate to do the allocation logic
preferred_size += BlockCtrlSize;
std::size_t nunits = preferred_size < merged_size ? preferred_size : merged_size;
//This must success since nunits is less than merged_size!
if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){
//Something very ugly is happening here. This is a bug
//or there is memory corruption
assert(0);
return false;
}
return true;
}
template<class MutexFamily, class VoidPointer>
inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_shrink (void *ptr
,std::size_t max_size
,std::size_t preferred_size
,std::size_t &received_size)
{
//Obtain the real size of the block
block_ctrl *block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(ptr) - BlockCtrlBytes);
std::size_t block_size = block->m_size;
//All used blocks' next is marked with 0 so check it
assert(block->m_next == 0);
//Put this to a safe value
received_size = block_size*Alignment - BlockCtrlBytes;
//Now translate it to Alignment units
max_size = max_size/Alignment;
preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment;
//Some parameter checks
if(max_size < preferred_size)
return false;
std::size_t data_size = block_size - BlockCtrlSize;
if(data_size < preferred_size)
return false;
if(data_size == preferred_size)
return true;
//We must be able to create at least a new empty block
if((data_size - preferred_size) < BlockCtrlSize){
return false;
}
//Now we can just rewrite the size of the old buffer
block->m_size = preferred_size + BlockCtrlSize;
//Update new size
received_size = preferred_size*Alignment;
//We create the new block
block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(block) + block->m_size*Alignment);
//Write control data to simulate this new block was previously allocated
block->m_next = 0;
block->m_size = data_size - preferred_size;
//Now deallocate the new block to insert it in the free list
this->priv_deallocate(detail::char_ptr_cast(block)+BlockCtrlBytes);
return true;
}
template<class MutexFamily, class VoidPointer> inline
void* simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_check_and_allocate
(std::size_t nunits
,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* prev
,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* block
,std::size_t &received_size)
{
std::size_t upper_nunits = nunits + BlockCtrlSize;
bool found = false;
if (block->m_size > upper_nunits){
//This block is bigger than needed, split it in
//two blocks, the first's size will be (block->m_size-units)
//the second's size (units)
std::size_t total_size = block->m_size;
block->m_size = nunits;
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(block) + Alignment*nunits);
new_block->m_size = total_size - nunits;
new_block->m_next = block->m_next;
prev->m_next = new_block;
found = true;
}
else if (block->m_size >= nunits){
//This block has exactly the right size with an extra
//unusable extra bytes.
prev->m_next = block->m_next;
found = true;
}
if(found){
//We need block_ctrl for deallocation stuff, so
//return memory user can overwrite
m_header.m_allocated += block->m_size*Alignment;
received_size = block->m_size*Alignment - BlockCtrlBytes;
//Mark the block as allocated
block->m_next = 0;
//Check alignment
assert(((detail::char_ptr_cast(block) - detail::char_ptr_cast(this))
% Alignment) == 0 );
return detail::char_ptr_cast(block)+BlockCtrlBytes;
}
return 0;
}
template<class MutexFamily, class VoidPointer>
void simple_seq_fit_impl<MutexFamily, VoidPointer>::deallocate(void* addr)
{
if(!addr) return;
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
return this->priv_deallocate(addr);
}
template<class MutexFamily, class VoidPointer>
void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
{
if(!addr) return;
//Let's get free block list. List is always sorted
//by memory address to allow block merging.
//Pointer next always points to the first
//(lower address) block
block_ctrl_ptr prev = &m_header.m_root;
block_ctrl_ptr pos = m_header.m_root.m_next;
block_ctrl_ptr block = reinterpret_cast<block_ctrl*>
(detail::char_ptr_cast(addr) - BlockCtrlBytes);
//All used blocks' next is marked with 0 so check it
assert(block->m_next == 0);
//Check if alignment and block size are right
assert((detail::char_ptr_cast(addr) - detail::char_ptr_cast(this))
% Alignment == 0 );
std::size_t total_size = Alignment*block->m_size;
assert(m_header.m_allocated >= total_size);
//Update used memory count
m_header.m_allocated -= total_size;
//Let's find the previous and the next block of the block to deallocate
//This ordering comparison must be done with original pointers
//types since their mapping to raw pointers can be different
//in each process
while((detail::get_pointer(pos) != &m_header.m_root) && (block > pos)){
prev = pos;
pos = pos->m_next;
}
//Try to combine with upper block
if ((detail::char_ptr_cast(detail::get_pointer(block))
+ Alignment*block->m_size) ==
detail::char_ptr_cast(detail::get_pointer(pos))){
block->m_size += pos->m_size;
block->m_next = pos->m_next;
}
else{
block->m_next = pos;
}
//Try to combine with lower block
if ((detail::char_ptr_cast(detail::get_pointer(prev))
+ Alignment*prev->m_size) ==
detail::char_ptr_cast(detail::get_pointer(block))){
prev->m_size += block->m_size;
prev->m_next = block->m_next;
}
else{
prev->m_next = block;
}
}
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP

View File

@@ -0,0 +1,61 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MULTI_SIMPLE_SEQ_FIT_HPP
#define BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_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/mem_algo/detail/simple_seq_fit_impl.hpp>
#include <boost/interprocess/intersegment_ptr.hpp>
/*!\file
Describes sequential fit algorithm used to allocate objects in shared memory.
*/
namespace boost {
namespace interprocess {
/*!This class implements the simple sequential fit algorithm with a simply
linked list of free buffers.*/
template<class MutexFamily, class VoidPtr>
class multi_simple_seq_fit
: public detail::simple_seq_fit_impl<MutexFamily, VoidPtr>
{
typedef detail::simple_seq_fit_impl<MutexFamily, VoidPtr> base_t;
public:
/*!Constructor. "size" is the total size of the fixed size memory segment,
"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(multi_simple_seq_fit)
offset that the allocator should not use at all.*/
multi_simple_seq_fit (std::size_t size, std::size_t extra_hdr_bytes)
: base_t(size, extra_hdr_bytes){}
/*!Allocates bytes from existing segments. If there is no memory, it uses
the growing functor associated with the group to allocate a new segment.
If this fails, returns 0.*/
void* allocate (std::size_t nbytes)
{ return base_t::multi_allocate(nbytes); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP

View File

@@ -0,0 +1,55 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_SIMPLE_SEQ_FIT_HPP
#define BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_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/mem_algo/detail/simple_seq_fit_impl.hpp>
#include <boost/interprocess/offset_ptr.hpp>
/*!\file
Describes sequential fit algorithm used to allocate objects in shared memory.
*/
namespace boost {
namespace interprocess {
/*!This class implements the simple sequential fit algorithm with a simply
linked list of free buffers.*/
template<class MutexFamily, class VoidPointer>
class simple_seq_fit
: public detail::simple_seq_fit_impl<MutexFamily, VoidPointer>
{
typedef detail::simple_seq_fit_impl<MutexFamily, VoidPointer> base_t;
public:
/*!Constructor. "size" is the total size of the fixed size memory segment,
"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit)
offset that the allocator should not use at all.*/
simple_seq_fit (std::size_t size, std::size_t extra_hdr_bytes)
: base_t(size, extra_hdr_bytes){}
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP

View File

@@ -0,0 +1,407 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MEMORY_MAPPING_HPP
#define BOOST_INTERPROCESS_MEMORY_MAPPING_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/noncopyable.hpp>
#include <string>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <sys/mman.h> //mmap, off64_t
# include <unistd.h>
# include <sys/stat.h>
# else
# error Unknown platform
# endif
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes memory_mapping and mapped region classes
*/
namespace boost {
namespace interprocess {
class memory_mapping : private boost::noncopyable
{
public:
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef void * mapping_handle_t;
typedef long long mapping_offset_t;
enum { invalid_mapping_handle = 0 };
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef int mapping_handle_t;
typedef off64_t mapping_offset_t;
enum { invalid_mapping_handle = -1 };
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef enum { ro_mode = 0x01
, rw_mode = 0x02
, access_mode_mask = 0xff
} accessmode_t;
memory_mapping()
: m_handle(mapping_handle_t(invalid_mapping_handle))
{}
void assign_data(mapping_handle_t handle, accessmode_t mode)
{ m_handle = handle; m_mode = mode; }
mapping_handle_t get_mapping_handle() const
{ return m_handle; }
/*!Returns access mode*/
accessmode_t get_mode() const
{ return m_mode; }
virtual ~memory_mapping() = 0;
private:
mapping_handle_t m_handle;
accessmode_t m_mode;
};
inline memory_mapping::~memory_mapping()
{}
class mapped_region : private boost::noncopyable
{
typedef memory_mapping::mapping_offset_t mapping_offset_t;
public:
/*!Creates a mapping region of the mapped memory "mapping", starting in
offset "offset", and the mapping's size will be "size". The mapping
can be opened for read-only "memory_mapping::ro_mode" or read-write
"memory_mapping::rw_mode.*/
mapped_region(const memory_mapping& mapping
,memory_mapping::mapping_offset_t offset
,std::size_t size
,memory_mapping::accessmode_t mode
,const void *address = 0);
/*!Default constructor. Address and size and offset will be 0. Does not throw*/
mapped_region();
/*!Destroys the mapped region. Does not throw*/
~mapped_region();
/*!Returns the size of the mapping. Never throws.*/
std::size_t get_size() const;
/*!Returns the base address of the mapping. Never throws.*/
void* get_address() const;
/*!Returns the offset of the mapping from the beginning of the
mapped memory. Never throws.*/
mapping_offset_t get_offset() const;
/*!Flushes to the disk a byte range within the mapped memory.
Never throws*/
bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0);
/*!Swaps the mapped_region with another mapped region*/
void swap(mapped_region &other);
friend void swap(mapped_region &x, mapped_region &y)
{ x.swap(y); }
private:
/*!Closes a previously opened memory mapping. Never throws.*/
void priv_close();
void* m_base;
std::size_t m_size;
mapping_offset_t m_offset;
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
mapping_offset_t m_extra_offset;
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
};
inline mapped_region::mapped_region()
: m_base(0), m_size(0), m_offset(0)
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
, m_extra_offset(0)
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
// empty
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
{}
inline mapped_region::~mapped_region()
{ this->priv_close(); }
inline std::size_t mapped_region::get_size() const
{ return m_size; }
inline mapped_region::mapping_offset_t mapped_region::get_offset() const
{ return m_offset; }
inline void* mapped_region::get_address() const
{ return m_base; }
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline mapped_region::mapped_region
(const memory_mapping &mapping
,mapped_region::mapping_offset_t offset
,std::size_t size
,memory_mapping::accessmode_t mode
,const void *address)
: m_base(0)
{
if(size == 0){
__int64 total_size;
if(!winapi::get_file_size(mapping.get_mapping_handle(), total_size)){
error_info err(winapi::get_last_error());
throw interprocess_exception(err);
}
if(total_size > (__int64)((std::size_t)(-1))){
error_info err(size_error);
throw interprocess_exception(err);
}
size = static_cast<std::size_t>(total_size - offset);
}
unsigned long file_map_access = 0;
//Set accesses
if (mode == memory_mapping::rw_mode){
file_map_access |= winapi::page_readwrite;
}
else if (mode == memory_mapping::ro_mode){
file_map_access |= winapi::page_readonly;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
//Create file mapping
memory_mapping::mapping_handle_t hnd =
winapi::create_file_mapping
(mapping.get_mapping_handle(), file_map_access, 0, 0, 0);
//Check if all is correct
if(!hnd){
error_info err = winapi::get_last_error();
this->priv_close();
throw interprocess_exception(err);
}
//We can't map any offset so we have to obtain system's
//memory granularity
unsigned long granularity = 0;
unsigned long foffset_low;
unsigned long foffset_high;
winapi::system_info info;
get_system_info(&info);
granularity = info.dwAllocationGranularity;
//Now we calculate valid offsets
foffset_low = (unsigned long)(offset / granularity) * granularity;
foffset_high = (unsigned long)(((offset / granularity) * granularity) >> 32);
//We calculate the difference between demanded and valid offset
m_extra_offset = (offset - (offset / granularity) * granularity);
//Store user values in memory
m_offset = offset;
m_size = size;
unsigned long map_access = 0;
if (mode == memory_mapping::rw_mode){
map_access |= winapi::file_map_write;
}
else if (mode == memory_mapping::ro_mode){
map_access |= winapi::file_map_read;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
//Map with new offsets and size
m_base = winapi::map_view_of_file_ex
(hnd,
map_access,
foffset_high,
foffset_low,
static_cast<std::size_t>(m_extra_offset + m_size),
(void*)address);
//We don't need the file mapping anymore
winapi::close_handle(hnd);
//Check error
if(!m_base){
error_info err = winapi::get_last_error();
this->priv_close();
throw interprocess_exception(err);
}
//Calculate new base for the user
m_base = reinterpret_cast<char*>(m_base) + m_extra_offset;
}
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
{
//Check some errors
if(m_base == 0)
return false;
if(mapping_offset >= m_size || (mapping_offset+numbytes)> m_size){
return false;
}
if(numbytes == 0){
numbytes = m_size-mapping_offset;
}
//Flush it all
return 0 == winapi::flush_view_of_file
(reinterpret_cast<char*>(m_base)+mapping_offset,
static_cast<std::size_t>(numbytes));
}
inline void mapped_region::priv_close()
{
if(m_base){
this->flush();
winapi::unmap_view_of_file(reinterpret_cast<char*>(m_base) - m_extra_offset);
m_base = 0;
}
}
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline mapped_region::mapped_region
(const memory_mapping &mapping,
mapped_region::mapping_offset_t offset,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *address)
: m_base(MAP_FAILED)
{
if(size == 0){
mapping_offset_t filesize = lseek64(mapping.get_mapping_handle(), offset, SEEK_END);
if(filesize == -1 ){
error_info err(system_error_code());
throw interprocess_exception(err);
}
if(offset >= filesize){
error_info err(size_error);
throw interprocess_exception(err);
}
filesize -= offset;
size = (size_t)filesize;
if((mapping_offset_t)size != filesize){
error_info err(size_error);
throw interprocess_exception(err);
}
}
//Create new mapping
int prot = PROT_READ;
if(mode == memory_mapping::ro_mode){
}
else if(mode == memory_mapping::rw_mode){
prot |= PROT_WRITE;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
//Map it to the address space
m_base = mmap64( (void*)address
, size
, prot
, MAP_SHARED
, mapping.get_mapping_handle()
, offset);
m_offset = offset;
m_size = size;
//Check if mapping was successful
if(m_base == MAP_FAILED){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
}
inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
{
if(mapping_offset >= m_size || (mapping_offset+numbytes)> m_size){
return false;
}
if(numbytes == 0){
numbytes = m_size - mapping_offset;
}
//Flush it all
return msync(reinterpret_cast<char*>(m_base)+mapping_offset,
numbytes, MS_SYNC) == 0;
}
inline void mapped_region::priv_close()
{
if(m_base != MAP_FAILED){
this->flush();
munmap(m_base, m_size);
m_base = MAP_FAILED;
}
}
#endif //##if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline void mapped_region::swap(mapped_region &other)
{
detail::do_swap(this->m_base, other.m_base);
detail::do_swap(this->m_size, other.m_size);
detail::do_swap(this->m_offset, other.m_offset);
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
detail::do_swap(this->m_extra_offset, other.m_extra_offset);
#else
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
}
/*!No-op functor*/
struct null_mapped_region_function
{
bool operator()(const mapped_region &region, bool) const
{ return true; }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MEMORY_MAPPING_HPP

View File

@@ -0,0 +1,336 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_OFFSET_PTR_HPP
#define BOOST_OFFSET_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/cast_tags.hpp>
#include <boost/assert.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
/*!\file
Describes a smart pointer that stores the offset between this pointer and
target pointee, called offset_ptr.
*/
namespace boost {
namespace interprocess {
/*!A smart pointer that stores the offset between between the pointer and the
the object it points. This allows offset allows special properties, since
the pointer is independent from the address address of the pointee, if the
pointer and the pointee are still separated by the same offset. This feature
converts offset_ptr in a smart pointer that can be placed in shared memory and
memory mapped files mapped in different addresses in every process.*/
template <class PointedType>
class offset_ptr
{
typedef boost::interprocess::workaround::random_it<PointedType> random_it_t;
typedef offset_ptr<PointedType> self_t;
typedef typename random_it_t::const_pointer const_pointer_t;
typedef typename random_it_t::const_reference const_reference_t;
void unspecified_bool_type_func() const {}
typedef void (self_t::*unspecified_bool_type)() const;
void set_offset(const void *ptr)
{
//offset == 1 && ptr != 0 is not legal for this pointer
if(ptr){
m_offset = detail::char_ptr_cast(ptr) -
detail::char_ptr_cast(this);
BOOST_ASSERT(m_offset != 1);
}
else{
m_offset = 1;
}
}
void inc_offset(std::ptrdiff_t bytes)
{ m_offset += bytes; }
void dec_offset(std::ptrdiff_t bytes)
{ m_offset -= bytes; }
void* get_pointer(void) const
{ return m_offset == 1 ? 0 : detail::char_ptr_cast(this) + m_offset; }
std::ptrdiff_t m_offset; //Distance between this object and pointed address
public:
typedef typename random_it_t::pointer pointer;
typedef typename random_it_t::reference reference;
typedef typename random_it_t::value_type value_type;
typedef typename random_it_t::difference_type difference_type;
typedef typename random_it_t::iterator_category iterator_category;
public: //Public Functions
/*!Constructor from raw pointer (allows "0" pointer conversion). Never throws.*/
offset_ptr(pointer ptr = 0) { this->set_offset(ptr); }
/*!Constructor from other pointer. Never throws.*/
template <class T>
offset_ptr(T *ptr)
{ pointer p (ptr); (void)p; this->set_offset(ptr); }
/*!Constructor from other offset_ptr */
offset_ptr(const offset_ptr& ptr)
{ this->set_offset(ptr.get()); }
/*!Constructor from other offset_ptr. If pointers of pointee types are
convertible, offset_ptrs will be convertibles. Never throws.*/
template<class T2>
offset_ptr(const offset_ptr<T2> &ptr)
{ pointer p(ptr.get()); (void)p; this->set_offset(ptr.get()); }
/*!Emulates static_cast operator. Never throws. */
template<class Y>
offset_ptr(const offset_ptr<Y> & r, detail::static_cast_tag)
{ this->set_offset(static_cast<PointedType*>(r.get())); }
/*!Emulates const_cast operator. Never throws.*/
template<class Y>
offset_ptr(const offset_ptr<Y> & r, detail::const_cast_tag)
{ this->set_offset(const_cast<PointedType*>(r.get())); }
/*!Emulates dynamic_cast operator. Never throws.*/
template<class Y>
offset_ptr(const offset_ptr<Y> & r, detail::dynamic_cast_tag)
{ this->set_offset(dynamic_cast<PointedType*>(r.get())); }
/*!Emulates reinterpret_cast operator. Never throws.*/
template<class Y>
offset_ptr(const offset_ptr<Y> & r, detail::reinterpret_cast_tag)
{ this->set_offset(reinterpret_cast<PointedType*>(r.get())); }
/*!Obtains raw pointer from offset. Never throws.*/
pointer get()const
{ return (pointer)this->get_pointer(); }
/*!Pointer-like -> operator. It can return 0 pointer. Never throws.*/
pointer operator->() const
{ return this->get(); }
/*!Dereferencing operator, if it is a null offset_ptr behavior
is undefined. Never throws.*/
reference operator* () const
{ return *(this->get()); }
/*!Indexing operator. Never throws.*/
reference operator[](std::ptrdiff_t idx) const
{ return this->get()[idx]; }
/*!Assignment from pointer (saves extra conversion). Never throws.*/
offset_ptr& operator= (pointer from)
{ this->set_offset(from); return *this; }
/*!Assignment from other offset_ptr. Never throws.*/
offset_ptr& operator= (const offset_ptr & pt)
{ pointer p(pt.get()); (void)p; this->set_offset(pt.get()); return *this; }
/*!Assignment from related offset_ptr. If pointers of pointee types
are assignable, offset_ptrs will be assignable. Never throws.*/
template <class T2>
offset_ptr& operator= (const offset_ptr<T2> & pt)
{ this->set_offset(pt.get()); return *this; }
/*!offset_ptr + std::ptrdiff_t. Never throws.*/
offset_ptr operator+ (std::ptrdiff_t offset) const
{ return offset_ptr(this->get()+offset); }
/*!offset_ptr - std::ptrdiff_t. Never throws.*/
offset_ptr operator- (std::ptrdiff_t offset) const
{ return offset_ptr(this->get()-offset); }
/*!offset_ptr += std::ptrdiff_t. Never throws.*/
offset_ptr &operator+= (std::ptrdiff_t offset)
{ this->inc_offset(offset * sizeof (PointedType)); return *this; }
/*!offset_ptr -= std::ptrdiff_t. Never throws.*/
offset_ptr &operator-= (std::ptrdiff_t offset)
{ this->dec_offset(offset * sizeof (PointedType)); return *this; }
/*!++offset_ptr. Never throws.*/
offset_ptr& operator++ (void)
{ this->inc_offset(sizeof (PointedType)); return *this; }
/*!offset_ptr++. Never throws.*/
offset_ptr operator++ (int)
{ offset_ptr temp(*this); ++*this; return temp; }
/*!--offset_ptr. Never throws.*/
offset_ptr& operator-- (void)
{ this->dec_offset(sizeof (PointedType)); return *this; }
/*!offset_ptr--. Never throws.*/
offset_ptr operator-- (int)
{ offset_ptr temp(*this); --*this; return temp; }
/*!safe bool conversion operator. Never throws.*/
operator unspecified_bool_type() const
{ return this->get()? &self_t::unspecified_bool_type_func : 0; }
/*!Not operator. Not needed in theory, but improves portability.
Never throws.*/
bool operator! () const
{ return this->get() == 0; }
/*
friend void swap (offset_ptr &pt, offset_ptr &pt2)
{
value_type *ptr = pt.get();
pt = pt2;
pt2 = ptr;
}
*/
};
/*!offset_ptr<T1> == offset_ptr<T2>. Never throws.*/
template<class T1, class T2>
inline bool operator== (const offset_ptr<T1> &pt1,
const offset_ptr<T2> &pt2)
{ return pt1.get() == pt2.get(); }
/*!offset_ptr<T1> != offset_ptr<T2>. Never throws.*/
template<class T1, class T2>
inline bool operator!= (const offset_ptr<T1> &pt1,
const offset_ptr<T2> &pt2)
{ return pt1.get() != pt2.get(); }
/*!offset_ptr<T1> < offset_ptr<T2>. Never throws.*/
template<class T1, class T2>
inline bool operator< (const offset_ptr<T1> &pt1,
const offset_ptr<T2> &pt2)
{ return pt1.get() < pt2.get(); }
/*!offset_ptr<T1> <= offset_ptr<T2>. Never throws.*/
template<class T1, class T2>
inline bool operator<= (const offset_ptr<T1> &pt1,
const offset_ptr<T2> &pt2)
{ return pt1.get() <= pt2.get(); }
/*!offset_ptr<T1> > offset_ptr<T2>. Never throws.*/
template<class T1, class T2>
inline bool operator> (const offset_ptr<T1> &pt1,
const offset_ptr<T2> &pt2)
{ return pt1.get() > pt2.get(); }
/*!offset_ptr<T1> >= offset_ptr<T2>. Never throws.*/
template<class T1, class T2>
inline bool operator>= (const offset_ptr<T1> &pt1,
const offset_ptr<T2> &pt2)
{ return pt1.get() >= pt2.get(); }
/*!operator<< */
template<class E, class T, class Y>
inline std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, offset_ptr<Y> const & p)
{ return os << p.get(); }
/*!operator>> */
template<class E, class T, class Y>
inline std::basic_istream<E, T> & operator>>
(std::basic_istream<E, T> & os, offset_ptr<Y> & p)
{ Y * tmp; return os >> tmp; p = tmp; }
/*!std::ptrdiff_t + offset_ptr */
template<class T>
inline offset_ptr<T> operator+(std::ptrdiff_t diff, const offset_ptr<T>& right)
{ return right + diff; }
/*!offset_ptr - offset_ptr */
template<class T, class T2>
inline std::ptrdiff_t operator- (const offset_ptr<T> &pt, const offset_ptr<T2> &pt2)
{ return pt.get()- pt2.get(); }
/*!swap specialization */
template<class T>
inline void swap (boost::interprocess::offset_ptr<T> &pt,
boost::interprocess::offset_ptr<T> &pt2)
{
typename offset_ptr<T>::value_type *ptr = pt.get();
pt = pt2;
pt2 = ptr;
}
/*!get_pointer() enables boost::mem_fn to recognize offset_ptr.
Never throws.*/
template<class T>
inline T * get_pointer(boost::interprocess::offset_ptr<T> const & p)
{ return p.get(); }
/*!Simulation of static_cast between pointers. Never throws.*/
template<class T, class U>
inline boost::interprocess::offset_ptr<T>
static_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
{
return boost::interprocess::offset_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::offset_ptr<T>
const_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
{
return boost::interprocess::offset_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::offset_ptr<T>
dynamic_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
{
return boost::interprocess::offset_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::offset_ptr<T>
reinterpret_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
{
return boost::interprocess::offset_ptr<T>
(r, boost::interprocess::detail::reinterpret_cast_tag());
}
} //namespace interprocess {
/*!has_trivial_constructor<> == true_type specialization for optimizations*/
template <class T>
struct has_trivial_constructor
< boost::interprocess::offset_ptr<T> >
: public true_type
{};
/*!has_trivial_destructor<> == true_type specialization for optimizations*/
template <class T>
struct has_trivial_destructor
< boost::interprocess::offset_ptr<T> >
: public true_type
{};
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_OFFSET_PTR_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,704 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MEMORY_HPP
#define BOOST_INTERPROCESS_MEMORY_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/type_with_alignment.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/noncopyable.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/function.hpp>
#include <boost/interprocess/detail/global_lock.hpp>
#include <boost/compatibility/cpp_c_headers/cstddef>
#include <boost/interprocess/memory_mapping.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h> //O_CREAT, O_*...
# include <sys/mman.h> //mmap
# include <unistd.h> //ftruncate, close
# include <semaphore.h> //sem_t* family, SEM_VALUE_MAX
# include <string> //std::string
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
# else
# error Unknown platform
# endif
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes shared_memory class
*/
namespace boost {
namespace interprocess {
/*!A class that wraps a shared memory mapping that can be used to
create mapped regions from the mapped files*/
class shared_memory_mapping : public memory_mapping
{
enum type_t { DoCreate, DoOpen, DoCreateOrOpen };
public:
/*!Opens a file mapping of file "filename", starting in offset
"file_offset", and the mapping's size will be "size". The mapping
can be opened for read-only "ro_mode" or read-write "rw_mode. modes.*/
// shared_memory_mapping(const char *filename, memory_mapping::accessmode_t mode);
// Creates a shared memory object with name "name" and size "size", with the access mode "mode"
// If the file previously exists, throws an error
shared_memory_mapping(detail::create_only_t, const char *name, memory_mapping::accessmode_t mode)
{ this->priv_open_or_create(DoCreate, name, mode); }
// Tries to create a shared memory object with name "name" and size "size", with the
// access mode "mode". If the file previously exists, it tries to open it with mode "mode".
// Otherwise throws an error.
shared_memory_mapping(detail::open_or_create_t, const char *name, memory_mapping::accessmode_t mode)
{ this->priv_open_or_create(DoCreateOrOpen, name, mode); }
// Tries to open a shared memory object with name "name", with the access mode "mode".
// If the file does not previously exist, it throws an error.
shared_memory_mapping(detail::open_only_t, const char *name, memory_mapping::accessmode_t mode)
{ this->priv_open_or_create(DoOpen, name, mode); }
// Erases a shared memory object from the system.
static bool remove(const char *name);
//Sets the size of the shared memory mapping
void truncate(memory_mapping::mapping_offset_t length);
// Closes the shared memory mapping. All mapped regions are still
// valid after destruction. The shared memory object still exists and
// can be newly opened.
~shared_memory_mapping();
/*!Returns the name of the file.*/
const char *get_name() const;
/*!Return access mode*/
accessmode_t get_mode() const;
/*!Get mapping handle*/
mapping_handle_t get_mapping_handle() const;
private:
/*!Closes a previously opened file mapping. Never throws.*/
void priv_close();
bool priv_open_or_create(type_t type, const char *filename,
memory_mapping::accessmode_t mode);
std::string m_filename;
};
inline shared_memory_mapping::~shared_memory_mapping()
{ this->priv_close(); }
/*!Returns the name of the file.*/
inline const char *shared_memory_mapping::get_name() const
{ return m_filename.c_str(); }
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline bool shared_memory_mapping::priv_open_or_create
(type_t type,
const char *filename,
memory_mapping::accessmode_t mode)
{
m_filename = filename;
//Make sure a temporary path is created for shared memory
const unsigned long BufferSize = 512;
std::string shmfile;
shmfile.resize(BufferSize);
unsigned long n = winapi::get_temp_path(BufferSize, &shmfile[0]);
if(n > BufferSize){
shmfile.resize(n);
n = winapi::get_temp_path(n, &shmfile[0]);
}
if(!n){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
//Remove final null.
shmfile.resize(n);
shmfile += "boost_interprocess\\";
if(!winapi::create_directory(shmfile.c_str(), 0)){
unsigned long err = winapi::get_last_error();
if(err != winapi::error_already_exists){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
}
shmfile += filename;
unsigned long file_access = 0;
unsigned long file_creation_flags = 0;
//Set accesses
if (mode == rw_mode){
file_access |= winapi::generic_read | winapi::generic_write;
}
else if (mode == ro_mode){
file_access |= winapi::generic_read;
}
switch(type){
case DoOpen:
file_creation_flags = winapi::open_existing;
break;
case DoCreate:
file_creation_flags = winapi::create_new;
break;
case DoCreateOrOpen:
file_creation_flags = winapi::open_always;
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Open file using windows API since we need the handle
memory_mapping::mapping_handle_t hnd = winapi::create_file
(shmfile.c_str(), file_access, file_creation_flags, winapi::file_attribute_temporary);
//Check for error
if(hnd == winapi::invalid_handle_value){
error_info err = winapi::get_last_error();
this->priv_close();
throw interprocess_exception(err);
}
memory_mapping::assign_data(hnd, mode);
return true;
}
inline bool shared_memory_mapping::remove(const char *filename)
{
try{
//Make sure a temporary path is created for shared memory
const unsigned long BufferSize = 512;
std::string shmfile;
shmfile.resize(BufferSize);
unsigned long n = winapi::get_temp_path(BufferSize, &shmfile[0]);
if(n > BufferSize){
shmfile.resize(n);
n = winapi::get_temp_path(n, &shmfile[0]);
}
if(!n){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
//Remove final null.
shmfile.resize(n);
shmfile += "boost_interprocess\\";
shmfile += filename;
return std::remove(shmfile.c_str()) == 0;
}
catch(...){
return false;
}
}
inline void shared_memory_mapping::truncate(memory_mapping::mapping_offset_t length)
{
if(!winapi::set_file_pointer_ex( memory_mapping::get_mapping_handle(), length
, 0, winapi::file_begin)){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
if(!winapi::set_end_of_file(memory_mapping::get_mapping_handle())){
error_info err = winapi::get_last_error();
throw interprocess_exception(err);
}
}
inline void shared_memory_mapping::priv_close()
{
if(memory_mapping::get_mapping_handle() != winapi::invalid_handle_value){
winapi::close_handle(memory_mapping::get_mapping_handle());
memory_mapping::assign_data
(winapi::invalid_handle_value, memory_mapping::get_mode());
}
}
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
inline bool shared_memory_mapping::priv_open_or_create
(type_t type,
const char *filename,
memory_mapping::accessmode_t mode)
{
m_filename = filename;
//Create new mapping
int oflag = 0;
if(mode == memory_mapping::ro_mode){
oflag |= O_RDONLY;
}
else if(mode == memory_mapping::rw_mode){
oflag |= O_RDWR;
}
else{
error_info err(mode_error);
throw interprocess_exception(err);
}
switch(type){
case DoOpen:
//No addition
break;
case DoCreate:
oflag |= (O_CREAT | O_EXCL);
break;
case DoCreateOrOpen:
oflag |= O_CREAT;
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Open file using windows API since we need the handle
memory_mapping::mapping_handle_t hnd = shm_open
(filename, oflag, S_IRWXO | S_IRWXG | S_IRWXU);
//Check for error
if(hnd == -1){
error_info err = errno;
this->priv_close();
throw interprocess_exception(err);
}
memory_mapping::assign_data(hnd, mode);
return true;
}
inline bool shared_memory_mapping::remove(const char *filename)
{
return 0 != shm_unlink(filename);
}
inline void shared_memory_mapping::truncate(memory_mapping::mapping_offset_t length)
{
if(0 != ftruncate(memory_mapping::get_mapping_handle(), length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void shared_memory_mapping::priv_close()
{
if(memory_mapping::get_mapping_handle() != -1){
::close(memory_mapping::get_mapping_handle());
memory_mapping::assign_data
(-1, memory_mapping::get_mode());
}
}
#endif //##if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!A class that wraps basic shared memory management*/
class shared_memory : private boost::noncopyable
{
enum type_t { DoCreate, DoOpen, DoCreateOrOpen };
shared_memory();
public:
/*!Creates a shared memory segment with name "name", with size "size".
If the segment was previously created it throws an error.
The segment can be created in two modes: read-only "ro_mode" or read-write "rw_mode".
The user can also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
shared_memory(detail::create_only_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode = memory_mapping::rw_mode,
const void *addr = 0);
/*!Opens a shared memory segment with name "name". If it was previously
created throws an error.
The segment can be opened in two modes: read-only "ro_mode" or read-write "rw_mode".
The user can also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
shared_memory(detail::open_only_t,
const char *name,
memory_mapping::accessmode_t mode = memory_mapping::rw_mode,
const void *addr = 0);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created it tries to open it. User can specify the mapping address in "addr".
The segment can be opened in two modes: read-only "ro_mode" or read-write "rw_mode".
If "addr" is 0, the operating system will choose the mapping address.
This function can throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc)*/
shared_memory(detail::open_or_create_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode = memory_mapping::rw_mode,
const void *addr = 0);
/*!Creates a shared memory segment with name "name", with size "size".
The user must also specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
It also executes a copy of the functor "construct_func" atomically if
the segment is created. The functor must have the following signature:
bool operator()(const segment_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
must be "true". If the functor returns "false", or throws an error
is supposed and the shared memory won't be created.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const segment_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
shared_memory(detail::create_only_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created tries to open it.
User must specify the mapping address in "addr". If "addr" is 0,
the operating system will choose the mapping address.
It also executes a copy of the functor "construct_func" atomically
if the segment is opened. The functor must have the following signature:
bool operator()(const segment_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
must be "false". If the functor returns "false", or throws an error
is supposed and the shared memory won't be opened.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const segment_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
shared_memory(detail::open_only_t,
const char *name,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_funcc);
/*!Creates a shared memory segment with name "name", and size "size" if
the shared memory was not previously created. If it was previously
created it tries to open it. User can specify the mapping address in "addr".
If "addr" is 0, the operating system will choose the mapping address.
It also executes the functor "construct_func" atomically if the segment is
created or opened. The functor must have the following signature:
bool operator()(const segment_info_t * info, bool created)
"info" is an initialized segment info structure, and "created"
will be "true" if the shared memory was created. If the functor
returns "false", or throws an error is supposed and the
shared memory won't be opened.
The user must specify a destroy_func, that will be copied in this
constructor and executed in the destructor, before unmapping the
shared memory segment.
The functor must have the following signature:
void operator()(const segment_info_t * info, bool last) const
"info" is an initialized segment info structure, and "last"
indicates if this unmapping is the last unmapping so that
there will be no no other processes attached to the segment.
The functor must NOT throw.
This function can throw if copying any functor throws,
the construct_func execution throws, and it
will throw boost::inteprocess_exception and
other standard exceptions derived from std::exception
(like std::bad_alloc) on any error*/
template <class ConstructFunc>
shared_memory(detail::open_or_create_t,
const char *name,
std::size_t size,
memory_mapping::accessmode_t mode,
const void *addr,
const ConstructFunc &construct_func);
/*!Destructor. Unmaps shared memory from process' address space.
It also executes the destruction functor atomically if
the user has registered that the destruction functor
in the constructor of this class.
Never throws.*/
~shared_memory();
/*!Returns the size of the shared memory segment. Never throws.*/
std::size_t get_size() const;
/*!Returns shared memory segment's address for this process.
Never throws.*/
void* get_address() const;
/*!Swaps the shared memory segment this shared_memory object
manages with another managed by "other".
Never throws.*/
void swap(shared_memory &other);
/*!Returns the name of the shared memory segment used in the
constructor. Never throws.*/
const char *get_name() const;
/*!Erases a shared memory object from the system.*/
static bool remove(const char *name);
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef void * OS_handle_t;
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef int OS_handle_t;
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!Returns the handle that identifies the shared memory
segment in a operating system. This is operating system
and implementation dependent and should be used only
in special situations.
Never throws.*/
OS_handle_t get_OS_handle() const;
private:
template <class ConstructFunc>
bool priv_open_or_create(type_t type, const char *name, std::size_t size,
memory_mapping::accessmode_t mode, const void *addr,
ConstructFunc construct_func);
mapped_region m_mapped_region;
std::string m_name;
};
inline shared_memory::shared_memory
(detail::create_only_t, const char *name, std::size_t size,
memory_mapping::accessmode_t mode, const void *addr)
{
this->priv_open_or_create(DoCreate, name, size, mode, addr, null_mapped_region_function());
}
inline shared_memory::shared_memory
(detail::open_only_t, const char *name,
memory_mapping::accessmode_t mode, const void *addr)
{
this->priv_open_or_create(DoOpen, name, 0, mode, addr, null_mapped_region_function());
}
inline shared_memory::shared_memory
(detail::open_or_create_t, const char *name, std::size_t size,
memory_mapping::accessmode_t mode, const void *addr)
{
this->priv_open_or_create(DoCreateOrOpen, name, size, mode, addr, null_mapped_region_function());
}
template <class ConstructFunc>
inline shared_memory::shared_memory
(detail::create_only_t, const char *name, std::size_t size,
memory_mapping::accessmode_t mode, const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoCreate, name, size, mode, addr, construct_func);
}
template <class ConstructFunc>
inline shared_memory::shared_memory
(detail::open_only_t, const char *name,
memory_mapping::accessmode_t mode, const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoOpen, name, 0, mode, addr, construct_func);
}
template <class ConstructFunc>
inline shared_memory::shared_memory
(detail::open_or_create_t, const char *name, std::size_t size,
memory_mapping::accessmode_t mode, const void *addr,
const ConstructFunc &construct_func)
{
this->priv_open_or_create(DoCreateOrOpen, name, size, mode, addr, construct_func);
}
/*!Erases a shared memory object from the system.*/
inline bool shared_memory::remove(const char *name)
{ return shared_memory_mapping::remove(name); }
inline shared_memory::~shared_memory()
{}
inline std::size_t shared_memory::get_size() const
{ return m_mapped_region.get_size(); }
inline void* shared_memory::get_address() const
{ return m_mapped_region.get_address(); }
inline const char *shared_memory::get_name() const
{ return m_name.c_str(); }
inline void shared_memory::swap(shared_memory &other)
{
detail::do_swap(this->m_name, other.m_name);
detail::do_swap(this->m_mapped_region, other.m_mapped_region);
}
inline void swap(shared_memory &x, shared_memory &y)
{ x.swap(y); }
template <class ConstructFunc> inline
bool shared_memory::priv_open_or_create
(shared_memory::type_t type, const char *name, std::size_t size,
memory_mapping::accessmode_t mode, const void *addr,
ConstructFunc construct_func)
{
error_info err;
m_name = name;
//This global interprocess_mutex guarantees synchronized creation/open logic
detail::global_lock mut;
if(!mut.acquire()){
#ifdef BOOST_NO_EXCEPTIONS
return false;
#else
throw interprocess_exception(err);
#endif
}
//shared_memory_mapping has no default constructor.
//And embedded system paranoids like me don't like dynamic memoryç
//boost::optional does not solve well in place factories
boost::optional<shared_memory_mapping> mapping;
//Do some in-place construction
bool created = false;
switch(type){
case DoOpen:
{
mapping = in_place(open_only, name, memory_mapping::rw_mode);
}
break;
case DoCreateOrOpen:
{
try{
mapping = in_place(create_only, name, memory_mapping::rw_mode);
mapping->truncate(size);
created = true;
}
catch(interprocess_exception &ex){
if(ex.get_error_code() != already_exists_error){
throw;
}
mapping = in_place(open_only, name, memory_mapping::rw_mode);
}
}
break;
case DoCreate:
{
mapping = in_place(create_only, name, memory_mapping::rw_mode);
mapping->truncate(size);
created = true;
}
break;
default:
break;
}
mapped_region mapped(*mapping, 0, size, /*file_mapping::rw_mode*/mode, addr);
//Now swap mapped region
m_mapped_region.swap(mapped);
//Execute atomic functor
construct_func(m_mapped_region, created);
return true;
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MEMORY_HPP

View File

@@ -0,0 +1,135 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_base_pt.hpp
//
//
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2006 Ion Gaztañaga
//
// 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)
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <typeinfo>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
namespace boost{
namespace interprocess{
namespace detail{
class sp_counted_base
{
private:
sp_counted_base( sp_counted_base const & );
sp_counted_base & operator= ( sp_counted_base const & );
long use_count_; // #shared
long weak_count_; // #weak + (#shared != 0)
mutable pthread_mutex_t m_mut;
public:
sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
{
detail::mutexattr_wrapper mut_attr;
detail::mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
~sp_counted_base() // nothrow
{
int res = pthread_mutex_destroy(&m_mut);
assert(res == 0);(void)res;
}
// dispose() is called when use_count_ drops to zero, to release
// the resources managed by *this.
/*
virtual void dispose() = 0; // nothrow
// destroy() is called when weak_count_ drops to zero.
virtual void destroy() // nothrow
{
delete this;
}
virtual void * get_deleter( std::type_info const & ti ) = 0;
*/
void add_ref_copy()
{
pthread_mutex_lock( &m_mut );
++use_count_;
pthread_mutex_unlock( &m_mut );
}
bool add_ref_lock() // true on success
{
pthread_mutex_lock( &m_mut );
bool r = use_count_ == 0? false: ( ++use_count_, true );
pthread_mutex_unlock( &m_mut );
return r;
}
bool ref_release() // nothrow
{
pthread_mutex_lock( &m_mut );
long new_use_count = --use_count_;
pthread_mutex_unlock( &m_mut );
return new_use_count == 0;
}
void weak_add_ref() // nothrow
{
pthread_mutex_lock( &m_mut );
++weak_count_;
pthread_mutex_unlock( &m_mut );
}
bool weak_release() // nothrow
{
pthread_mutex_lock( &m_mut );
long new_weak_count = --weak_count_;
pthread_mutex_unlock( &m_mut );
return new_weak_count == 0;
}
long use_count() const // nothrow
{
pthread_mutex_lock( &m_mut );
long r = use_count_;
pthread_mutex_unlock( &m_mut );
return r;
}
};
} // namespace detail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED

View File

@@ -0,0 +1,119 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_base_w32.hpp
//
//
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2006 Ion Gaztañaga
//
// 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)
//
//
// Lock-free algorithm by Alexander Terekhov
//
// Thanks to Ben Hitchings for the #weak + (#shared != 0)
// formulation
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#include <typeinfo>
namespace boost {
namespace interprocess {
namespace detail {
class sp_counted_base
{
private:
sp_counted_base( sp_counted_base const & );
sp_counted_base & operator= ( sp_counted_base const & );
long use_count_; // #shared
long weak_count_; // #weak + (#shared != 0)
public:
sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
{}
~sp_counted_base() // nothrow
{}
/*
// dispose() is called when use_count_ drops to zero, to release
// the resources managed by *this.
virtual void dispose() = 0; // nothrow
// destroy() is called when weak_count_ drops to zero.
virtual void destroy() // nothrow
{
delete this;
}
virtual void * get_deleter( std::type_info const & ti ) = 0;
*/
void add_ref_copy()
{
winapi::interlocked_increment( &use_count_ );
}
bool add_ref_lock() // true on success
{
for( ;; )
{
long tmp = static_cast< long const volatile& >( use_count_ );
if( tmp == 0 ) return false;
if( winapi::interlocked_compare_exchange( &use_count_, tmp + 1, tmp ) == tmp ) return true;
}
}
bool ref_release() // nothrow
{ return winapi::interlocked_decrement( &use_count_ ) == 0; }
/*
void release() // nothrow
{
if(ref_release()){
//dispose();
weak_release();
}
}
*/
void weak_add_ref() // nothrow
{ winapi::interlocked_increment( &weak_count_ ); }
bool weak_release() // nothrow
{ return winapi::interlocked_decrement( &weak_count_ ) == 0; }
long use_count() const // nothrow
{ return static_cast<long const volatile &>( use_count_ ); }
};
} // namespace detail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED

View File

@@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/detail/bad_weak_ptr.hpp
//
// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
// (C) Copyright Ion Gaztañaga 2006. 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_BAD_WEAK_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#ifndef BOOST_NO_EXCEPTIONS
#include <exception>
#endif
namespace boost{
namespace interprocess{
class bad_weak_ptr
: public std::exception
{
public:
virtual char const * what() const throw()
{ return "boost::interprocess::bad_weak_ptr"; }
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,317 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/detail/shared_count.hpp
//
// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
// (C) Copyright Peter Dimov 2004-2005
// (C) Copyright Ion Gaztañaga 2006. 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_DETAIL_SHARED_COUNT_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/checked_delete.hpp>
#include <boost/throw_exception.hpp>
#include <boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp>
#include <boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <functional>
#include <functional> // std::less
namespace boost {
namespace interprocess {
namespace detail{
template<class T, class A, class D>
class weak_count;
template<class T, class A, class D>
class shared_count
{
public:
typedef typename detail::pointer_to_other
<typename A::pointer, T>::type pointer;
private:
typedef sp_counted_impl_pd<A, D> counted_impl;
typedef typename detail::pointer_to_other
<typename A::pointer, counted_impl>::type counted_impl_ptr;
typedef typename detail::pointer_to_other
<typename A::pointer, sp_counted_base>::type counted_base_ptr;
typedef typename A::template rebind
<counted_impl>::other counted_impl_allocator;
typedef typename detail::pointer_to_other
<typename A::pointer, const D>::type const_deleter_pointer;
typedef typename detail::pointer_to_other
<typename A::pointer, const A>::type const_allocator_pointer;
pointer m_px;
counted_impl_ptr m_pi;
template <class T2, class A2, class D2>
friend class weak_count;
template <class T2, class A2, class D2>
friend class shared_count;
public:
shared_count()
: m_px(0), m_pi(0) // nothrow
{}
template <class Ptr>
shared_count(const Ptr &p, const A &a, D d)
: m_px(p), m_pi(0)
{
BOOST_TRY{
if(p){
counted_impl_allocator alloc(a);
m_pi = alloc.allocate(1);
//Anti-exception deallocator
scoped_ptr<counted_impl,
scoped_deallocator<counted_impl_allocator> >
deallocator(m_pi, alloc);
//It's more correct to use A::construct but
//this needs copy constructor and we don't like it
new(detail::get_pointer(m_pi))counted_impl(p, a, d);
deallocator.release();
}
}
BOOST_CATCH (...){
d(p); // delete p
throw;
}
BOOST_CATCH_END
}
~shared_count() // nothrow
{
if( m_pi != 0 )
m_pi->release();
}
shared_count(shared_count const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if( m_pi != 0 ) m_pi->add_ref_copy(); }
//this is a test
template<class Y>
explicit shared_count(shared_count<Y, A, D> const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if( m_pi != 0 ) m_pi->add_ref_copy(); }
//this is a test
template<class Y>
explicit shared_count(const pointer & ptr, shared_count<Y, A, D> const & r)
: m_px(ptr), m_pi(r.m_pi) // nothrow
{ if( m_pi != 0 ) m_pi->add_ref_copy(); }
/*
explicit shared_count(weak_count<Y, A, D> const & r)
// throws bad_weak_ptr when r.use_count() == 0
: m_pi( r.m_pi )
{
if( m_pi == 0 || !m_pi->add_ref_lock() ){
boost::throw_exception( boost::interprocess::bad_weak_ptr() );
}
}
*/
template<class Y>
explicit shared_count(weak_count<Y, A, D> const & r)
// throws bad_weak_ptr when r.use_count() == 0
: m_px(r.m_px), m_pi( r.m_pi )
{
if( m_pi == 0 || !m_pi->add_ref_lock() ){
boost::throw_exception( boost::interprocess::bad_weak_ptr() );
}
}
const pointer &get_pointer() const
{ return m_px; }
pointer &get_pointer()
{ return m_px; }
shared_count & operator= (shared_count const & r) // nothrow
{
m_px = r.m_px;
counted_impl_ptr tmp = r.m_pi;
if( tmp != m_pi ){
if(tmp != 0) tmp->add_ref_copy();
if(m_pi != 0) m_pi->release();
m_pi = tmp;
}
return *this;
}
template<class Y>
shared_count & operator= (shared_count<Y, A, D> const & r) // nothrow
{
m_px = r.m_px;
counted_impl_ptr tmp = r.m_pi;
if( tmp != m_pi ){
if(tmp != 0) tmp->add_ref_copy();
if(m_pi != 0) m_pi->release();
m_pi = tmp;
}
return *this;
}
void swap(shared_count & r) // nothrow
{ detail::do_swap(m_px, r.m_px); detail::do_swap(m_pi, r.m_pi); }
long use_count() const // nothrow
{ return m_pi != 0? m_pi->use_count(): 0; }
bool unique() const // nothrow
{ return use_count() == 1; }
const_deleter_pointer get_deleter() const
{ return m_pi ? m_pi->get_deleter() : 0; }
const_allocator_pointer get_allocator() const
{ return m_pi ? m_pi->get_allocator() : 0; }
template<class T2, class A2, class D2>
bool internal_equal (shared_count<T2, A2, D2> const & other) const
{ return this->m_pi == other.m_pi; }
template<class T2, class A2, class D2>
bool internal_less (shared_count<T2, A2, D2> const & other) const
{ return std::less<counted_base_ptr>()(this->m_pi, other.m_pi); }
};
template<class T, class A, class D, class T2, class A2, class D2> inline
bool operator==(shared_count<T, A, D> const & a, shared_count<T2, A2, D2> const & b)
{ return a.internal_equal(b); }
template<class T, class A, class D, class T2, class A2, class D2> inline
bool operator<(shared_count<T, A, D> const & a, shared_count<T2, A2, D2> const & b)
{ return a.internal_less(b); }
template<class T, class A, class D>
class weak_count
{
public:
typedef typename detail::pointer_to_other
<typename A::pointer, T>::type pointer;
private:
typedef sp_counted_impl_pd<A, D> counted_impl;
typedef typename detail::pointer_to_other
<typename A::pointer, counted_impl>::type counted_impl_ptr;
typedef typename detail::pointer_to_other
<typename A::pointer, sp_counted_base>::type counted_base_ptr;
pointer m_px;
counted_impl_ptr m_pi;
template <class T2, class A2, class D2>
friend class weak_count;
template <class T2, class A2, class D2>
friend class shared_count;
public:
weak_count(): m_px(0), m_pi(0) // nothrow
{}
template <class Y>
explicit weak_count(shared_count<Y, A, D> const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if(m_pi != 0) m_pi->weak_add_ref(); }
weak_count(weak_count const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if(m_pi != 0) m_pi->weak_add_ref(); }
template<class Y>
weak_count(weak_count<Y, A, D> const & r)
: m_px(r.m_px), m_pi(r.m_pi) // nothrow
{ if(m_pi != 0) m_pi->weak_add_ref(); }
~weak_count() // nothrow
{ if(m_pi != 0) m_pi->weak_release(); }
template<class Y>
weak_count & operator= (shared_count<Y, A, D> const & r) // nothrow
{
m_px = r.m_px;
counted_impl_ptr tmp = r.m_pi;
if(tmp != 0) tmp->weak_add_ref();
if(m_pi != 0) m_pi->weak_release();
m_pi = tmp;
return *this;
}
weak_count & operator= (weak_count const & r) // nothrow
{
counted_impl_ptr tmp = r.m_pi;
if(tmp != 0) tmp->weak_add_ref();
if(m_pi != 0) m_pi->weak_release();
m_pi = tmp;
return *this;
}
void set_pointer(const pointer &ptr)
{ m_px = ptr; }
template<class Y>
weak_count & operator= (weak_count<Y, A, D> const& r) // nothrow
{
counted_impl_ptr tmp = r.m_pi;
if(tmp != 0) tmp->weak_add_ref();
if(m_pi != 0) m_pi->weak_release();
m_pi = tmp;
return *this;
}
void swap(weak_count & r) // nothrow
{ detail::do_swap(m_px, r.m_px); detail::do_swap(m_pi, r.m_pi); }
long use_count() const // nothrow
{ return m_pi != 0? m_pi->use_count() : 0; }
template<class T2, class A2, class D2>
bool internal_equal (weak_count<T2, A2, D2> const & other) const
{ return this->m_pi == other.m_pi; }
template<class T2, class A2, class D2>
bool internal_less (weak_count<T2, A2, D2> const & other) const
{ return std::less<counted_base_ptr>()(this->m_pi, other.m_pi); }
};
template<class T, class A, class D, class T2, class A2, class D2> inline
bool operator==(weak_count<T, A, D> const & a, weak_count<T2, A2, D2> const & b)
{ return a.internal_equal(b); }
template<class T, class A, class D, class T2, class A2, class D2> inline
bool operator<(weak_count<T, A, D> const & a, weak_count<T2, A2, D2> const & b)
{ return a.internal_less(b); }
} // namespace detail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED

View File

@@ -0,0 +1,44 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_base.hpp
//
// Copyright 2005 Peter Dimov
// Copyright 2006 Ion Gaztañaga
//
// 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)
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
# include <boost/interprocess/smart_ptr/detail/sp_counted_base_w32.hpp>
#elif defined( BOOST_HAS_PTHREADS )
//Ordinary pthreads counted base is not enough
//we need process shared attributte.
# include <boost/interprocess/smart_ptr/detail/sp_counted_base_pt.hpp>
#else
// Use #define BOOST_DISABLE_THREADS to avoid the error
# error Unrecognized threading platform
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED

View File

@@ -0,0 +1,135 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_base_pt.hpp
//
//
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2006 Ion Gaztañaga
//
// 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)
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <typeinfo>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
namespace boost{
namespace interprocess{
namespace detail{
class sp_counted_base
{
private:
sp_counted_base( sp_counted_base const & );
sp_counted_base & operator= ( sp_counted_base const & );
long use_count_; // #shared
long weak_count_; // #weak + (#shared != 0)
mutable pthread_mutex_t m_mut;
public:
sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
{
detail::mutexattr_wrapper mut_attr;
detail::mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
~sp_counted_base() // nothrow
{
int res = pthread_mutex_destroy(&m_mut);
assert(res == 0);(void)res;
}
// dispose() is called when use_count_ drops to zero, to release
// the resources managed by *this.
/*
virtual void dispose() = 0; // nothrow
// destroy() is called when weak_count_ drops to zero.
virtual void destroy() // nothrow
{
delete this;
}
virtual void * get_deleter( std::type_info const & ti ) = 0;
*/
void add_ref_copy()
{
pthread_mutex_lock( &m_mut );
++use_count_;
pthread_mutex_unlock( &m_mut );
}
bool add_ref_lock() // true on success
{
pthread_mutex_lock( &m_mut );
bool r = use_count_ == 0? false: ( ++use_count_, true );
pthread_mutex_unlock( &m_mut );
return r;
}
bool ref_release() // nothrow
{
pthread_mutex_lock( &m_mut );
long new_use_count = --use_count_;
pthread_mutex_unlock( &m_mut );
return new_use_count == 0;
}
void weak_add_ref() // nothrow
{
pthread_mutex_lock( &m_mut );
++weak_count_;
pthread_mutex_unlock( &m_mut );
}
bool weak_release() // nothrow
{
pthread_mutex_lock( &m_mut );
long new_weak_count = --weak_count_;
pthread_mutex_unlock( &m_mut );
return new_weak_count == 0;
}
long use_count() const // nothrow
{
pthread_mutex_lock( &m_mut );
long r = use_count_;
pthread_mutex_unlock( &m_mut );
return r;
}
};
} // namespace detail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED

View File

@@ -0,0 +1,119 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_base_w32.hpp
//
//
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2006 Ion Gaztañaga
//
// 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)
//
//
// Lock-free algorithm by Alexander Terekhov
//
// Thanks to Ben Hitchings for the #weak + (#shared != 0)
// formulation
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#include <typeinfo>
namespace boost {
namespace interprocess {
namespace detail {
class sp_counted_base
{
private:
sp_counted_base( sp_counted_base const & );
sp_counted_base & operator= ( sp_counted_base const & );
long use_count_; // #shared
long weak_count_; // #weak + (#shared != 0)
public:
sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
{}
~sp_counted_base() // nothrow
{}
/*
// dispose() is called when use_count_ drops to zero, to release
// the resources managed by *this.
virtual void dispose() = 0; // nothrow
// destroy() is called when weak_count_ drops to zero.
virtual void destroy() // nothrow
{
delete this;
}
virtual void * get_deleter( std::type_info const & ti ) = 0;
*/
void add_ref_copy()
{
winapi::interlocked_increment( &use_count_ );
}
bool add_ref_lock() // true on success
{
for( ;; )
{
long tmp = static_cast< long const volatile& >( use_count_ );
if( tmp == 0 ) return false;
if( winapi::interlocked_compare_exchange( &use_count_, tmp + 1, tmp ) == tmp ) return true;
}
}
bool ref_release() // nothrow
{ return winapi::interlocked_decrement( &use_count_ ) == 0; }
/*
void release() // nothrow
{
if(ref_release()){
//dispose();
weak_release();
}
}
*/
void weak_add_ref() // nothrow
{ winapi::interlocked_increment( &weak_count_ ); }
bool weak_release() // nothrow
{ return winapi::interlocked_decrement( &weak_count_ ) == 0; }
long use_count() const // nothrow
{ return static_cast<long const volatile &>( use_count_ ); }
};
} // namespace detail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED

View File

@@ -0,0 +1,114 @@
#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
//
// This file is the adaptation for shared memory memory mapped
// files of boost/detail/sp_counted_impl.hpp
//
// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
// Copyright 2004-2005 Peter Dimov
// Copyright 2006 Ion Gaztañaga
//
// 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)
//
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/smart_ptr/detail/sp_counted_base.hpp>
#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
#include <boost/interprocess/detail/utilities.hpp>
namespace boost {
namespace interprocess {
namespace detail {
template<class A, class D>
class sp_counted_impl_pd
: public sp_counted_base
, A::template rebind< sp_counted_impl_pd<A, D> >::other
, D // copy constructor must not throw
{
private:
typedef sp_counted_impl_pd<A, D> this_type;
typedef typename A::template rebind
<this_type>::other this_allocator;
typedef typename this_allocator::pointer this_pointer;
sp_counted_impl_pd( sp_counted_impl_pd const & );
sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & );
typedef typename detail::pointer_to_other
<typename A::pointer, const D>::type const_deleter_pointer;
typedef typename detail::pointer_to_other
<typename A::pointer, const A>::type const_allocator_pointer;
typedef typename D::pointer pointer;
pointer m_ptr;
public:
// pre: d(p) must not throw
template<class Ptr>
sp_counted_impl_pd(const Ptr & p, const A &a, const D &d )
: this_allocator(a), D(d), m_ptr(p)
{}
const_deleter_pointer get_deleter() const
{ return const_deleter_pointer(&static_cast<const D&>(*this)); }
const_allocator_pointer get_allocator() const
{ return const_allocator_pointer(&static_cast<const A&>(*this)); }
void dispose() // nothrow
{ static_cast<D&>(*this)(m_ptr); }
void destroy() // nothrow
{
//Self destruction, so get a copy of the allocator
//(in the future we could move it)
this_allocator a_copy(*this);
BOOST_ASSERT(a_copy == *this);
this_pointer this_ptr (this);
//Do it now!
scoped_ptr<this_type,
scoped_deallocator<this_allocator> >(this_ptr, a_copy);
a_copy.destroy(this_ptr);
}
void release() // nothrow
{
if(this->ref_release()){
this->dispose();
this->weak_release();
}
}
void weak_release() // nothrow
{
if(sp_counted_base::weak_release()){
this->destroy();
}
}
};
} // namespace detail
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED

View File

@@ -0,0 +1,70 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/enable_shared_from_this.hpp
//
// (C) Copyright Peter Dimov 2002
// (C) Copyright Ion Gaztañaga 2006. 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_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
#define BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/smart_ptr/weak_ptr.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
namespace boost{
namespace interprocess{
template<class T, class A, class D>
class enable_shared_from_this
{
protected:
enable_shared_from_this()
{}
enable_shared_from_this(enable_shared_from_this const &)
{}
enable_shared_from_this & operator=(enable_shared_from_this const &)
{ return *this; }
~enable_shared_from_this()
{}
public:
shared_ptr<T, A, D> shared_from_this()
{
shared_ptr<T, A, D> p(_internal_weak_this);
BOOST_ASSERT(detail::get_pointer(p.get()) == this);
return p;
}
shared_ptr<T const, A, D> shared_from_this() const
{
shared_ptr<T const, A, D> p(_internal_weak_this);
BOOST_ASSERT(detail::get_pointer(p.get()) == this);
return p;
}
typedef T element_type;
mutable weak_ptr<element_type, A, D> _internal_weak_this;
};
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED

View File

@@ -0,0 +1,254 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/intrusive_ptr.hpp
//
// (C) Copyright Peter Dimov 2001, 2002
// (C) Copyright Ion Gaztañaga 2006. 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_INTRUSIVE_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED
/*!\file
Describes an intrusive ownership pointer.
*/
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/generic_cast.hpp>
#include <functional> // for std::less
#include <iosfwd> // for std::basic_ostream
namespace boost {
namespace interprocess {
/*!The intrusive_ptr class template stores a pointer to an object
with an embedded reference count. intrusive_ptr is parameterized on
T (the type of the object pointed to) and VoidPointer(a void pointer type
that defines the type of pointer that intrusive_ptr will store).
intrusive_ptr<T, void *> defines a class with a T* member whereas
intrusive_ptr<T, offset_ptr<void> > defines a class with a offset_ptr<T> member.
Relies on unqualified calls to:
void intrusive_ptr_add_ref(T * p);
void intrusive_ptr_release(T * p);
with (p != 0)
The object is responsible for destroying itself.*/
template<class T, class VoidPointer>
class intrusive_ptr
{
public:
/*!Provides the type of the internal stored pointer.*/
typedef typename detail::pointer_to_other<VoidPointer, T>::type pointer;
/*!Provides the type of the stored pointer.*/
typedef T element_type;
private:
typedef VoidPointer VP;
typedef intrusive_ptr this_type;
typedef pointer this_type::*unspecified_bool_type;
public:
/*!Constructor. Initializes internal pointer to 0. Does not throw*/
intrusive_ptr(): m_ptr(0)
{}
/*!Constructor. Copies pointer and if "p" is not zero and
"add_ref" is true calls intrusive_ptr_add_ref(get_pointer(p)).
Does not throw*/
intrusive_ptr(const pointer &p, bool add_ref = true): m_ptr(p)
{
if(m_ptr != 0 && add_ref) intrusive_ptr_add_ref(detail::get_pointer(m_ptr));
}
/*!Copy constructor. Copies the internal pointer and if "p" is not
zero calls intrusive_ptr_add_ref(get_pointer(p)). Does not throw*/
intrusive_ptr(intrusive_ptr const & rhs)
: m_ptr(rhs.m_ptr)
{
if(m_ptr != 0) intrusive_ptr_add_ref(detail::get_pointer(m_ptr));
}
/*!Constructor from related. Copies the internal pointer and if "p" is not
zero calls intrusive_ptr_add_ref(get_pointer(p)). Does not throw*/
template<class U> intrusive_ptr
(intrusive_ptr<U, VP> const & rhs)
: m_ptr(rhs.get())
{
if(m_ptr != 0) intrusive_ptr_add_ref(detail::get_pointer(m_ptr));
}
/*!Destructor. If internal pointer is not 0, calls
intrusive_ptr_release(get_pointer(m_ptr)). Does not throw*/
~intrusive_ptr()
{
if(m_ptr != 0) intrusive_ptr_release(detail::get_pointer(m_ptr));
}
/*!Assignment operator. Equivalent to intrusive_ptr(r).swap(*this).
Does not throw*/
intrusive_ptr & operator=(intrusive_ptr const & rhs)
{
this_type(rhs).swap(*this);
return *this;
}
/*!Assignment from related. Equivalent to intrusive_ptr(r).swap(*this).
Does not throw*/
template<class U> intrusive_ptr & operator=
(intrusive_ptr<U, VP> const & rhs)
{
this_type(rhs).swap(*this);
return *this;
}
/*!Assignment from pointer. Equivalent to intrusive_ptr(r).swap(*this).
Does not throw*/
intrusive_ptr & operator=(pointer rhs)
{
this_type(rhs).swap(*this);
return *this;
}
/*!Returns a reference to the internal pointer. Does not throw*/
pointer &get()
{ return m_ptr; }
/*!Returns a reference to the internal pointer. Does not throw*/
const pointer &get() const
{ return m_ptr; }
/*!Returns *get(). Does not throw*/
T & operator*() const
{ return *m_ptr; }
/*!Returns *get(). Does not throw*/
const pointer &operator->() const
{ return m_ptr; }
/*!Returns get(). Does not throw*/
pointer &operator->()
{ return m_ptr; }
/*!Conversion to boolean. Does not throw*/
operator unspecified_bool_type () const
{ return m_ptr == 0? 0: &this_type::m_ptr; }
/*!Not operator. Does not throw*/
bool operator! () const
{ return m_ptr == 0; }
/*!Exchanges the contents of the two smart pointers. Does not throw*/
void swap(intrusive_ptr & rhs)
{ detail::do_swap(m_ptr, rhs.m_ptr); }
private:
pointer m_ptr;
};
/*Returns a.get() == b.get(). Does not throw*/
template<class T, class U, class VP> inline
bool operator==(intrusive_ptr<T, VP> const & a,
intrusive_ptr<U, VP> const & b)
{ return a.get() == b.get(); }
/*Returns a.get() != b.get(). Does not throw*/
template<class T, class U, class VP> inline
bool operator!=(intrusive_ptr<T, VP> const & a,
intrusive_ptr<U, VP> const & b)
{ return a.get() != b.get(); }
/*Returns a.get() == b. Does not throw*/
template<class T, class VP> inline
bool operator==(intrusive_ptr<T, VP> const & a,
const typename intrusive_ptr<T, VP>::pointer &b)
{ return a.get() == b; }
/*Returns a.get() != b. Does not throw*/
template<class T, class VP> inline
bool operator!=(intrusive_ptr<T, VP> const & a,
const typename intrusive_ptr<T, VP>::pointer &b)
{ return a.get() != b; }
/*Returns a == b.get(). Does not throw*/
template<class T, class VP> inline
bool operator==(const typename intrusive_ptr<T, VP>::pointer &a,
intrusive_ptr<T, VP> const & b)
{ return a == b.get(); }
/*Returns a != b.get(). Does not throw*/
template<class T, class VP> inline
bool operator!=(const typename intrusive_ptr<T, VP>::pointer &a,
intrusive_ptr<T, VP> const & b)
{ return a != b.get(); }
/*Returns a.get() < b.get(). Does not throw*/
template<class T, class VP> inline
bool operator<(intrusive_ptr<T, VP> const & a,
intrusive_ptr<T, VP> const & b)
{
return std::less<typename intrusive_ptr<T, VP>::pointer>()
(a.get(), b.get());
}
/*!Exchanges the contents of the two intrusive_ptrs. Does not throw*/
template<class T, class VP> inline
void swap(intrusive_ptr<T, VP> & lhs,
intrusive_ptr<T, VP> & rhs)
{ lhs.swap(rhs); }
// operator<<
template<class E, class T, class Y, class VP>
inline std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, intrusive_ptr<Y, VP> const & p)
{ os << p.get(); return os; }
/*Returns p.get(). Does not throw*/
template<class T, class VP>
inline typename boost::interprocess::intrusive_ptr<T, VP>::pointer
get_pointer(intrusive_ptr<T, VP> p)
{ return p.get(); }
/*Emulates static cast operator. Does not throw*/
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP> static_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_static_cast<U>(p.get()); }
/*Emulates const cast operator. Does not throw*/
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP> const_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_const_cast<U>(p.get()); }
/*Emulates dynamic cast operator. Does not throw*/
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP> dynamic_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_dynamic_cast<U>(p.get()); }
/*Emulates reinterpret cast operator. Does not throw*/
template<class T, class U, class VP>
inline boost::interprocess::intrusive_ptr<T, VP>reinterpret_pointer_cast
(boost::interprocess::intrusive_ptr<U, VP> const & p)
{ return do_reinterpret_cast<U>(p.get()); }
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,140 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/scoped_ptr.hpp
//
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
// (C) Copyright Peter Dimov 2001, 2002
// (C) Copyright Ion Gaztañaga 2006. 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_SCOPED_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
/*!scoped_ptr stores a pointer to a dynamically allocated object.
The object pointed to is guaranteed to be deleted, either on destruction
of the scoped_ptr, or via an explicit reset. The user can avoid this
deletion using release().
scoped_ptr is parameterized on T (the type of the object pointed to) and
Deleter (the functor to be executed to delete the internal pointer).
The internal pointer will be of the same pointer type as typename
Deleter::pointer type (that is, if typename Deleter::pointer is
offset_ptr<void>, the internal pointer will be offset_ptr<T>).*/
template<class T, class Deleter>
class scoped_ptr // noncopyable
: private Deleter
{
scoped_ptr(scoped_ptr const &);
scoped_ptr & operator=(scoped_ptr const &);
typedef scoped_ptr<T, Deleter> this_type;
typedef typename workaround::random_it<T>::reference reference;
public:
/*!Provides the type of the stored pointer.*/
typedef T element_type;
/*!Provides the type of the internal stored pointer.*/
typedef typename detail::pointer_to_other
<typename Deleter::pointer, T>::type pointer;
/*!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d.
Does not throw.*/
explicit scoped_ptr(const pointer &p = 0, const Deleter &d = Deleter())
: Deleter(d), m_ptr(p) // throws if pointer/Deleter copy ctor throws
{}
/*!If the stored pointer is not 0, destroys the object pointed to by the stored pointer.
calling the operator() of the stored deleter. Never throws*/
~scoped_ptr()
{
if(m_ptr){
Deleter &del = static_cast<Deleter&>(*this);
del(m_ptr);
}
}
/*!Deletes the object pointed to by the stored pointer and then
stores a copy of p. Never throws*/
void reset(const pointer &p = 0) // never throws
{ BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); }
/*!Deletes the object pointed to by the stored pointer and then
stores a copy of p and a copy of d.*/
void reset(const pointer &p, const Deleter &d) // never throws
{ BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); }
/*!Assigns internal pointer as 0 and returns previous pointer. This will
avoid deletion on destructor*/
pointer release()
{ pointer tmp(m_ptr); m_ptr = 0; return tmp; }
/*!Returns a reference to the object pointed to by the stored pointer.
Never throws.*/
reference operator*() const
{ BOOST_ASSERT(m_ptr != 0); return *m_ptr; }
/*!Returns the internal stored pointer.*/
pointer &operator->() // never throws
{ BOOST_ASSERT(m_ptr != 0); return m_ptr; }
/*!Returns the internal stored pointer. Never throws.*/
const pointer &operator->() const
{ BOOST_ASSERT(m_ptr != 0); return m_ptr; }
/*!Returns the stored pointer. Never throws.*/
pointer & get()
{ return m_ptr; }
/*!Returns the stored pointer. Never throws.*/
const pointer & get() const
{ return m_ptr; }
// implicit conversion to "bool"
typedef pointer this_type::*unspecified_bool_type;
operator unspecified_bool_type() const // never throws
{ return m_ptr == 0? 0: &this_type::m_ptr; }
/*!Returns true if the stored pointer is 0. Never throws.*/
bool operator! () const // never throws
{ return m_ptr == 0; }
/*!Exchanges the internal pointer and deleter with other scoped_ptr
Never throws.*/
void swap(scoped_ptr & b) // never throws
{ detail::do_swap<Deleter>(*this, b); detail::do_swap(m_ptr, b.m_ptr); }
private:
pointer m_ptr;
};
/*!Exchanges the internal pointer and deleter with other scoped_ptr
Never throws.*/
template<class T, class D> inline
void swap(scoped_ptr<T, D> & a, scoped_ptr<T, D> & b) // never throws
{ a.swap(b); }
/*!Returns a copy of the stored pointer*/
template<class T, class D> inline
typename scoped_ptr<T, D>::pointer get_pointer(scoped_ptr<T, D> const & p)
{ return p.get(); }
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,276 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/shared_ptr.hpp
//
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
// (C) Copyright Peter Dimov 2001, 2002, 2003
// (C) Copyright Ion Gaztañaga 2006. 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_SHARED_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/assert.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/generic_cast.hpp>
#include <boost/interprocess/detail/cast_tags.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <boost/interprocess/smart_ptr/detail/shared_count.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <algorithm> // for std::swap
#include <functional> // for std::less
#include <typeinfo> // for std::bad_cast
#include <iosfwd> // for std::basic_ostream
namespace boost{
namespace interprocess{
template<class T, class VA, class D> class weak_ptr;
template<class T, class VA, class D> class enable_shared_from_this;
namespace detail{
template<class T, class VA, class D>
inline void sp_enable_shared_from_this
(shared_count<T, VA, D> const & pn,
const typename pointer_to_other <typename shared_count<T, VA, D>::pointer,
enable_shared_from_this<T, VA, D> >::type &pe,
const typename shared_count<T, VA, D>::pointer &px)
{
if(pe != 0)
pe->_internal_weak_this._internal_assign(pn);
}
/*
template<class T, class VA, class D>
inline void sp_enable_shared_from_this(shared_count<T, VA, D> const &, ...)
{}
*/
} // namespace detail
/*!shared_ptr stores a pointer to a dynamically allocated object.
The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to
it is destroyed or reset. shared_ptr is parameterized on
T (the type of the object pointed to), VA (the void allocator to be used
to allocate the auxiliary data) and D (the deleter whose
operator() will be used to delete the object.
The internal pointer will be of the same pointer type as typename
VA::pointer type (that is, if typename VA::pointer is
offset_ptr<void>, the internal pointer will be offset_ptr<T>).*/
template<class T, class VA, class D>
class shared_ptr
{
private:
typedef shared_ptr<T, VA, D> this_type;
public:
/*!Provides the type of the stored pointer.*/
typedef T element_type;
/*!Provides the type of the stored pointer.*/
typedef T value_type;
/*!Provides the type of the internal stored pointer.*/
typedef typename detail::pointer_to_other
<typename VA::pointer, T>::type pointer;
typedef typename workaround::random_it<T>::reference reference;
typedef typename workaround::random_it<T>::const_reference const_reference;
typedef typename detail::pointer_to_other
<typename VA::pointer, const D>::type const_deleter_pointer;
typedef typename detail::pointer_to_other
<typename VA::pointer, const VA>::type const_allocator_pointer;
/*!Constructs an empty shared_ptr. Use_count() == 0 && get() == 0.*/
shared_ptr()
: m_pn() // never throws
{}
/*!Constructs a shared_ptr that owns the pointer p. Auxiliary data will be allocated
with a copy of a and the object will be deleted with a copy of d.
Requirements: D and A's copy constructor must not throw.*/
explicit shared_ptr(const pointer&p, const VA &a = VA(), const D &d = D())
: m_pn(p, a, d)
{
typedef pointer Pointer;
//Check that the pointer passed is of the same type that
//the pointer the allocator defines or it's a raw pointer
typedef typename detail::pointer_to_other<Pointer, T>::type ParameterPointer;
BOOST_STATIC_ASSERT((boost::is_same<pointer, ParameterPointer>::value)||
(boost::is_pointer<Pointer>::value));
//detail::sp_enable_shared_from_this( m_pn, p, p );
}
/*!If r is empty, constructs an empty shared_ptr. Otherwise, constructs
a shared_ptr that shares ownership with r. Never throws.*/
template<class Y>
shared_ptr(shared_ptr<Y, VA, D> const & r)
: m_pn(r.m_pn) // never throws
{}
/*!Constructs a shared_ptr that shares ownership with r and stores
a copy of the pointer stored in r.*/
template<class Y>
explicit shared_ptr(weak_ptr<Y, VA, D> const & r)
: m_pn(r.m_pn) // may throw
{}
template<class Y>
shared_ptr(shared_ptr<Y, VA, D> const & r, detail::static_cast_tag)
: m_pn(do_static_cast<typename detail::pointer_to_other<pointer, T>::type>(r.m_pn.get_pointer()),
r.m_pn)
{}
template<class Y>
shared_ptr(shared_ptr<Y, VA, D> const & r, detail::const_cast_tag)
: m_pn(do_const_cast<typename detail::pointer_to_other<pointer, T>::type>(r.m_pn.get_pointer()),
r.m_pn)
{}
template<class Y>
shared_ptr(shared_ptr<Y, VA, D> const & r, detail::dynamic_cast_tag)
: m_pn(do_dynamic_cast<typename detail::pointer_to_other<pointer, T>::type>(r.m_pn.get_pointer()),
r.m_pn)
{
if(!m_pn.get_pointer()){ // need to allocate new counter -- the cast failed
m_pn = detail::shared_count<T, VA, D>();
}
}
/*!Equivalent to shared_ptr(r).swap(*this). Never throws*/
template<class Y>
shared_ptr & operator=(shared_ptr<Y, VA, D> const & r)
{
m_pn = r.m_pn; // shared_count::op= doesn't throw
return *this;
}
void reset()
{
this_type().swap(*this);
}
template<class Pointer>
void reset(const Pointer &p, const VA &a = VA(), const D &d = D())
{
//Check that the pointer passed is of the same type that
//the pointer the allocator defines or it's a raw pointer
typedef typename detail::pointer_to_other<Pointer, T>::type ParameterPointer;
BOOST_STATIC_ASSERT((boost::is_same<pointer, ParameterPointer>::value)||
(boost::is_pointer<Pointer>::value));
this_type(p, a, d).swap(*this);
}
reference operator* () const // never throws
{ BOOST_ASSERT(m_pn.get_pointer() != 0); return *m_pn.get_pointer(); }
pointer operator-> () const // never throws
{ BOOST_ASSERT(m_pn.get_pointer() != 0); return m_pn.get_pointer(); }
pointer &operator-> () // never throws
{ BOOST_ASSERT(m_pn.get_pointer() != 0); return m_pn.get_pointer(); }
const pointer &get() const // never throws
{ return m_pn.get_pointer(); }
pointer &get() // never throws
{ return m_pn.get_pointer(); }
// implicit conversion to "bool"
void unspecified_bool_type_func() const {}
typedef void (this_type::*unspecified_bool_type)() const;
operator unspecified_bool_type() const // never throws
{ return !m_pn.get_pointer() ? 0 : &this_type::unspecified_bool_type_func; }
bool operator! () const // never throws
{ return !m_pn.get_pointer(); }
bool unique() const // never throws
{ return m_pn.unique(); }
long use_count() const // never throws
{ return m_pn.use_count(); }
void swap(shared_ptr<T, VA, D> & other) // never throws
{ m_pn.swap(other.m_pn); }
template<class T2, class A2, class D2>
bool _internal_less(shared_ptr<T2, A2, D2> const & rhs) const
{ return m_pn < rhs.m_pn; }
const_deleter_pointer get_deleter() const
{ return m_pn.get_deleter(); }
const_allocator_pointer get_allocator() const
{ return m_pn.get_allocator(); }
private:
template<class T2, class A2, class D2> friend class shared_ptr;
template<class T2, class A2, class D2> friend class weak_ptr;
detail::shared_count<T, VA, D> m_pn; // reference counter
}; // shared_ptr
template<class T, class VA, class D, class U, class VA2, class D2> inline
bool operator==(shared_ptr<T, VA, D> const & a, shared_ptr<U, VA2, D2> const & b)
{ return a.get() == b.get(); }
template<class T, class VA, class D, class U, class VA2, class D2> inline
bool operator!=(shared_ptr<T, VA, D> const & a, shared_ptr<U, VA2, D2> const & b)
{ return a.get() != b.get(); }
template<class T, class VA, class D, class U, class VA2, class D2> inline
bool operator<(shared_ptr<T, VA, D> const & a, shared_ptr<U, VA2, D2> const & b)
{ return a._internal_less(b); }
template<class T, class VA, class D> inline
void swap(shared_ptr<T, VA, D> & a, shared_ptr<T, VA, D> & b)
{ a.swap(b); }
template<class T, class VA, class D, class U> inline
shared_ptr<T, VA, D> static_pointer_cast(shared_ptr<U, VA, D> const & r)
{ return shared_ptr<T, VA, D>(r, detail::static_cast_tag()); }
template<class T, class VA, class D, class U> inline
shared_ptr<T, VA, D> const_pointer_cast(shared_ptr<U, VA, D> const & r)
{ return shared_ptr<T, VA, D>(r, detail::const_cast_tag()); }
template<class T, class VA, class D, class U> inline
shared_ptr<T, VA, D> dynamic_pointer_cast(shared_ptr<U, VA, D> const & r)
{ return shared_ptr<T, VA, D>(r, detail::dynamic_cast_tag()); }
// get_pointer() enables boost::mem_fn to recognize shared_ptr
template<class T, class VA, class D> inline
T * get_pointer(shared_ptr<T, VA, D> const & p)
{ return p.get(); }
// operator<<
template<class E, class T, class Y, class VA, class D> inline
std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, shared_ptr<Y, VA, D> const & p)
{ os << p.get(); return os; }
/*
// get_deleter (experimental)
template<class T, class VA, class D>
typename detail::pointer_to_other<shared_ptr<T, VA, D>, D>::type
get_deleter(shared_ptr<T, VA, D> const & p)
{ return static_cast<D *>(p._internal_get_deleter(typeid(D))); }
*/
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,419 @@
// I, Howard Hinnant, hereby place this code in the public domain.
#ifdef _MSC_VER
#pragma warning (push)
//Disable "multiple copy constructors specified"
#pragma warning (disable : 4521)
#pragma warning (disable : 4522)
#endif
#include <boost/compressed_pair.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <cstddef>
namespace boost_ext{
namespace detail
{
struct two {char _[2];};
namespace pointer_type_imp
{
template <class U> static two test(...);
template <class U> static char test(typename U::pointer* = 0);
}
template <class T>
struct has_pointer_type
{
static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
};
namespace pointer_type_imp
{
template <class T, class D, bool = has_pointer_type<D>::value>
struct pointer_type
{
typedef typename D::pointer type;
};
template <class T, class D>
struct pointer_type<T, D, false>
{
typedef T* type;
};
}
template <class T, class D>
struct pointer_type
{
typedef typename pointer_type_imp::pointer_type<T,
typename boost::remove_reference<D>::type>::type type;
};
}
template <class T>
struct default_delete
{
default_delete() {}
template <class U> default_delete(const default_delete<U>&) {}
void operator() (T* ptr) const
{
BOOST_STATIC_ASSERT(sizeof(T) > 0);
delete ptr;
}
};
template <class T>
struct default_delete<T[]>
{
void operator() (T* ptr) const
{
BOOST_STATIC_ASSERT(sizeof(T) > 0);
delete [] ptr;
}
};
template <class T, std::size_t N>
struct default_delete<T[N]>
{
void operator() (T* ptr, std::size_t) const
{
BOOST_STATIC_ASSERT(sizeof(T) > 0);
delete [] ptr;
}
};
template <class T, class D> class unique_ptr;
namespace detail
{
template <class T> struct unique_ptr_error;
template <class T, class D>
struct unique_ptr_error<const unique_ptr<T, D> >
{
typedef unique_ptr<T, D> type;
};
} // detail
template <class T, class D = default_delete<T> >
class unique_ptr
{
struct nat {int for_bool_;};
typedef typename boost::add_reference<D>::type deleter_reference;
typedef typename boost::add_reference<const D>::type deleter_const_reference;
public:
typedef T element_type;
typedef D deleter_type;
typedef typename detail::pointer_type<T, D>::type pointer;
// constructors
unique_ptr() : ptr_(pointer()) {}
explicit unique_ptr(pointer p) : ptr_(p) {}
unique_ptr(pointer p, typename boost::mpl::if_<
boost::is_reference<D>,
D,
typename boost::add_reference<const D>::type>::type d)
: ptr_(p, d) {}
unique_ptr(const unique_ptr& u)
: ptr_(const_cast<unique_ptr&>(u).release(), u.get_deleter()) {}
template <class U, class E>
unique_ptr(const unique_ptr<U, E>& u,
typename boost::enable_if_c<
boost::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
boost::is_convertible<E, D>::value &&
(
!boost::is_reference<D>::value ||
boost::is_same<D, E>::value
)
,
nat
>::type = nat())
: ptr_(const_cast<unique_ptr<U,E>&>(u).release(), u.get_deleter()) {}
// destructor
~unique_ptr() {reset();}
// assignment
unique_ptr& operator=(const unique_ptr& cu)
{
unique_ptr& u = const_cast<unique_ptr&>(cu);
reset(u.release());
ptr_.second() = u.get_deleter();
return *this;
}
template <class U, class E>
unique_ptr& operator=(const unique_ptr<U, E>& cu)
{
unique_ptr<U, E>& u = const_cast<unique_ptr<U, E>&>(cu);
reset(u.release());
ptr_.second() = u.get_deleter();
return *this;
}
unique_ptr& operator=(int nat::*)
{
reset();
return *this;
}
// observers
typename boost::add_reference<T>::type operator*() const {return *ptr_.first();}
pointer operator->() const {return ptr_.first();}
pointer get() const {return ptr_.first();}
deleter_reference get_deleter() {return ptr_.second();}
deleter_const_reference get_deleter() const {return ptr_.second();}
operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
// modifiers
pointer release()
{
pointer tmp = ptr_.first();
ptr_.first() = pointer();
return tmp;
}
void reset(pointer p = pointer())
{
if (ptr_.first() != p)
{
if (ptr_.first())
ptr_.second()(ptr_.first());
ptr_.first() = p;
}
}
void swap(unique_ptr& u) {ptr_.swap(u.ptr_);}
private:
boost::compressed_pair<pointer, D> ptr_;
unique_ptr(unique_ptr&);
template <class U, class E> unique_ptr(unique_ptr<U, E>&);
template <class U> unique_ptr(U&, typename detail::unique_ptr_error<U>::type = 0);
unique_ptr& operator=(unique_ptr&);
template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&);
template <class U> typename detail::unique_ptr_error<U>::type operator=(U&);
};
template <class T, class D>
class unique_ptr<T[], D>
{
struct nat {int for_bool_;};
typedef typename boost::add_reference<D>::type deleter_reference;
typedef typename boost::add_reference<const D>::type deleter_const_reference;
public:
typedef T element_type;
typedef D deleter_type;
typedef typename detail::pointer_type<T, D>::type pointer;
// constructors
unique_ptr() : ptr_(pointer()) {}
explicit unique_ptr(pointer p) : ptr_(p) {}
unique_ptr(pointer p, typename boost::mpl::if_<
boost::is_reference<D>,
D,
typename boost::add_reference<const D>::type>::type d)
: ptr_(p, d) {}
unique_ptr(const unique_ptr& u)
: ptr_(const_cast<unique_ptr&>(u).release(), u.get_deleter()) {}
// destructor
~unique_ptr() {reset();}
// assignment
unique_ptr& operator=(const unique_ptr& cu)
{
unique_ptr& u = const_cast<unique_ptr&>(cu);
reset(u.release());
ptr_.second() = u.get_deleter();
return *this;
}
unique_ptr& operator=(int nat::*)
{
reset();
return *this;
}
// observers
typename boost::add_reference<T>::type operator[](std::size_t i) const {return ptr_.first()[i];}
pointer get() const {return ptr_.first();}
deleter_reference get_deleter() {return ptr_.second();}
deleter_const_reference get_deleter() const {return ptr_.second();}
operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
// modifiers
pointer release()
{
pointer tmp = ptr_.first();
ptr_.first() = pointer();
return tmp;
}
void reset(pointer p = pointer())
{
if (ptr_.first() != p)
{
if (ptr_.first())
ptr_.second()(ptr_.first());
ptr_.first() = p;
}
}
void swap(unique_ptr& u) {ptr_.swap(u.ptr_);}
private:
boost::compressed_pair<pointer, D> ptr_;
template <class U, class E> unique_ptr(U p, E,
typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
template <class U> explicit unique_ptr(U,
typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
unique_ptr(unique_ptr&);
template <class U> unique_ptr(U&, typename detail::unique_ptr_error<U>::type = 0);
unique_ptr& operator=(unique_ptr&);
template <class U> typename detail::unique_ptr_error<U>::type operator=(U&);
};
template <class T, class D, std::size_t N>
class unique_ptr<T[N], D>
{
struct nat {int for_bool_;};
typedef typename boost::add_reference<D>::type deleter_reference;
typedef typename boost::add_reference<const D>::type deleter_const_reference;
public:
typedef T element_type;
typedef D deleter_type;
typedef typename detail::pointer_type<T, D>::type pointer;
static const std::size_t size = N;
// constructors
unique_ptr() : ptr_(pointer()) {}
explicit unique_ptr(pointer p) : ptr_(p) {}
unique_ptr(pointer p, typename boost::mpl::if_<
boost::is_reference<D>,
D,
typename boost::add_reference<const D>::type>::type d)
: ptr_(p, d) {}
unique_ptr(const unique_ptr& u)
: ptr_(const_cast<unique_ptr&>(u).release(), u.get_deleter()) {}
// destructor
~unique_ptr() {reset();}
// assignment
unique_ptr& operator=(const unique_ptr& cu)
{
unique_ptr& u = const_cast<unique_ptr&>(cu);
reset(u.release());
ptr_.second() = u.get_deleter();
return *this;
}
unique_ptr& operator=(int nat::*)
{
reset();
return *this;
}
// observers
typename boost::add_reference<T>::type operator[](std::size_t i) const {return ptr_.first()[i];}
pointer get() const {return ptr_.first();}
deleter_reference get_deleter() {return ptr_.second();}
deleter_const_reference get_deleter() const {return ptr_.second();}
operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
// modifiers
pointer release()
{
pointer tmp = ptr_.first();
ptr_.first() = pointer();
return tmp;
}
void reset(pointer p = pointer())
{
if (ptr_.first() != p)
{
if (ptr_.first())
ptr_.second()(ptr_.first(), N);
ptr_.first() = p;
}
}
void swap(unique_ptr& u) {ptr_.swap(u.ptr_);}
private:
boost::compressed_pair<pointer, D> ptr_;
template <class U, class E> unique_ptr(U p, E,
typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
template <class U> explicit unique_ptr(U,
typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
unique_ptr(unique_ptr&);
template <class U> unique_ptr(U&, typename detail::unique_ptr_error<U>::type = 0);
unique_ptr& operator=(unique_ptr&);
template <class U> typename detail::unique_ptr_error<U>::type operator=(U&);
};
template <class T, class D>
inline
void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) {x.swap(y);}
template <class T1, class D1, class T2, class D2>
inline
bool
operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() == y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() != y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator <(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() < y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() <= y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator >(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() > y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() >= y.get();}
template <class T, class D>
inline
unique_ptr<T, D>
move(unique_ptr<T, D>& p)
{
return unique_ptr<T, D>(p.release(), p.get_deleter());
}
} //namespace boost_ext{
#ifdef _MSC_VER
#pragma warning (pop)
#endif

View File

@@ -0,0 +1,407 @@
// I, Howard Hinnant, hereby place this code in the public domain.
namespace std { namespace detail {
template <bool cond, class Then, class Else>
struct select
{
typedef Then type;
};
template <class Then, class Else>
struct select<false, Then, Else>
{
typedef Else type;
};
template <bool b, class T = void> struct restrict_to {};
template <class T> struct restrict_to<true, T> {typedef T type;};
using boost::compressed_pair;
struct two {char _[2];};
namespace pointer_type_imp
{
template <class U> static two test(...);
template <class U> static char test(typename U::pointer* = 0);
}
template <class T>
struct has_pointer_type
{
static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
};
namespace pointer_type_imp
{
template <class T, class D, bool = has_pointer_type<D>::value>
struct pointer_type
{
typedef typename D::pointer type;
};
template <class T, class D>
struct pointer_type<T, D, false>
{
typedef T* type;
};
}
template <class T, class D>
struct pointer_type
{
typedef typename pointer_type_imp::pointer_type<T,
typename tr1::remove_reference<D>::type>::type type;
};
} }
namespace std
{
template <class T>
struct default_delete
{
default_delete() {}
template <class U> default_delete(const default_delete<U>&) {}
void operator() (T* ptr) const
{
static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type");
delete ptr;
}
};
template <class T>
struct default_delete<T[]>
{
void operator() (T* ptr) const
{
static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type");
delete [] ptr;
}
};
template <class T, std::size_t N>
struct default_delete<T[N]>
{
void operator() (T* ptr, std::size_t) const
{
static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type");
delete [] ptr;
}
};
template <class T, class D = default_delete<T> >
class unique_ptr
{
struct nat {int for_bool_;};
public:
typedef T element_type;
typedef D deleter_type;
typedef typename detail::pointer_type<T, D>::type pointer;
// constructors
unique_ptr() : ptr_(pointer()) {}
explicit unique_ptr(pointer p) : ptr_(p) {}
unique_ptr(pointer p, typename detail::select<
tr1::is_reference<D>::value,
D,
const D&>::type d)
: ptr_(p, d) {}
unique_ptr(pointer p, typename tr1::remove_reference<D>::type&& d)
: ptr_(p, std::move(d))
{
static_assert(!tr1::is_reference<D>::value, "rvalue deleter bound to reference");
}
unique_ptr(unique_ptr&& u)
: ptr_(u.release(), std::forward<D>(u.get_deleter())) {}
template <class U, class E>
unique_ptr(unique_ptr<U, E>&& u,
typename detail::restrict_to<
tr1::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
tr1::is_convertible<E, D>::value &&
(
!tr1::is_reference<D>::value ||
tr1::is_same<D, E>::value
)
,
nat
>::type = nat())
: ptr_(u.release(), std::forward<D>(u.get_deleter())) {}
// destructor
~unique_ptr() {reset();}
// assignment
unique_ptr& operator=(unique_ptr&& u)
{
reset(u.release());
ptr_.second() = std::move(u.get_deleter());
return *this;
}
template <class U, class E>
unique_ptr& operator=(unique_ptr<U, E>&& u)
{
reset(u.release());
ptr_.second() = std::move(u.get_deleter());
return *this;
}
unique_ptr& operator=(int nat::*)
{
reset();
return *this;
}
// observers
typename tr1::add_reference<T>::type operator*() const {return *ptr_.first();}
pointer operator->() const {return ptr_.first();}
pointer get() const {return ptr_.first();}
D& get_deleter() {return ptr_.second();}
const D& get_deleter() const {return ptr_.second();}
operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
// modifiers
pointer release()
{
pointer tmp = ptr_.first();
ptr_.first() = pointer();
return tmp;
}
void reset(pointer p = pointer())
{
if (ptr_.first() != p)
{
if (ptr_.first())
ptr_.second()(ptr_.first());
ptr_.first() = p;
}
}
void swap(unique_ptr&& u) {ptr_.swap(u.ptr_);}
private:
detail::compressed_pair<pointer, D> ptr_;
unique_ptr(const unique_ptr&);
template <class U, class E> unique_ptr(const unique_ptr<U, E>&);
unique_ptr& operator=(const unique_ptr&);
template <class U, class E> unique_ptr& operator=(const unique_ptr<U, E>&);
};
template <class T, class D>
class unique_ptr<T[], D>
{
struct nat {int for_bool_;};
public:
typedef T element_type;
typedef D deleter_type;
typedef typename detail::pointer_type<T, D>::type pointer;
// constructors
unique_ptr() : ptr_(pointer()) {}
explicit unique_ptr(pointer p) : ptr_(p) {}
unique_ptr(pointer p, typename detail::select<
tr1::is_reference<D>::value,
D,
const D&>::type d)
: ptr_(p, d) {}
unique_ptr(pointer p, typename tr1::remove_reference<D>::type&& d)
: ptr_(p, std::move(d))
{
static_assert(!tr1::is_reference<D>::value, "rvalue deleter bound to reference");
}
unique_ptr(unique_ptr&& u)
: ptr_(u.release(), std::forward<D>(u.get_deleter())) {}
// destructor
~unique_ptr() {reset();}
// assignment
unique_ptr& operator=(unique_ptr&& u)
{
reset(u.release());
ptr_.second() = std::move(u.get_deleter());
return *this;
}
unique_ptr& operator=(int nat::*)
{
reset();
return *this;
}
// observers
typename tr1::add_reference<T>::type operator[](std::size_t i) const {return ptr_.first()[i];}
pointer get() const {return ptr_.first();}
D& get_deleter() {return ptr_.second();}
const D& get_deleter() const {return ptr_.second();}
operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
// modifiers
pointer release()
{
pointer tmp = ptr_.first();
ptr_.first() = pointer();
return tmp;
}
void reset(pointer p = pointer())
{
if (ptr_.first() != p)
{
if (ptr_.first())
ptr_.second()(ptr_.first());
ptr_.first() = p;
}
}
void swap(unique_ptr&& u) {ptr_.swap(u.ptr_);}
private:
detail::compressed_pair<pointer, D> ptr_;
template <class U> unique_ptr(U p,
typename detail::select<
tr1::is_reference<D>::value,
D,
const D&>::type d,
typename detail::restrict_to<tr1::is_convertible<U, pointer>::value>::type* = 0);
template <class U> unique_ptr(U p, typename tr1::remove_reference<D>::type&& d,
typename detail::restrict_to<tr1::is_convertible<U, pointer>::value>::type* = 0);
template <class U> explicit unique_ptr(U,
typename detail::restrict_to<tr1::is_convertible<U, pointer>::value>::type* = 0);
unique_ptr(const unique_ptr&);
unique_ptr& operator=(const unique_ptr&);
};
template <class T, class D, std::size_t N>
class unique_ptr<T[N], D>
{
struct nat {int for_bool_;};
public:
typedef T element_type;
typedef D deleter_type;
typedef typename detail::pointer_type<T, D>::type pointer;
static const std::size_t size = N;
// constructors
unique_ptr() : ptr_(pointer()) {}
explicit unique_ptr(pointer p) : ptr_(p) {}
unique_ptr(pointer p, typename detail::select<
tr1::is_reference<D>::value,
D,
const D&>::type d)
: ptr_(p, d) {}
unique_ptr(pointer p, typename tr1::remove_reference<D>::type&& d)
: ptr_(p, std::move(d))
{
static_assert(!tr1::is_reference<D>::value, "rvalue deleter bound to reference");
}
unique_ptr(unique_ptr&& u)
: ptr_(u.release(), std::forward<D>(u.get_deleter())) {}
// destructor
~unique_ptr() {reset();}
// assignment
unique_ptr& operator=(unique_ptr&& u)
{
reset(u.release());
ptr_.second() = std::move(u.get_deleter());
return *this;
}
unique_ptr& operator=(int nat::*)
{
reset();
return *this;
}
// observers
typename tr1::add_reference<T>::type operator[](std::size_t i) const {return ptr_.first()[i];}
pointer get() const {return ptr_.first();}
D& get_deleter() {return ptr_.second();}
const D& get_deleter() const {return ptr_.second();}
operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
// modifiers
pointer release()
{
pointer tmp = ptr_.first();
ptr_.first() = pointer();
return tmp;
}
void reset(pointer p = pointer())
{
if (ptr_.first() != p)
{
if (ptr_.first())
ptr_.second()(ptr_.first(), N);
ptr_.first() = p;
}
}
void swap(unique_ptr&& u) {ptr_.swap(u.ptr_);}
private:
detail::compressed_pair<pointer, D> ptr_;
template <class U> unique_ptr(U p,
typename detail::select<
tr1::is_reference<D>::value,
D,
const D&>::type d,
typename detail::restrict_to<tr1::is_convertible<U, pointer>::value>::type* = 0);
template <class U> unique_ptr(U p, typename tr1::remove_reference<D>::type&& d,
typename detail::restrict_to<tr1::is_convertible<U, pointer>::value>::type* = 0);
template <class U> explicit unique_ptr(U,
typename detail::restrict_to<tr1::is_convertible<U, pointer>::value>::type* = 0);
unique_ptr(const unique_ptr&);
unique_ptr& operator=(const unique_ptr&);
};
template <class T, class D>
inline
void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) {x.swap(y);}
template <class T, class D>
inline
void swap(unique_ptr<T, D>&& x, unique_ptr<T, D>& y) {x.swap(y);}
template <class T, class D>
inline
void swap(unique_ptr<T, D>& x, unique_ptr<T, D>&& y) {x.swap(y);}
template <class T1, class D1, class T2, class D2>
inline
bool
operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() == y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() != y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator <(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() < y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() <= y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator >(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() > y.get();}
template <class T1, class D1, class T2, class D2>
inline
bool
operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
{return x.get() >= y.get();}
} // std

View File

@@ -0,0 +1,149 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is the adaptation for Interprocess of boost/weak_ptr.hpp
//
// (C) Copyright Peter Dimov 2001, 2002, 2003
// (C) Copyright Ion Gaztañaga 2006. 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_WEAK_PTR_HPP_INCLUDED
#define BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
namespace boost{
namespace interprocess{
template<class T, class A, class D>
class weak_ptr
{
private:
// Borland 5.5.1 specific workarounds
typedef weak_ptr<T, A, D> this_type;
typedef typename detail::pointer_to_other
<typename A::pointer, T>::type pointer;
typedef typename workaround::random_it<T>::reference reference;
typedef typename workaround::random_it<T>::const_reference const_reference;
public:
typedef T element_type;
typedef T value_type;
weak_ptr()
: m_pn() // never throws
{}
// generated copy constructor, assignment, destructor are fine
//
// The "obvious" converting constructor implementation:
//
// template<class Y>
// weak_ptr(weak_ptr<Y> const & r): m_px(r.m_px), m_pn(r.m_pn) // never throws
// {
// }
//
// has a serious problem.
//
// r.m_px may already have been invalidated. The m_px(r.m_px)
// conversion may require access to *r.m_px (virtual inheritance).
//
// It is not possible to avoid spurious access violations since
// in multithreaded programs r.m_px may be invalidated at any point.
template<class Y>
weak_ptr(weak_ptr<Y, A, D> const & r)
: m_pn(r.m_pn) // never throws
{
//Construct a temporary shared_ptr so that nobody
//can destroy the value while constructing this
const shared_ptr<T, A, D> &ref = r.lock();
m_pn.set_pointer(ref.get());
}
template<class Y>
weak_ptr(shared_ptr<Y, A, D> const & r)
: m_pn(r.m_pn) // never throws
{}
template<class Y>
weak_ptr & operator=(weak_ptr<Y, A, D> const & r) // never throws
{
//Construct a temporary shared_ptr so that nobody
//can destroy the value while constructing this
const shared_ptr<T, A, D> &ref = r.lock();
m_pn = r.m_pn;
m_pn.set_pointer(ref.get());
return *this;
}
template<class Y>
weak_ptr & operator=(shared_ptr<Y, A, D> const & r) // never throws
{ m_pn = r.m_pn; return *this; }
shared_ptr<T, A, D> lock() const // never throws
{
// optimization: avoid throw overhead
if(expired()){
return shared_ptr<element_type, A, D>();
}
BOOST_TRY{
return shared_ptr<element_type, A, D>(*this);
}
BOOST_CATCH(bad_weak_ptr const &){
// Q: how can we get here?
// A: another thread may have invalidated r after the use_count test above.
return shared_ptr<element_type, A, D>();
}
BOOST_CATCH_END
}
long use_count() const // never throws
{ return m_pn.use_count(); }
bool expired() const // never throws
{ return m_pn.use_count() == 0; }
void reset() // never throws in 1.30+
{ this_type().swap(*this); }
void swap(this_type & other) // never throws
{ detail::do_swap(m_pn, other.m_pn); }
template<class T2, class A2, class D2>
bool _internal_less(weak_ptr<T2, A2, D2> const & rhs) const
{ return m_pn < rhs.m_pn; }
template<class Y>
void _internal_assign(const detail::shared_count<Y, A, D> & pn2)
{ m_pn = pn2; }
private:
template<class T2, class A2, class D2> friend class shared_ptr;
template<class T2, class A2, class D2> friend class weak_ptr;
detail::weak_count<T, A, D> m_pn; // reference counter
}; // weak_ptr
template<class T, class A, class D, class U, class A2, class D2> inline
bool operator<(weak_ptr<T, A, D> const & a, weak_ptr<U, A2, D2> const & b)
{ return a._internal_less(b); }
template<class T, class A, class D> inline
void swap(weak_ptr<T, A, D> & a, weak_ptr<T, A, D> & b)
{ a.swap(b); }
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED

View File

@@ -0,0 +1,422 @@
/*
* Copyright (c) 1998
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's sstream file. Modified by Ion Gaztañaga 2005.
// Changed internal SGI string to a buffer. Added efficient
// internal buffer get/set/swap functions, so that we can obtain/establish the
// internal buffer without any reallocation or copy. Kill those temporaries!
///////////////////////////////////////////////////////////////////////////////
/*!\file
This file defines basic_bufferbuf, basic_ibufferstream,
basic_obufferstream, and basic_bufferstream classes. These classes
represent streamsbufs and streams whose sources or destinations
are fixed size character buffers.
*/
#ifndef BOOST_INTERPROCESS_BUFFERSTREAM_HPP
#define BOOST_INTERPROCESS_BUFFERSTREAM_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <iosfwd>
#include <ios>
#include <istream>
#include <ostream>
#include <string> // char traits
#include <cstddef> // ptrdiff_t
#include <assert.h>
#include <boost/interprocess/interprocess_fwd.hpp>
namespace boost { namespace interprocess {
/*!A streambuf class that controls the transmission of elements to and from
a basic_xbufferstream. The elements are transmitted from a to a fixed
size buffer*/
template <class CharT, class CharTraits>
class basic_bufferbuf
: public std::basic_streambuf<CharT, CharTraits>
{
public:
typedef CharT char_type;
typedef typename CharTraits::int_type int_type;
typedef typename CharTraits::pos_type pos_type;
typedef typename CharTraits::off_type off_type;
typedef CharTraits traits_type;
typedef std::basic_streambuf<char_type, traits_type> base_t;
public:
/*!Constructor. Does not throw.*/
explicit basic_bufferbuf(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: base_t(), m_mode(mode), m_buffer(0), m_length(0)
{}
/*!Constructor. Assigns formatting buffer. Does not throw.*/
explicit basic_bufferbuf(CharT *buffer, std::size_t length,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: base_t(), m_mode(mode), m_buffer(buffer), m_length(length)
{ this->set_pointers(); }
virtual ~basic_bufferbuf(){}
public:
/*!Returns the pointer and size of the internal buffer.
Does not throw.*/
std::pair<CharT *, std::size_t> buffer() const
{ return std::pair<CharT *, std::size_t>(m_buffer, m_length); }
/*!Sets the underlying buffer to a new value. Does not throw.*/
void buffer(CharT *buffer, std::size_t length)
{ m_buffer = buffer; m_length = length; this->set_pointers(); }
private:
void set_pointers()
{
// The initial read position is the beginning of the buffer.
if(m_mode & std::ios_base::in)
this->setg(m_buffer, m_buffer, m_buffer + m_length);
// The initial write position is the beginning of the buffer.
if(m_mode & std::ios_base::out)
this->setp(m_buffer, m_buffer + m_length);
}
protected:
virtual int_type underflow()
{
// Precondition: gptr() >= egptr(). Returns a character, if available.
return this->gptr() != this->egptr() ?
CharTraits::to_int_type(*this->gptr()) : CharTraits::eof();
}
virtual int_type pbackfail(int_type c = CharTraits::eof())
{
if(this->gptr() != this->eback()) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
this->gbump(-1);
return c;
}
else if(m_mode & std::ios_base::out) {
this->gbump(-1);
*this->gptr() = c;
return c;
}
else
return CharTraits::eof();
}
else {
this->gbump(-1);
return CharTraits::not_eof(c);
}
}
else
return CharTraits::eof();
}
virtual int_type overflow(int_type c = CharTraits::eof())
{
if(m_mode & std::ios_base::out) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(!(m_mode & std::ios_base::in)) {
if(this->pptr() != this->epptr()) {
*this->pptr() = CharTraits::to_char_type(c);
this->pbump(1);
return c;
}
else
return CharTraits::eof();
}
else {
if(this->pptr() == this->epptr()) {
//We can't append to a static buffer
return CharTraits::eof();
}
else {
*this->pptr() = CharTraits::to_char_type(c);
this->pbump(1);
return c;
}
}
}
else // c is EOF, so we don't have to do anything
return CharTraits::not_eof(c);
}
else // Overflow always fails if it's read-only.
return CharTraits::eof();
}
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{
bool in = false;
bool out = false;
const std::ios_base::openmode inout =
std::ios_base::in | std::ios_base::out;
if((mode & inout) == inout) {
if(dir == std::ios_base::beg || dir == std::ios_base::end)
in = out = true;
}
else if(mode & std::ios_base::in)
in = true;
else if(mode & std::ios_base::out)
out = true;
if(!in && !out)
return pos_type(off_type(-1));
else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) ||
(out && (!(m_mode & std::ios_base::out) || this->pptr() == 0)))
return pos_type(off_type(-1));
std::streamoff newoff;
switch(dir) {
case std::ios_base::beg:
newoff = 0;
break;
case std::ios_base::end:
newoff = static_cast<std::streamoff>(m_length);
break;
case std::ios_base::cur:
newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
: static_cast<std::streamoff>(this->pptr() - this->pbase());
break;
default:
return pos_type(off_type(-1));
}
off += newoff;
if(in) {
std::ptrdiff_t n = this->egptr() - this->eback();
if(off < 0 || off > n)
return pos_type(off_type(-1));
else
this->setg(this->eback(), this->eback() + off, this->eback() + n);
}
if(out) {
std::ptrdiff_t n = this->epptr() - this->pbase();
if(off < 0 || off > n)
return pos_type(off_type(-1));
else {
this->setp(this->pbase(), this->pbase() + n);
this->pbump(off);
}
}
return pos_type(off);
}
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{ return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); }
private:
std::ios_base::openmode m_mode;
CharT * m_buffer;
std::size_t m_length;
};
/*!A basic_istream class that uses a fixed size character buffer
as its formatting buffer.*/
template <class CharT, class CharTraits>
class basic_ibufferstream
: public std::basic_istream<CharT, CharTraits>
{
public: // Typedefs
typedef typename std::basic_ios
<CharT, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_istream<char_type, CharTraits> base_t;
public:
/*!Constructor. Does not throw.*/
basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in)
: basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Assigns formatting buffer. Does not throw.*/
basic_ibufferstream(const CharT *buffer, std::size_t length,
std::ios_base::openmode mode = std::ios_base::in)
: basic_ios_t(), base_t(0),
m_buf(const_cast<CharT*>(buffer), length, mode | std::ios_base::in)
{ basic_ios_t::init(&m_buf); }
~basic_ibufferstream(){};
public:
/*!Returns the address of the stored stream buffer.*/
basic_bufferbuf<CharT, CharTraits>* rdbuf() const
{ return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&m_buf); }
/*!Returns the pointer and size of the internal buffer.
Does not throw.*/
std::pair<const CharT *, std::size_t> buffer() const
{ return m_buf.buffer(); }
/*!Sets the underlying buffer to a new value. Resets
stream position. Does not throw.*/
void buffer(const CharT *buffer, std::size_t length)
{ m_buf.buffer(const_cast<CharT*>(buffer), length); }
private:
basic_bufferbuf<CharT, CharTraits> m_buf;
};
/*!A basic_ostream class that uses a fixed size character buffer
as its formatting buffer.*/
template <class CharT, class CharTraits>
class basic_obufferstream
: public std::basic_ostream<CharT, CharTraits>
{
public:
typedef typename std::basic_ios
<CharT, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_ostream<char_type, CharTraits> base_t;
public:
/*!Constructor. Does not throw.*/
basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Assigns formatting buffer. Does not throw.*/
basic_obufferstream(CharT *buffer, std::size_t length,
std::ios_base::openmode mode = std::ios_base::out)
: basic_ios_t(), base_t(0),
m_buf(buffer, length, mode | std::ios_base::out)
{ basic_ios_t::init(&m_buf); }
~basic_obufferstream(){}
public:
/*!Returns the address of the stored stream buffer.*/
basic_bufferbuf<CharT, CharTraits>* rdbuf() const
{ return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&m_buf); }
/*!Returns the pointer and size of the internal buffer.
Does not throw.*/
std::pair<CharT *, std::size_t> buffer() const
{ return m_buf.buffer(); }
/*!Sets the underlying buffer to a new value. Resets
stream position. Does not throw.*/
void buffer(CharT *buffer, std::size_t length)
{ m_buf.buffer(buffer, length); }
private:
basic_bufferbuf<CharT, CharTraits> m_buf;
};
/*!A basic_iostream class that uses a fixed size character buffer
as its formatting buffer.*/
template <class CharT, class CharTraits>
class basic_bufferstream
: public std::basic_iostream<CharT, CharTraits>
{
public: // Typedefs
typedef typename std::basic_ios
<CharT, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_iostream<char_type, CharTraits> base_t;
public:
/*!Constructor. Does not throw.*/
basic_bufferstream(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(mode)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Assigns formatting buffer. Does not throw.*/
basic_bufferstream(CharT *buffer, std::size_t length,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(buffer, length, mode)
{ basic_ios_t::init(&m_buf); }
~basic_bufferstream(){}
public:
/*!Returns the address of the stored stream buffer.*/
basic_bufferbuf<CharT, CharTraits>* rdbuf() const
{ return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&m_buf); }
/*!Returns the pointer and size of the internal buffer.
Does not throw.*/
std::pair<CharT *, std::size_t> buffer() const
{ return m_buf.buffer(); }
/*!Sets the underlying buffer to a new value. Resets
stream position. Does not throw.*/
void buffer(CharT *buffer, std::size_t length)
{ m_buf.buffer(buffer, length); }
private:
basic_bufferbuf<CharT, CharTraits> m_buf;
};
//Some typedefs to simplify usage
typedef basic_bufferbuf<char> bufferbuf;
typedef basic_bufferstream<char> bufferstream;
typedef basic_ibufferstream<char> ibufferstream;
typedef basic_obufferstream<char> obufferstream;
typedef basic_bufferbuf<wchar_t> wbufferbuf;
typedef basic_bufferstream<wchar_t> wbufferstream;
typedef basic_ibufferstream<wchar_t> wibufferstream;
typedef basic_obufferstream<wchar_t> wobufferstream;
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */

View File

@@ -0,0 +1,629 @@
/*
* Copyright (c) 1998
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's sstream file. Modified by Ion Gaztañaga 2005.
// Changed internal SGI string to a generic, templatized string. Added efficient
// internal buffer get/set/swap functions, so that we can obtain/establish the
// internal buffer without any reallocation or copy. Kill those temporaries!
///////////////////////////////////////////////////////////////////////////////
/*!\file
This file defines basic_stringbuf, basic_istringstream,
basic_ostringstream, and basic_stringstreamclasses. These classes
represent streamsbufs and streams whose sources or destinations are
STL-like strings that can be swapped with external strings to avoid
unnecessary allocations/copies.
*/
#ifndef BOOST_INTERPROCESS_STRINGSTREAM_HPP
#define BOOST_INTERPROCESS_STRINGSTREAM_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <iosfwd>
#include <ios>
#include <istream>
#include <ostream>
#include <string> // char traits
#include <cstddef> // ptrdiff_t
#include <boost/interprocess/interprocess_fwd.hpp>
#include <assert.h>
namespace boost { namespace interprocess {
/*!A streambuf class that controls the transmission of elements to and from
a basic_istringstream, basic_ostringstream or basic_stringstream.
It holds a character string specified by CharString template parameter
as its formatting buffer. The string must have contiguous storage, like
std::string, boost::interprocess::string or boost::interprocess::basic_string*/
template <class CharString, class CharTraits>
class basic_stringbuf
: public std::basic_streambuf<typename CharString::value_type, CharTraits>
{
public:
typedef CharString string_type;
typedef typename CharString::value_type char_type;
typedef typename CharTraits::int_type int_type;
typedef typename CharTraits::pos_type pos_type;
typedef typename CharTraits::off_type off_type;
typedef CharTraits traits_type;
private:
typedef std::basic_streambuf<char_type, traits_type> base_t;
basic_stringbuf(const basic_stringbuf&);
basic_stringbuf & operator =(const basic_stringbuf&);
public:
/*!Constructor. Throws if string_type default constructor throws.*/
explicit basic_stringbuf(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: base_t(), m_mode(mode)
{ this->set_pointers(); }
/*!Constructor. Throws if string_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
explicit basic_stringbuf(const VectorParameter &param,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: base_t(), m_mode(mode), m_string(param)
{ this->set_pointers(); }
virtual ~basic_stringbuf(){}
public:
/*!Swaps the underlying string with the passed string.
This function resets the read/write position in the stream.
Does not throw.*/
void swap_string(string_type &vect)
{ m_string.swap(vect); this->set_pointers(); }
/*!Returns a const reference to the internal string.
Does not throw.*/
const string_type &string() const { return m_string; }
/*!Calls resize() method of the internal string.
Resets the stream to the first position.
Throws if the internals string's resize throws.*/
void resize(typename string_type::size_type size)
{ m_string.resize(size); this->set_pointers(); }
private:
void set_pointers()
{
// The initial read position is the beginning of the string.
if(m_mode & std::ios_base::in)
this->setg(&m_string[0], &m_string[0], &m_string[m_string.size()]);
// The initial write position is the beginning of the string.
if(m_mode & std::ios_base::out)
this->setp(&m_string[0], &m_string[m_string.size()]);
}
protected:
virtual int_type underflow()
{
// Precondition: gptr() >= egptr(). Returns a character, if available.
return this->gptr() != this->egptr()
? CharTraits::to_int_type(*this->gptr())
: CharTraits::eof();
}
virtual int_type uflow()
{
// Precondition: gptr() >= egptr().
if(this->gptr() != this->egptr()) {
int_type c = CharTraits::to_int_type(*this->gptr());
this->gbump(1);
return c;
}
else
return CharTraits::eof();
}
virtual int_type pbackfail(int_type c = CharTraits::eof())
{
if(this->gptr() != this->eback()) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
this->gbump(-1);
return c;
}
else if(m_mode & std::ios_base::out) {
this->gbump(-1);
*this->gptr() = c;
return c;
}
else
return CharTraits::eof();
}
else {
this->gbump(-1);
return CharTraits::not_eof(c);
}
}
else
return CharTraits::eof();
}
virtual int_type overflow(int_type c = CharTraits::eof())
{
if(m_mode & std::ios_base::out) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(!(m_mode & std::ios_base::in)) {
if(this->pptr() != this->epptr()) {
*this->pptr() = CharTraits::to_char_type(c);
this->pbump(1);
return c;
}
else
return CharTraits::eof();
}
else {
// We're not using a special append buffer, just the string itself.
if(this->pptr() == this->epptr()) {
std::ptrdiff_t offset = this->gptr() - this->eback();
m_string.push_back(CharTraits::to_char_type(c));
this->setg(&m_string[0], &m_string[offset], &m_string[m_string.size()]);
this->setp(&m_string[0], &m_string[m_string.size()]);
this->pbump(static_cast<int>(m_string.size()));
return c;
}
else {
*this->pptr() = CharTraits::to_char_type(c);
this->pbump(1);
return c;
}
}
}
else // c is EOF, so we don't have to do anything
return CharTraits::not_eof(c);
}
else // Overflow always fails if it's read-only.
return CharTraits::eof();
}
virtual std::streamsize xsputn(const char_type* s, std::streamsize n)
{
std::streamsize nwritten = 0;
if((m_mode & std::ios_base::out) && n > 0) {
// If the put pointer is somewhere in the middle of the
// string, then overwrite instead of append.
assert(this->pbase() == &m_string[0]);
// if(this->pbase() == &m_string[0]) {
std::streamsize avail = static_cast<std::streamsize>(
&m_string[m_string.size()] - this->pptr());
if(avail > n) {
CharTraits::copy(this->pptr(), s, n);
this->pbump(n);
return n;
}
else if(avail){
CharTraits::copy(this->pptr(), s, avail);
nwritten += avail;
n -= avail;
s += avail;
}
// }
// At this point we know we're appending.
if(m_mode & std::ios_base::in) {
std::ptrdiff_t get_offset = this->gptr() - this->eback();
m_string.insert(m_string.end(), s, s + n);
this->setg(&m_string[0], &m_string[get_offset], &m_string[m_string.size()]);
this->setp(&m_string[0], &m_string[m_string.size()]);
this->pbump(static_cast<int>(m_string.size()));
}
else {
m_string.insert(m_string.end(), s, s + n);
}
nwritten += n;
}
return nwritten;
}
virtual std::streamsize xsputnc(char_type c, std::streamsize n)
{
std::streamsize nwritten = 0;
if((m_mode & std::ios_base::out) && n > 0) {
// If the put pointer is somewhere in the middle of the string,
// then overwrite instead of append.
assert(this->pbase() == &m_string[0]);
// if(this->pbase() == &m_string[0]) {
std::streamsize avail = static_cast<std::streamsize>
(&m_string[m_string.size()] - this->pptr());
if(avail > n) {
CharTraits::assign(this->pptr(), n, c);
this->pbump(n);
return n;
}
else if(avail){
CharTraits::assign(this->pptr(), avail, c);
nwritten += avail;
n -= avail;
}
// }
// At this point we know we're appending.
if(this->m_mode & std::ios_base::in) {
std::streamsize get_offset = static_cast<std::streamsize>
(this->gptr() - this->eback());
m_string.insert(m_string.end(), n, c);
this->setg(&m_string[0], &m_string[get_offset], &m_string[m_string.size()]);
this->setp(&m_string[0], &m_string[m_string.size()]);
this->pbump(static_cast<int>(m_string.size()));
}
else {
m_string.insert(m_string.end(), n, c);
}
nwritten += n;
}
return nwritten;
}
virtual base_t* setbuf(char_type* buf, std::streamsize n)
{
// According to the C++ standard the effects of setbuf are implementation
// defined, except that setbuf(0, 0) has no effect. In this implementation,
// setbuf(<anything>, n), for n > 0, calls resize(n) on the underlying
// string.
if(n > 0) {
// bool do_get_area = false;
// bool do_put_area = false;
std::ptrdiff_t offg = 0;
std::ptrdiff_t offp = 0;
assert(this->pbase() == &m_string[0]);
//if(this->pbase() == &m_string[0]) {
//do_put_area = true;
offp = this->pptr() - this->pbase();
//}
assert(this->eback() == &m_string[0]);
//if(this->eback() == &m_string[0]) {
//do_get_area = true;
offg = this->gptr() - this->eback();
//}
m_string.resize(n);
//if(do_get_area) {
this->setg(&m_string[0], &m_string[offg], &m_string[m_string.size()]);
//}
//if(do_put_area) {
this->setp(&m_string[0], &m_string[m_string.size()]);
this->pbump(static_cast<int>(offp));
//}
}
return this;
}
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{
bool in = false;
bool out = false;
const std::ios_base::openmode inout =
std::ios_base::in | std::ios_base::out;
if((mode & inout) == inout) {
if(dir == std::ios_base::beg || dir == std::ios_base::end)
in = out = true;
}
else if(mode & std::ios_base::in)
in = true;
else if(mode & std::ios_base::out)
out = true;
if(!in && !out)
return pos_type(off_type(-1));
else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) ||
(out && (!(m_mode & std::ios_base::out) || this->pptr() == 0)))
return pos_type(off_type(-1));
std::streamoff newoff;
switch(dir) {
case std::ios_base::beg:
newoff = 0;
break;
case std::ios_base::end:
newoff = static_cast<std::streamoff>(m_string.size());
break;
case std::ios_base::cur:
newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
: static_cast<std::streamoff>(this->pptr() - this->pbase());
break;
default:
return pos_type(off_type(-1));
}
off += newoff;
if(in) {
std::ptrdiff_t n = this->egptr() - this->eback();
if(off < 0 || off > n)
return pos_type(off_type(-1));
else
this->setg(this->eback(), this->eback() + off, this->eback() + n);
}
if(out) {
std::ptrdiff_t n = this->epptr() - this->pbase();
if(off < 0 || off > n)
return pos_type(off_type(-1));
else {
this->setp(this->pbase(), this->pbase() + n);
this->pbump(off);
}
}
return pos_type(off);
}
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{
bool in = (mode & std::ios_base::in) != 0;
bool out = (mode & std::ios_base::out) != 0;
if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) ||
(out && (!(m_mode & std::ios_base::out) || this->pptr() == 0)))
return pos_type(off_type(-1));
const off_type n = pos - pos_type(off_type(0));
if(in) {
if(n < 0 || n > this->egptr() - this->eback())
return pos_type(off_type(-1));
this->setg(this->eback(), this->eback() + n, this->egptr());
}
if(out) {
if(n < 0 || n > off_type(m_string.size()))
return pos_type(off_type(-1));
this->setp(&m_string[0], &m_string[m_string.size()]);
this->pbump(n);
}
return pos;
}
private:
std::ios_base::openmode m_mode;
string_type m_string;
};
/*!A basic_istream class that holds a character string specified by CharString
template parameter as its formatting buffer. The string must have
contiguous storage, like std::string, boost::interprocess::string or
boost::interprocess::basic_string*/
template <class CharString, class CharTraits>
class basic_istringstream
: public std::basic_istream<typename CharString::value_type, CharTraits>
{
public:
typedef CharString string_type;
typedef typename std::basic_ios
<typename CharString::value_type, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_istream<char_type, CharTraits> base_t;
public:
/*!Constructor. Throws if string_type default constructor throws.*/
basic_istringstream(std::ios_base::openmode mode = std::ios_base::in)
: basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Throws if string_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
basic_istringstream(const VectorParameter &param,
std::ios_base::openmode mode = std::ios_base::in)
: basic_ios_t(), base_t(0),
m_buf(param, mode | std::ios_base::in)
{ basic_ios_t::init(&m_buf); }
~basic_istringstream(){};
public:
/*!Returns the address of the stored stream buffer.*/
basic_stringbuf<CharString, CharTraits>* rdbuf() const
{ return const_cast<basic_stringbuf<CharString, CharTraits>*>(&m_buf); }
/*!Swaps the underlying string with the passed string.
This function resets the read position in the stream.
Does not throw.*/
void swap_string(string_type &vect)
{ m_buf.swap_string(vect); }
/*!Returns a const reference to the internal string.
Does not throw.*/
const string_type &string() const
{ return m_buf.string(); }
/*!Calls resize() method of the internal string.
Resets the stream to the first position.
Throws if the internals string's resize throws.*/
void resize(typename string_type::size_type size)
{ m_buf.resize(size); }
private:
basic_stringbuf<CharString, CharTraits> m_buf;
};
/*!A basic_ostream class that holds a character string specified by CharString
template parameter as its formatting buffer. The string must have
contiguous storage, like std::string, boost::interprocess::string or
boost::interprocess::basic_string*/
template <class CharString, class CharTraits>
class basic_ostringstream
: public std::basic_ostream<typename CharString::value_type, CharTraits>
{
public:
typedef CharString string_type;
typedef typename std::basic_ios
<typename CharString::value_type, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_ostream<char_type, CharTraits> base_t;
public:
/*!Constructor. Throws if string_type default constructor throws.*/
basic_ostringstream(std::ios_base::openmode mode = std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Throws if string_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
basic_ostringstream(const VectorParameter &param,
std::ios_base::openmode mode = std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(param, mode | std::ios_base::out)
{ basic_ios_t::init(&m_buf); }
~basic_ostringstream(){}
public:
/*!Returns the address of the stored stream buffer.*/
basic_stringbuf<CharString, CharTraits>* rdbuf() const
{ return const_cast<basic_stringbuf<CharString, CharTraits>*>(&m_buf); }
/*!Swaps the underlying string with the passed string.
This function resets the write position in the stream.
Does not throw.*/
void swap_string(string_type &vect)
{ m_buf.swap_string(vect); }
/*!Returns a const reference to the internal string.
Does not throw.*/
const string_type &string() const
{ return m_buf.string(); }
/*!Calls resize() method of the internal string.
Resets the stream to the first position.
Throws if the internals string's resize throws.*/
void resize(typename string_type::size_type size)
{ m_buf.resize(size); }
private:
basic_stringbuf<CharString, CharTraits> m_buf;
};
/*!A basic_iostream class that holds a character string specified by CharString
template parameter as its formatting buffer. The string must have
contiguous storage, like std::string, boost::interprocess::string or
boost::interprocess::basic_string*/
template <class CharString, class CharTraits>
class basic_stringstream
: public std::basic_iostream<typename CharString::value_type, CharTraits>
{
public:
typedef CharString string_type;
typedef typename std::basic_ios
<typename CharString::value_type, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_iostream<char_type, CharTraits> base_t;
public:
/*!Constructor. Throws if string_type default constructor throws.*/
basic_stringstream(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(mode)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Throws if string_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
basic_stringstream(const VectorParameter &param, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(param, mode)
{ basic_ios_t::init(&m_buf); }
~basic_stringstream(){}
public:
//Returns the address of the stored stream buffer.
basic_stringbuf<CharString, CharTraits>* rdbuf() const
{ return const_cast<basic_stringbuf<CharString, CharTraits>*>(&m_buf); }
/*!Swaps the underlying string with the passed string.
This function resets the read/write position in the stream.
Does not throw.*/
void swap_string(string_type &vect)
{ m_buf.swap_string(vect); }
/*!Returns a const reference to the internal string.
Does not throw.*/
const string_type &string() const
{ return m_buf.string(); }
/*!Calls resize() method of the internal string.
Resets the stream to the first position.
Throws if the internals string's resize throws.*/
void resize(typename string_type::size_type size)
{ m_buf.resize(size); }
private:
basic_stringbuf<CharString, CharTraits> m_buf;
};
//Some typedefs to simplify usage
/*
typedef basic_stringbuf<std::string<char> > stringbuf;
typedef basic_stringstream<std::string<char> > stringstream;
typedef basic_istringstream<std::string<char> > istringstream;
typedef basic_ostringstream<std::string<char> > ostringstream;
typedef basic_stringbuf<std::string<wchar_t> > wstringbuf;
typedef basic_stringstream<std::string<wchar_t> > wstringstream;
typedef basic_istringstream<std::string<wchar_t> > wistringstream;
typedef basic_ostringstream<std::string<wchar_t> > wostringstream;
*/
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_STRINGSTREAM_HPP */

View File

@@ -0,0 +1,544 @@
/*
* Copyright (c) 1998
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// This file comes from SGI's sstream file. Modified by Ion Gaztañaga 2005.
// Changed internal SGI string to a generic, templatized vector. Added efficient
// internal buffer get/set/swap functions, so that we can obtain/establish the
// internal buffer without any reallocation or copy. Kill those temporaries!
///////////////////////////////////////////////////////////////////////////////
/*!\file
This file defines basic_vectorbuf, basic_ivectorstream,
basic_ovectorstream, and basic_vectorstreamclasses. These classes
represent streamsbufs and streams whose sources or destinations are
STL-like vectors that can be swapped with external vectors to avoid
unnecessary allocations/copies.
*/
#ifndef BOOST_INTERPROCESS_VECTORSTREAM_HPP
#define BOOST_INTERPROCESS_VECTORSTREAM_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <iosfwd>
#include <ios>
#include <istream>
#include <ostream>
#include <string> // char traits
#include <cstddef> // ptrdiff_t
#include <boost/interprocess/interprocess_fwd.hpp>
#include <assert.h>
namespace boost { namespace interprocess {
/*!A streambuf class that controls the transmission of elements to and from
a basic_ivectorstream, basic_ovectorstream or basic_vectorstream.
It holds a character vector specified by CharVector template parameter
as its formatting buffer. The vector must have contiguous storage, like
std::vector, boost::interprocess::vector or boost::interprocess::basic_string*/
template <class CharVector, class CharTraits>
class basic_vectorbuf
: public std::basic_streambuf<typename CharVector::value_type, CharTraits>
{
public:
typedef CharVector vector_type;
typedef typename CharVector::value_type char_type;
typedef typename CharTraits::int_type int_type;
typedef typename CharTraits::pos_type pos_type;
typedef typename CharTraits::off_type off_type;
typedef CharTraits traits_type;
private:
typedef std::basic_streambuf<char_type, traits_type> base_t;
basic_vectorbuf(const basic_vectorbuf&);
basic_vectorbuf & operator =(const basic_vectorbuf&);
public:
/*!Constructor. Throws if vector_type default constructor throws.*/
explicit basic_vectorbuf(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: base_t(), m_mode(mode)
{ this->set_pointers(); }
/*!Constructor. Throws if vector_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
explicit basic_vectorbuf(const VectorParameter &param,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: base_t(), m_mode(mode), m_vect(param)
{ this->set_pointers(); }
virtual ~basic_vectorbuf(){}
public:
/*!Swaps the underlying vector with the passed vector.
This function resets the read/write position in the stream.
Does not throw.*/
void swap_vector(vector_type &vect)
{
//Update high water if necessary
//And resize vector to remove extra size
if (this->m_mode & std::ios_base::out){
if (mp_high_water < base_t::pptr()){
//Restore the vector's size if necessary
mp_high_water = base_t::pptr();
}
m_vect.resize(mp_high_water - &m_vect[0]);
}
//Now swap vector
m_vect.swap(vect);
//Now update pointer data
typename vector_type::size_type old_size = m_vect.size();
m_vect.resize(m_vect.capacity());
this->set_pointers();
mp_high_water = &m_vect[0] + old_size;
}
/*!Returns a const reference to the internal vector.
Does not throw.*/
const vector_type &vector() const
{
if (this->m_mode & std::ios_base::out){
if (mp_high_water < base_t::pptr()){
//Restore the vector's size if necessary
mp_high_water = base_t::pptr();
}
m_vect.resize(mp_high_water - &m_vect[0]);
const_cast<basic_vectorbuf * const>(this)->set_pointers();
}
return m_vect;
}
/*!Calls reserve() method of the internal vector.
Resets the stream to the first position.
Throws if the internals vector's reserve throws.*/
void reserve(typename vector_type::size_type size)
{
m_vect.reserve(size);
//Now update pointer data
typename vector_type::size_type old_size = m_vect.size();
m_vect.resize(m_vect.capacity());
this->set_pointers();
mp_high_water = &m_vect[0] + old_size;
}
/*!Calls clear() method of the internal vector.
Resets the stream to the first position.*/
void clear()
{ m_vect.clear(); this->set_pointers(); }
private:
void set_pointers()
{
// The initial read position is the beginning of the vector.
if(m_mode & std::ios_base::in)
setg(&m_vect[0], &m_vect[0], &m_vect[m_vect.size()]);
// The initial write position is the beginning of the vector.
if(m_mode & std::ios_base::out){
this->setp(&m_vect[0], &m_vect[m_vect.size()]);
if (m_mode & (std::ios_base::app | std::ios_base::ate))
base_t::pbump((int)m_vect.size());
}
mp_high_water = &m_vect[0] + m_vect.size();
}
protected:
virtual int_type underflow()
{
if (base_t::gptr() == 0)
return CharTraits::eof();
if (mp_high_water < base_t::pptr())
mp_high_water = base_t::pptr();
if (base_t::egptr() < mp_high_water)
base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water);
if (base_t::gptr() < base_t::egptr())
return CharTraits::to_int_type(*base_t::gptr());
return CharTraits::eof();
}
virtual int_type pbackfail(int_type c = CharTraits::eof())
{
if(this->gptr() != this->eback()) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
this->gbump(-1);
return c;
}
else if(m_mode & std::ios_base::out) {
this->gbump(-1);
*this->gptr() = c;
return c;
}
else
return CharTraits::eof();
}
else {
this->gbump(-1);
return CharTraits::not_eof(c);
}
}
else
return CharTraits::eof();
}
virtual int_type overflow(int_type c = CharTraits::eof())
{
if(m_mode & std::ios_base::out) {
if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
if(!(m_mode & std::ios_base::in)) {
if(this->pptr() < this->epptr()) {
*this->pptr() = CharTraits::to_char_type(c);
this->pbump(1);
if (mp_high_water < base_t::pptr())
mp_high_water = base_t::pptr();
if ((m_mode & std::ios_base::in) && base_t::egptr() < mp_high_water)
base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water);
return c;
}
else
return CharTraits::eof();
}
else {
try{
typedef typename vector_type::difference_type dif_t;
dif_t inpos = base_t::gptr() - base_t::eback();
dif_t outpos = base_t::pptr() - base_t::pbase() + 1;
dif_t hipos = mp_high_water - base_t::pbase();
if (hipos < outpos)
hipos = outpos;
m_vect.push_back(CharTraits::to_char_type(c));
m_vect.resize(m_vect.capacity());
char_type* p = const_cast<char_type*>(&m_vect[0]);
if (m_mode & std::ios_base::in)
base_t::setg(p, p + inpos, p + hipos);
base_t::setp(p, p + (dif_t)m_vect.size());
base_t::pbump((int)outpos);
mp_high_water = base_t::pbase() + hipos;
return c;
}
catch(...){
return CharTraits::eof();
}
}
}
else // c is EOF, so we don't have to do anything
return CharTraits::not_eof(c);
}
else // Overflow always fails if it's read-only.
return CharTraits::eof();
}
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{
bool in = false;
bool out = false;
const std::ios_base::openmode inout =
std::ios_base::in | std::ios_base::out;
if((mode & inout) == inout) {
if(dir == std::ios_base::beg || dir == std::ios_base::end)
in = out = true;
}
else if(mode & std::ios_base::in)
in = true;
else if(mode & std::ios_base::out)
out = true;
if(!in && !out)
return pos_type(off_type(-1));
else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) ||
(out && (!(m_mode & std::ios_base::out) || this->pptr() == 0)))
return pos_type(off_type(-1));
off_type newoff;
off_type limit = static_cast<off_type>
(mode & std::ios_base::out ?
mp_high_water - base_t::pbase() :
mp_high_water - base_t::eback()
);
switch(dir) {
case std::ios_base::beg:
newoff = 0;
break;
case std::ios_base::end:
newoff = limit;
break;
case std::ios_base::cur:
newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
: static_cast<std::streamoff>(this->pptr() - this->pbase());
break;
default:
return pos_type(off_type(-1));
}
newoff += off;
if (newoff < 0 || newoff > limit)
return pos_type(-1);
if (m_mode & std::ios_base::app && mode & std::ios_base::out && newoff != limit)
return pos_type(-1);
if (in)
base_t::setg(base_t::eback(), base_t::eback() + newoff, base_t::egptr());
if (out){
base_t::setp(base_t::pbase(), base_t::epptr());
base_t::pbump((int)newoff);
}
return pos_type(newoff);
}
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
{ return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); }
private:
std::ios_base::openmode m_mode;
mutable vector_type m_vect;
mutable char_type* mp_high_water;
};
/*!A basic_istream class that holds a character vector specified by CharVector
template parameter as its formatting buffer. The vector must have
contiguous storage, like std::vector, boost::interprocess::vector or
boost::interprocess::basic_string*/
template <class CharVector, class CharTraits>
class basic_ivectorstream
: public std::basic_istream<typename CharVector::value_type, CharTraits>
{
public:
typedef CharVector vector_type;
typedef typename std::basic_ios
<typename CharVector::value_type, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_istream<char_type, CharTraits> base_t;
public:
/*!Constructor. Throws if vector_type default constructor throws.*/
basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in)
: basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Throws if vector_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
basic_ivectorstream(const VectorParameter &param,
std::ios_base::openmode mode = std::ios_base::in)
: basic_ios_t(), base_t(0),
m_buf(param, mode | std::ios_base::in)
{ basic_ios_t::init(&m_buf); }
~basic_ivectorstream(){};
public:
/*!Returns the address of the stored stream buffer.*/
basic_vectorbuf<CharVector, CharTraits>* rdbuf() const
{ return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); }
/*!Swaps the underlying vector with the passed vector.
This function resets the read position in the stream.
Does not throw.*/
void swap_vector(vector_type &vect)
{ m_buf.swap_vector(vect); }
/*!Returns a const reference to the internal vector.
Does not throw.*/
const vector_type &vector() const
{ return m_buf.vector(); }
/*!Calls reserve() method of the internal vector.
Resets the stream to the first position.
Throws if the internals vector's reserve throws.*/
void reserve(typename vector_type::size_type size)
{ m_buf.reserve(size); }
/*!Calls clear() method of the internal vector.
Resets the stream to the first position.*/
void clear()
{ m_buf.clear(); }
private:
basic_vectorbuf<CharVector, CharTraits> m_buf;
};
/*!A basic_ostream class that holds a character vector specified by CharVector
template parameter as its formatting buffer. The vector must have
contiguous storage, like std::vector, boost::interprocess::vector or
boost::interprocess::basic_string*/
template <class CharVector, class CharTraits>
class basic_ovectorstream
: public std::basic_ostream<typename CharVector::value_type, CharTraits>
{
public:
typedef CharVector vector_type;
typedef typename std::basic_ios
<typename CharVector::value_type, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_ostream<char_type, CharTraits> base_t;
public:
/*!Constructor. Throws if vector_type default constructor throws.*/
basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Throws if vector_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
basic_ovectorstream(const VectorParameter &param,
std::ios_base::openmode mode = std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(param, mode | std::ios_base::out)
{ basic_ios_t::init(&m_buf); }
~basic_ovectorstream(){}
public:
/*!Returns the address of the stored stream buffer.*/
basic_vectorbuf<CharVector, CharTraits>* rdbuf() const
{ return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); }
/*!Swaps the underlying vector with the passed vector.
This function resets the write position in the stream.
Does not throw.*/
void swap_vector(vector_type &vect)
{ m_buf.swap_vector(vect); }
/*!Returns a const reference to the internal vector.
Does not throw.*/
const vector_type &vector() const
{ return m_buf.vector(); }
/*!Calls reserve() method of the internal vector.
Resets the stream to the first position.
Throws if the internals vector's reserve throws.*/
void reserve(typename vector_type::size_type size)
{ m_buf.reserve(size); }
private:
basic_vectorbuf<CharVector, CharTraits> m_buf;
};
/*!A basic_iostream class that holds a character vector specified by CharVector
template parameter as its formatting buffer. The vector must have
contiguous storage, like std::vector, boost::interprocess::vector or
boost::interprocess::basic_string*/
template <class CharVector, class CharTraits>
class basic_vectorstream
: public std::basic_iostream<typename CharVector::value_type, CharTraits>
{
public:
typedef CharVector vector_type;
typedef typename std::basic_ios
<typename CharVector::value_type, CharTraits>::char_type char_type;
typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
private:
typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
typedef std::basic_iostream<char_type, CharTraits> base_t;
public:
/*!Constructor. Throws if vector_type default constructor throws.*/
basic_vectorstream(std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(mode)
{ basic_ios_t::init(&m_buf); }
/*!Constructor. Throws if vector_type(const VectorParameter &param) throws.*/
template<class VectorParameter>
basic_vectorstream(const VectorParameter &param, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out)
: basic_ios_t(), base_t(0), m_buf(param, mode)
{ basic_ios_t::init(&m_buf); }
~basic_vectorstream(){}
public:
//Returns the address of the stored stream buffer.
basic_vectorbuf<CharVector, CharTraits>* rdbuf() const
{ return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); }
/*!Swaps the underlying vector with the passed vector.
This function resets the read/write position in the stream.
Does not throw.*/
void swap_vector(vector_type &vect)
{ m_buf.swap_vector(vect); }
/*!Returns a const reference to the internal vector.
Does not throw.*/
const vector_type &vector() const
{ return m_buf.vector(); }
/*!Calls reserve() method of the internal vector.
Resets the stream to the first position.
Throws if the internals vector's reserve throws.*/
void reserve(typename vector_type::size_type size)
{ m_buf.reserve(size); }
/*!Calls clear() method of the internal vector.
Resets the stream to the first position.*/
void clear()
{ m_buf.clear(); }
private:
basic_vectorbuf<CharVector, CharTraits> m_buf;
};
//Some typedefs to simplify usage
/*
typedef basic_vectorbuf<std::vector<char> > vectorbuf;
typedef basic_vectorstream<std::vector<char> > vectorstream;
typedef basic_ivectorstream<std::vector<char> > ivectorstream;
typedef basic_ovectorstream<std::vector<char> > ovectorstream;
typedef basic_vectorbuf<std::vector<wchar_t> > wvectorbuf;
typedef basic_vectorstream<std::vector<wchar_t> > wvectorstream;
typedef basic_ivectorstream<std::vector<wchar_t> > wivectorstream;
typedef basic_ovectorstream<std::vector<wchar_t> > wovectorstream;
*/
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif /* BOOST_INTERPROCESS_VECTORSTREAM_HPP */

View File

@@ -0,0 +1,159 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_FILE_LOCK_HPP
#define BOOST_INTERPROCESS_FILE_LOCK_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/exceptions.hpp>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <assert.h>
#include <boost/interprocess/detail/os_file_functions.hpp>
/*!\file
Describes file_lock
*/
namespace boost {
namespace interprocess {
/*!Wraps a file locking class, to implement mutual exclusion */
class file_lock : private boost::noncopyable
{
public:
file_lock(const char *name);
~file_lock();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void lock_sharable();
bool try_lock_sharable();
bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
void unlock_sharable();
private:
detail::OS_file_handle_t m_file_hnd;
};
inline file_lock::file_lock(const char *name)
{
m_file_hnd = detail::open_existing_file(name);
if(m_file_hnd == detail::invalid_file()){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline file_lock::~file_lock()
{
if(m_file_hnd != detail::invalid_file()){
detail::close_file(m_file_hnd);
m_file_hnd = detail::invalid_file();
}
}
inline void file_lock::lock()
{
if(!detail::acquire_file_lock(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline bool file_lock::try_lock()
{
bool result;
if(!detail::try_acquire_file_lock(m_file_hnd, result)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time)
{
bool result;
if(!detail::timed_acquire_file_lock(m_file_hnd, result, abs_time)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline void file_lock::unlock()
{
if(!detail::release_file_lock(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void file_lock::lock_sharable()
{
if(!detail::acquire_file_lock_sharable(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline bool file_lock::try_lock_sharable()
{
bool result;
if(!detail::try_acquire_file_lock_sharable(m_file_hnd, result)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time)
{
bool result;
if(!detail::timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
return result;
}
inline void file_lock::unlock_sharable()
{
if(!detail::release_file_lock_sharable(m_file_hnd)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_FILE_LOCK_HPP

View File

@@ -0,0 +1,156 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// barrier is a modified version of Boost Threads barrier
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2003
// David Moore, William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_INTERPROCESS_BARRIER_HPP
#define BOOST_INTERPROCESS_BARRIER_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
# include <pthread.h>
# include <errno.h>
# include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#else //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
# include <boost/interprocess/sync/interprocess_mutex.hpp>
# include <boost/interprocess/sync/scoped_lock.hpp>
# include <boost/interprocess/sync/interprocess_condition.hpp>
# include <stdexcept>
#endif //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
# include <boost/interprocess/exceptions.hpp>
namespace boost {
namespace interprocess {
/*!An object of class barrier is a synchronization primitive that
can be placed in shared memory used to cause a set of threads from
different processes to wait until they each perform a certain
function or each reach a particular point in their execution.*/
class barrier
{
public:
/*!Constructs a barrier object that will cause count threads
to block on a call to wait(). */
barrier(unsigned int count);
/*!Destroys *this. If threads are still executing their wait()
operations, the behavior for these threads is undefined.*/
~barrier();
/*!Effects: Wait until N threads call wait(), where N equals the count
provided to the constructor for the barrier object.
Note that if the barrier is destroyed before wait() can return,
the behavior is undefined.
Returns: Exactly one of the N threads will receive a return value
of true, the others will receive a value of false. Precisely which
thread receives the return value of true will be implementation-defined.
Applications can use this value to designate one thread as a leader that
will take a certain action, and the other threads emerging from the barrier
can wait for that action to take place.*/
bool wait();
private:
#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
pthread_barrier_t m_barrier;
#else //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
interprocess_mutex m_mutex;
interprocess_condition m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
#endif//#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
};
#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
inline barrier::barrier(unsigned int count)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
detail::barrierattr_wrapper barrier_attr;
detail::barrier_initializer barrier
(m_barrier, barrier_attr, static_cast<int>(count));
barrier.release();
}
inline barrier::~barrier()
{
int res = pthread_barrier_destroy(&m_barrier);
assert(res == 0);(void)res;
}
inline bool barrier::wait()
{
int res = pthread_barrier_wait(&m_barrier);
if (res != PTHREAD_BARRIER_SERIAL_THREAD || res != 0)
throw interprocess_exception(system_error_code());
return res == PTHREAD_BARRIER_SERIAL_THREAD;
}
#else //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
inline barrier::barrier(unsigned int count)
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
}
inline barrier::~barrier(){}
inline bool barrier::wait()
{
scoped_lock<interprocess_mutex> lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0){
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
while (gen == m_generation){
m_cond.wait(lock);
}
return false;
}
#endif //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif

View File

@@ -0,0 +1,146 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_CONDITION_HPP
#define BOOST_INTERPROCESS_CONDITION_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/date_time/posix_time/ptime.hpp>
//#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/limits.hpp>
#include <cassert>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else
# include <errno.h>
# include <pthread.h>
#endif
/*!\file
Describes process-shared variables interprocess_condition class
*/
namespace boost {
namespace posix_time
{ class ptime; }
namespace interprocess {
class interprocess_condition : private noncopyable
{
public:
/*!Constructs a interprocess_condition*/
interprocess_condition();
/*!Destroys *this*/
~interprocess_condition();
/*!If there is a thread waiting on *this, change that
thread's state to ready. Otherwise there is no effect.*/
void notify_one();
/*!Change the state of all threads waiting on *this to ready.
If there are no waiting threads, notify_all() has no effect.*/
void notify_all();
/*!Releases the lock on the interprocess_mutex object associated with lock, blocks
the current thread of execution until readied by a call to
this->notify_one() or this->notify_all(), and then reacquires the lock.*/
template <typename L>
void wait(L& lock)
{
if (!lock)
throw lock_exception();
do_wait(*lock.interprocess_mutex());
}
/*!The same as: while (!pred()) wait(lock)*/
template <typename L, typename Pr>
void wait(L& lock, Pr pred)
{
if (!lock)
throw lock_exception();
while (!pred())
do_wait(*lock.interprocess_mutex());
}
/*!Releases the lock on the interprocess_mutex object associated with lock, blocks
the current thread of execution until readied by a call to
this->notify_one() or this->notify_all(), or until time abs_time is reached,
and then reacquires the lock.
Returns: false if time abs_time is reached, otherwise true.*/
template <typename L>
bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
{
if (!lock)
throw lock_exception();
return do_timed_wait(abs_time, *lock.interprocess_mutex());
}
/*!The same as: while (!pred()) {
if (!timed_wait(lock, abs_time)) return false;
} return true;*/
template <typename L, typename Pr>
bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
{
if (!lock)
throw lock_exception();
while (!pred()){
if (!do_timed_wait(abs_time, *lock.interprocess_mutex()))
return false;
}
return true;
}
private:
void do_wait(interprocess_mutex &mut);
bool do_timed_wait(const boost::posix_time::ptime &abs_time, interprocess_mutex &mut);
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
enum { SLEEP, NOTIFY_ONE, NOTIFY_ALL };
interprocess_mutex m_enter_mut;
interprocess_mutex m_check_mut;
volatile long m_command;
volatile long m_num_waiters;
bool do_timed_wait(bool tout_enabled, const boost::posix_time::ptime &abs_time, interprocess_mutex &mut);
void notify(long command);
#else
pthread_cond_t m_condition;
#endif
};
} //namespace interprocess
} // namespace boost
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/interprocess_condition.hpp>
#else
# include <boost/interprocess/sync/posix/interprocess_condition.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_CONDITION_HPP

View File

@@ -0,0 +1,105 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code.
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MUTEX_HPP
#define BOOST_INTERPROCESS_MUTEX_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/noncopyable.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <assert.h>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <pthread.h>
# include <errno.h>
# include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes interprocess_mutex class
*/
namespace boost {
namespace interprocess {
class interprocess_condition;
/*!Wraps a interprocess_mutex that can be placed in shared memory and can be
shared between processes. Allows timed lock tries*/
class interprocess_mutex : private boost::noncopyable
{
friend class interprocess_condition;
public:
interprocess_mutex();
~interprocess_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
private:
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
volatile long m_s;
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#ifdef _POSIX_TIMEOUTS
pthread_mutex_t m_mut;
#else
pthread_mutex_t m_mut;
pthread_cond_t m_cond;
bool m_locked;
#endif
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
};
} //namespace interprocess {
} //namespace boost {
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/interprocess_mutex.hpp>
#else
# include <boost/interprocess/sync/posix/interprocess_mutex.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MUTEX_HPP

View File

@@ -0,0 +1,114 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code:
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_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/noncopyable.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <assert.h>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <pthread.h>
# include <errno.h>
# include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes
*/
namespace boost {
namespace interprocess {
/*!Wraps a interprocess_mutex that can be placed in shared memory and can be
shared between processes. Allows several locking calls by the same
process. Allows timed lock tries*/
class interprocess_recursive_mutex : private boost::noncopyable
{
public:
interprocess_recursive_mutex();
~interprocess_recursive_mutex();
/*!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked.
Throws interprocess_exception if a severe error is found*/
void lock(void);
/*! Tries to lock the interprocess_mutex, returns false when interprocess_mutex
is already locked, returns true when success.
Throws interprocess_exception if a severe error is found*/
bool try_lock(void);
/*! Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before
abs_time time, returns false.
Throws interprocess_exception if a severe error is found*/
bool timed_lock(const boost::posix_time::ptime &abs_time);
/*! Unlocks the interprocess_mutex */
void unlock(void);
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
interprocess_mutex m_shared_timed_mutex;
unsigned int m_nLockCount;
unsigned long m_nOwner;
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined _POSIX_TIMEOUTS
pthread_mutex_t m_mut;
#else //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined _POSIX_TIMEOUTS
pthread_mutex_t m_mut;
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
unsigned int m_count;
#endif //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined _POSIX_TIMEOUTS
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
};
} //namespace interprocess {
} //namespace boost {
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/interprocess_recursive_mutex.hpp>
#else
# include <boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP

View File

@@ -0,0 +1,108 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_SEMAPHORE_HPP
#define BOOST_INTERPROCESS_SEMAPHORE_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/detail/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/noncopyable.hpp>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
# include <boost/interprocess/sync/interprocess_mutex.hpp>
# include <boost/interprocess/sync/interprocess_condition.hpp>
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#include <fcntl.h> //O_CREAT, O_*...
#include <unistd.h> //close
#include <string> //std::string
#include <semaphore.h> //sem_* family, SEM_VALUE_MAX
#include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
#include <boost/interprocess/sync/posix/semaphore_wrapper.hpp> //for shared_memory
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes a interprocess_semaphore class for inter-process synchronization
*/
namespace boost {
namespace interprocess {
/*!Wraps a interprocess_semaphore that can be placed in shared memory and can be
shared between processes. Allows timed lock tries*/
class interprocess_semaphore : private boost::noncopyable
{
public:
/*!Creates a interprocess_semaphore with the given initial count.
interprocess_exception if there is an error.*/
interprocess_semaphore(int initialCount);
/*!Destroys the interprocess_semaphore. Does not throw*/
~interprocess_semaphore();
/*!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting
for the interprocess_semaphore, then one of these processes will return successfully from
its wait function. If there is an error an interprocess_exception exception is thrown.*/
void post();
/*!Decrements the interprocess_semaphore. If the interprocess_semaphore value is not greater than zero,
then the calling process/thread blocks until it can decrement the counter.
If there is an error an interprocess_exception exception is thrown.*/
void wait();
/*!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater than zero
and returns true. If the value is not greater than zero returns false.
If there is an error an interprocess_exception exception is thrown.*/
bool try_wait();
/*!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater
than zero and returns true. Otherwise, waits for the interprocess_semaphore
to the posted or the timeout expires. If the timeout expires, the
function returns false. If the interprocess_semaphore is posted the function
returns true. If there is an error throws sem_exception*/
bool timed_wait(const boost::posix_time::ptime &abs_time);
/*!Returns the interprocess_semaphore count*/
// int get_count() const;
private:
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
interprocess_mutex m_mut;
interprocess_condition m_cond;
int m_count;
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
detail::semaphore_wrapper m_sem;
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
};
} //namespace interprocess {
} //namespace boost {
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/interprocess_semaphore.hpp>
#else
# include <boost/interprocess/sync/posix/interprocess_semaphore.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_SEMAPHORE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,523 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_UPGRADABLE_MUTEX_HPP
#define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_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/noncopyable.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <limits.h>
/*!\file
Describes interprocess_upgradabel_mutex class
*/
namespace boost {
namespace interprocess {
/*!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
shared between processes. Allows timed lock tries*/
class interprocess_upgradable_mutex : private boost::noncopyable
{
friend class interprocess_condition;
public:
interprocess_upgradable_mutex();
~interprocess_upgradable_mutex();
//Exlusive locking
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
//Upgradable locking
void lock_upgradable();
bool try_lock_upgradable();
bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
void unlock_upgradable();
//Sharable locking
void lock_sharable();
bool try_lock_sharable();
bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
void unlock_sharable();
//Downgrading
void unlock_and_lock_upgradable();
void unlock_and_lock_sharable();
void unlock_upgradable_and_lock_sharable();
//Upgrading
void unlock_upgradable_and_lock();
bool try_unlock_upgradable_and_lock();
bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
bool try_unlock_sharable_and_lock();
bool try_unlock_sharable_and_lock_upgradable();
private:
typedef scoped_lock<interprocess_mutex> scoped_lock_t;
//Pack all the control data in a word to be able
//to use atomic instructions in the future
struct control_word_t
{
unsigned exclusive_in : 1;
unsigned upgradable_in : 1;
unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2;
} m_ctrl;
interprocess_mutex m_mut;
interprocess_condition m_first_gate;
interprocess_condition m_second_gate;
private:
//Rollback structures for exceptions or failure return values
struct exclusive_rollback
{
exclusive_rollback(control_word_t &ctrl
,interprocess_condition &first_gate)
: mp_ctrl(&ctrl), m_first_gate(first_gate)
{}
void release()
{ mp_ctrl = 0; }
~exclusive_rollback()
{
if(mp_ctrl){
mp_ctrl->exclusive_in = 0;
m_first_gate.notify_all();
}
}
control_word_t *mp_ctrl;
interprocess_condition &m_first_gate;
};
struct upgradable_to_exclusive_rollback
{
upgradable_to_exclusive_rollback(control_word_t &ctrl)
: mp_ctrl(&ctrl)
{}
void release()
{ mp_ctrl = 0; }
~upgradable_to_exclusive_rollback()
{
if(mp_ctrl){
//Recover upgradable lock
mp_ctrl->upgradable_in = 1;
++mp_ctrl->num_upr_shar;
//Execute the second half of exclusive locking
mp_ctrl->exclusive_in = 0;
}
}
control_word_t *mp_ctrl;
};
};
inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
{
this->m_ctrl.exclusive_in = 0;
this->m_ctrl.upgradable_in = 0;
this->m_ctrl.num_upr_shar = 0;
}
inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
{}
inline void interprocess_upgradable_mutex::lock()
{
scoped_lock_t lock(m_mut);
//The exclusive lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
this->m_first_gate.wait(lock);
}
//Mark that exclusive lock has been acquired
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
//Now wait until all readers are gone
while (this->m_ctrl.num_upr_shar){
this->m_second_gate.wait(lock);
}
rollback.release();
}
inline bool interprocess_upgradable_mutex::try_lock()
{
scoped_lock_t lock(m_mut, try_to_lock);
//If we can't lock or any has there is any exclusive, upgradable
//or sharable mark return false;
if(!lock.locked()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar){
return false;
}
this->m_ctrl.exclusive_in = 1;
return true;
}
inline bool interprocess_upgradable_mutex::timed_lock
(const boost::posix_time::ptime &abs_time)
{
scoped_lock_t lock(m_mut, abs_time);
if(!lock.locked()) return false;
//The exclusive lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
if(!this->m_first_gate.timed_wait(lock, abs_time))
return false;
}
//Mark that exclusive lock has been acquired
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
//Now wait until all readers are gone
while (this->m_ctrl.num_upr_shar){
if(!this->m_second_gate.timed_wait(lock, abs_time)){
return false;
}
}
rollback.release();
return true;
}
inline void interprocess_upgradable_mutex::unlock()
{
scoped_lock_t lock(m_mut);
this->m_ctrl.exclusive_in = 0;
this->m_first_gate.notify_all();
}
//Upgradable locking
inline void interprocess_upgradable_mutex::lock_upgradable()
{
scoped_lock_t lock(m_mut);
//The upgradable lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
//or there are too many sharable locks
while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
|| ((~this->m_ctrl.num_upr_shar) == 0)){
this->m_first_gate.wait(lock);
}
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 1;
++this->m_ctrl.num_upr_shar;
}
inline bool interprocess_upgradable_mutex::try_lock_upgradable()
{
scoped_lock_t lock(m_mut, try_to_lock);
//The upgradable lock must fail
//if an exclusive or upgradable lock has been acquired
//or there are too many sharable locks
if(!lock.locked()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in
|| ((~this->m_ctrl.num_upr_shar) == 0)){
return false;
}
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 1;
++this->m_ctrl.num_upr_shar;
}
inline bool interprocess_upgradable_mutex::timed_lock_upgradable
(const boost::posix_time::ptime &abs_time)
{
scoped_lock_t lock(m_mut, abs_time);
if(!lock.locked()) return false;
//The upgradable lock must block in the first gate
//if an exclusive or upgradable lock has been acquired
//or there are too many sharable locks
while(this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in
|| ((~this->m_ctrl.num_upr_shar) == 0)){
if(!this->m_first_gate.timed_wait(lock, abs_time)){
return false;
}
}
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 1;
++this->m_ctrl.num_upr_shar;
return true;
}
inline void interprocess_upgradable_mutex::unlock_upgradable()
{
scoped_lock_t lock(m_mut);
//Mark that upgradable lock has been acquired
//And add upgradable to the sharable count
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
this->m_first_gate.notify_all();
}
//Sharable locking
inline void interprocess_upgradable_mutex::lock_sharable()
{
scoped_lock_t lock(m_mut);
//The sharable lock must block in the first gate
//if an exclusive lock has been acquired
//or there are too many sharable locks
while(this->m_ctrl.exclusive_in
|| ((~this->m_ctrl.num_upr_shar) == 0)){
this->m_first_gate.wait(lock);
}
//Increment sharable count
++this->m_ctrl.num_upr_shar;
}
inline bool interprocess_upgradable_mutex::try_lock_sharable()
{
scoped_lock_t lock(m_mut, try_to_lock);
//The sharable lock must fail
//if an exclusive lock has been acquired
//or there are too many sharable locks
if(!lock.locked()
|| this->m_ctrl.exclusive_in
|| ((~this->m_ctrl.num_upr_shar) == 0)){
return false;
}
//Increment sharable count
++this->m_ctrl.num_upr_shar;
return true;
}
inline bool interprocess_upgradable_mutex::timed_lock_sharable
(const boost::posix_time::ptime &abs_time)
{
scoped_lock_t lock(m_mut, abs_time);
if(!lock.locked()) return false;
//The sharable lock must block in the first gate
//if an exclusive lock has been acquired
//or there are too many sharable locks
while (this->m_ctrl.exclusive_in
|| ((~this->m_ctrl.num_upr_shar) == 0)){
if(!this->m_first_gate.timed_wait(lock, abs_time)){
return false;
}
}
//Increment sharable count
++this->m_ctrl.num_upr_shar;
return true;
}
inline void interprocess_upgradable_mutex::unlock_sharable()
{
scoped_lock_t lock(m_mut);
//Decrement sharable count
--this->m_ctrl.num_upr_shar;
if (this->m_ctrl.num_upr_shar == 0){
this->m_second_gate.notify_one();
}
//Check if there are blocked sharable because of
//there were too many sharable
else if((~(this->m_ctrl.num_upr_shar+1)) == 0){
this->m_first_gate.notify_all();
}
}
//Downgrading
inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
{
scoped_lock_t lock(m_mut);
//Unmark it as exclusive
this->m_ctrl.exclusive_in = 0;
//Mark it as upgradable
this->m_ctrl.upgradable_in = 1;
//The sharable count should be 0 so increment it
this->m_ctrl.num_upr_shar = 1;
//Notify readers that they can enter
m_first_gate.notify_all();
}
inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
{
scoped_lock_t lock(m_mut);
//Unmark it as exclusive
this->m_ctrl.exclusive_in = 0;
//The sharable count should be 0 so increment it
this->m_ctrl.num_upr_shar = 1;
//Notify readers that they can enter
m_first_gate.notify_all();
}
inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
{
scoped_lock_t lock(m_mut);
//Unmark it as upgradable (we don't have to decrement count)
this->m_ctrl.upgradable_in = 0;
//Notify readers/upgradable that they can enter
m_first_gate.notify_all();
}
//Upgrading
inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
{
scoped_lock_t lock(m_mut);
//Simulate unlock_upgradable() without
//notifying sharables.
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
//Execute the second half of exclusive locking
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
upgradable_to_exclusive_rollback rollback(m_ctrl);
while (this->m_ctrl.num_upr_shar){
this->m_second_gate.wait(lock);
}
rollback.release();
}
inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
{
scoped_lock_t lock(m_mut, try_to_lock);
//Check if there are no readers
if(!lock.locked()
|| this->m_ctrl.num_upr_shar != 1){
return false;
}
//Now unlock upgradable and mark exclusive
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
this->m_ctrl.exclusive_in = 1;
return true;
}
inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock
(const boost::posix_time::ptime &abs_time)
{
scoped_lock_t lock(m_mut, abs_time);
if(!lock.locked()) return false;
//Simulate unlock_upgradable() without
//notifying sharables.
this->m_ctrl.upgradable_in = 0;
--this->m_ctrl.num_upr_shar;
//Execute the second half of exclusive locking
this->m_ctrl.exclusive_in = 1;
//Prepare rollback
upgradable_to_exclusive_rollback rollback(m_ctrl);
while (this->m_ctrl.num_upr_shar){
if(!this->m_second_gate.timed_wait(lock, abs_time)){
return false;
}
}
rollback.release();
return true;
}
inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
{
scoped_lock_t lock(m_mut, try_to_lock);
//If we can't lock or any has there is any exclusive, upgradable
//or sharable mark return false;
if(!lock.locked()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.num_upr_shar == 1){
return false;
}
this->m_ctrl.exclusive_in = 1;
return true;
}
inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
{
scoped_lock_t lock(m_mut, try_to_lock);
//The upgradable lock must fail
//if an exclusive or upgradable lock has been acquired
if(!lock.locked()
|| this->m_ctrl.exclusive_in
|| this->m_ctrl.upgradable_in){
return false;
}
//Mark that upgradable lock has been acquired
this->m_ctrl.upgradable_in = 1;
return true;
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP

View File

@@ -0,0 +1,41 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_LOCK_OPTIONS_HPP
#define BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
/*!\file
Describes the lock options with associated with interprocess_mutex lock constructors.
*/
namespace boost {
namespace interprocess {
namespace detail{
struct dont_lock_t{};
struct try_to_lock_t {};
} //namespace detail{
static const detail::dont_lock_t dont_lock = detail::dont_lock_t();
static const detail::try_to_lock_t try_to_lock = detail::try_to_lock_t();
} // namespace interprocess
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP

View File

@@ -0,0 +1,57 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_MUTEX_FAMILY_HPP
#define BOOST_INTERPROCESS_MUTEX_FAMILY_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/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
/*!\file
Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory.
*/
namespace boost {
namespace interprocess {
/*!Describes interprocess_mutex family to use with Interprocess framework
based on boost::interprocess synchronization objects.*/
struct mutex_family
{
typedef boost::interprocess::interprocess_mutex mutex_t;
typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_t;
};
/*!Describes interprocess_mutex family to use with Interprocess frameworks
based on null operation synchronization objects.*/
struct null_mutex_family
{
typedef boost::interprocess::null_mutex mutex_t;
typedef boost::interprocess::null_mutex recursive_mutex_t;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP

View File

@@ -0,0 +1,167 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NAMED_MUTEX_HPP
#define BOOST_INTERPROCESS_NAMED_MUTEX_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/detail/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/noncopyable.hpp>
/*!\file
Describes a named mutex class for inter-process synchronization
*/
namespace boost {
namespace interprocess {
/*!A interprocess_mutex with a global name, so it can be found from different
processes. This interprocess_mutex can't be placed in shared memory, and
each process should have it's own interprocess_mutex.*/
class named_mutex : private boost::noncopyable
{
public:
/*!Creates a global interprocess_mutex with a name.*/
named_mutex(detail::create_only_t create_only, const char *name);
/*!Opens or creates a global interprocess_mutex with a name.
If the interprocess_mutex is created, this call is equivalent to create().
If the interprocess_mutex is already created, this call is equivalent to open().
Does not throw*/
named_mutex(detail::open_or_create_t open_or_create, const char *name);
/*!Opens a global interprocess_mutex with a name if that interprocess_mutex is previously.
created. If it is not previously created this function return false.
Does not throw*/
named_mutex(detail::open_only_t open_only, const char *name);
/*!Destroys named interprocess_mutex. Does not throw*/
~named_mutex();
/*!Unlocks a previously locked interprocess_mutex.*/
void unlock();
/*!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked.
Throws interprocess_exception if a severe error is found*/
void lock();
/*! Tries to lock the interprocess_mutex, returns false when interprocess_mutex
is already locked, returns true when success.
Throws interprocess_exception if a severe error is found*/
bool try_lock();
/*! Tries to lock the interprocess_mutex until time abs_time,
Returns false when timeout expires, returns true when locks.
Throws interprocess_exception if a severe error is found*/
bool timed_lock(const boost::posix_time::ptime &abs_time);
/*! Erases a named mutex from the system*/
static bool remove(const char *name);
private:
shared_memory m_shmem;
class construct_func_t;
};
class named_mutex::construct_func_t
{
public:
enum CreationType { open_only, open_or_create, create_only };
construct_func_t(CreationType type)
: m_creation_type(type){}
bool operator()(const mapped_region &region, bool created) const
{
switch(m_creation_type){
case open_only:
return true;
break;
case create_only:
case open_or_create:
if(created){
new(region.get_address())interprocess_mutex;
}
return true;
break;
default:
return false;
break;
}
return true;
}
private:
CreationType m_creation_type;
};
inline named_mutex::~named_mutex()
{}
inline named_mutex::named_mutex(detail::create_only_t, const char *name)
: m_shmem (create_only
,name
,sizeof(interprocess_mutex)
,memory_mapping::rw_mode
,0
,construct_func_t(construct_func_t::create_only))
{}
inline named_mutex::named_mutex(detail::open_or_create_t, const char *name)
: m_shmem (open_or_create
,name
,sizeof(interprocess_mutex)
,memory_mapping::rw_mode
,0
,construct_func_t(construct_func_t::open_or_create))
{}
inline named_mutex::named_mutex(detail::open_only_t, const char *name)
: m_shmem (open_only
,name
,memory_mapping::rw_mode
,0
,construct_func_t(construct_func_t::open_only))
{}
inline void named_mutex::lock()
{ static_cast<interprocess_mutex*>(m_shmem.get_address())->lock(); }
inline void named_mutex::unlock()
{ static_cast<interprocess_mutex*>(m_shmem.get_address())->unlock(); }
inline bool named_mutex::try_lock()
{ return static_cast<interprocess_mutex*>(m_shmem.get_address())->try_lock(); }
inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return static_cast<interprocess_mutex*>(m_shmem.get_address())->timed_lock(abs_time); }
inline bool named_mutex::remove(const char *name)
{ return shared_memory::remove(name); }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP

View File

@@ -0,0 +1,194 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NAMED_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_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/detail/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/noncopyable.hpp>
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
# include <boost/interprocess/sync/win32/win32_sync_primitives.hpp>
# include <boost/interprocess/sync/named_mutex.hpp>
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
#include <unistd.h> //close
#include <string> //std::string
#include <pthread.h> //pthread_* family
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
# include <boost/interprocess/sync/named_mutex.hpp>
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
/*!\file
Describes a named interprocess_mutex class for inter-process synchronization
*/
namespace boost {
namespace interprocess {
/*!A recursive interprocess_mutex with a global name, so it can be found from different
processes. This interprocess_mutex can't be placed in shared memory, and
each process should have it's own interprocess_mutex.*/
class named_recursive_mutex : private boost::noncopyable
{
public:
/*!Creates a global interprocess_mutex with a name.*/
named_recursive_mutex(detail::create_only_t create_only, const char *name);
/*!Opens or creates a global interprocess_mutex with a name.
If the interprocess_mutex is created, this call is equivalent to create().
If the interprocess_mutex is already created, this call is equivalent to open().
Does not throw*/
named_recursive_mutex(detail::open_or_create_t open_or_create, const char *name);
/*!Opens a global interprocess_mutex with a name if that interprocess_mutex is previously.
created. If it is not previously created this function return false.
Does not throw*/
named_recursive_mutex(detail::open_only_t open_only, const char *name);
/*!Destroys named interprocess_mutex. Does not throw*/
~named_recursive_mutex();
/*!Unlocks a previously locked interprocess_mutex.*/
void unlock();
/*!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked.
Throws interprocess_exception if a severe error is found*/
void lock();
/*! Tries to lock the interprocess_mutex, returns false when interprocess_mutex
is already locked, returns true when success.
Throws interprocess_exception if a severe error is found*/
bool try_lock();
/*! Tries to lock the interprocess_mutex until time abs_time,
Returns false when timeout expires, returns true when locks.
Throws interprocess_exception if a severe error is found*/
bool timed_lock(const boost::posix_time::ptime &abs_time);
/*! Erases a named recursive mutex from the system*/
static bool remove(const char *name);
private:
named_mutex m_mutex;
#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef unsigned long thread_type;
static thread_type s_get_invalid_thread_id(){ return thread_type(0xffffffff); }
static thread_type s_get_current_thread_id(){ return winapi::current_thread_id(); }
static bool s_thread_equal(thread_type a, thread_type b){ return a == b; }
#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
typedef pthread_t thread_type;
static thread_type s_get_invalid_thread_id(){ return thread_type(false); }
static thread_type s_get_current_thread_id(){ return pthread_self(); }
static bool s_thread_equal(thread_type a, thread_type b){ return pthread_equal(a, b) != 0; }
#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32)
thread_type m_valid_id;
unsigned int m_count;
};
inline named_recursive_mutex::~named_recursive_mutex()
{}
inline named_recursive_mutex::named_recursive_mutex
(detail::create_only_t, const char *name)
: m_mutex(boost::interprocess::create_only, name)
, m_valid_id(named_recursive_mutex::s_get_invalid_thread_id())
, m_count(0)
{}
inline named_recursive_mutex::named_recursive_mutex
(detail::open_or_create_t, const char *name)
: m_mutex(boost::interprocess::open_or_create, name)
, m_valid_id(named_recursive_mutex::s_get_invalid_thread_id())
, m_count(0)
{}
inline named_recursive_mutex::named_recursive_mutex
(detail::open_only_t, const char *name)
: m_mutex(boost::interprocess::open_only, name)
, m_valid_id(named_recursive_mutex::s_get_invalid_thread_id())
, m_count(0)
{}
inline void named_recursive_mutex::lock()
{
thread_type tid = named_recursive_mutex::s_get_current_thread_id();
if (named_recursive_mutex::s_thread_equal(m_valid_id, tid)){
++m_count;
}
else{
m_mutex.lock();
m_valid_id = tid;
++m_count;
}
}
inline void named_recursive_mutex::unlock()
{
thread_type tid = named_recursive_mutex::s_get_current_thread_id();
assert(named_recursive_mutex::s_thread_equal(m_valid_id, tid));
--m_count;
if(!m_count){
m_valid_id = named_recursive_mutex::s_get_invalid_thread_id();
m_mutex.unlock();
}
}
inline bool named_recursive_mutex::try_lock()
{
thread_type tid = named_recursive_mutex::s_get_current_thread_id();
if (named_recursive_mutex::s_thread_equal(m_valid_id, tid)){
++m_count;
return true;
}
else if(m_mutex.try_lock()){
m_valid_id = tid;
++m_count;
return true;
}
return false;
}
inline bool named_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
thread_type tid = named_recursive_mutex::s_get_current_thread_id();
if (named_recursive_mutex::s_thread_equal(m_valid_id, tid)){
++m_count;
return true;
}
else if(m_mutex.timed_lock(abs_time)){
m_valid_id = tid;
++m_count;
return true;
}
return false;
}
inline bool named_recursive_mutex::remove(const char *name)
{ return named_mutex::remove(name); }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP

View File

@@ -0,0 +1,181 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NAMED_SEMAPHORE_HPP
#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_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/detail/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/interprocess/shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/noncopyable.hpp>
/*!\file
Describes a named semaphore class for inter-process synchronization
*/
namespace boost {
namespace interprocess {
/*!A interprocess_semaphore with a global name, so it can be found from different
processes. Allows several resource sharing patterns and efficient
acknowledgment mechanisms.*/
class named_semaphore : private boost::noncopyable
{
public:
/*!Creates a global interprocess_semaphore with a name, and an initial count.
It will return an false if the interprocess_semaphore is already created.*/
named_semaphore(detail::create_only_t, const char *name, int initialCount);
/*!Opens or creates a global interprocess_semaphore with a name, and an initial count.
If the interprocess_semaphore is created, this call is equivalent to create().
If the interprocess_semaphore is already created, this call is equivalent to open()
and initialCount is ignored.*/
named_semaphore(detail::open_or_create_t, const char *name, int initialCount);
/*!Opens a global interprocess_semaphore with a name if that interprocess_semaphore is previously.
created. If it is not previously created this function return false.*/
named_semaphore(detail::open_only_t, const char *name);
/*!Destroys the named interprocess_semaphore. Does not throw*/
~named_semaphore();
/*!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting
for the interprocess_semaphore, then one of these processes will return successfully from
its wait function. If there is an error an interprocess_exception exception is thrown.*/
void post();
/*!Decrements the interprocess_semaphore. If the interprocess_semaphore value is not greater than zero,
then the calling process/thread blocks until it can decrement the counter.
If there is an error an interprocess_exception exception is thrown.*/
void wait();
/*!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater than zero
and returns true. If the value is not greater than zero returns false.
If there is an error an interprocess_exception exception is thrown.*/
bool try_wait();
/*!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater
than zero and returns true. Otherwise, waits for the interprocess_semaphore
to the posted or the timeout expires. If the timeout expires, the
function returns false. If the interprocess_semaphore is posted the function
returns true. If there is an error throws sem_exception*/
bool timed_wait(const boost::posix_time::ptime &abs_time);
/*! Erases a named semaphore from the system*/
static bool remove(const char *name);
/*!Returns the interprocess_semaphore count*/
// int get_count() const;
private:
shared_memory m_shmem;
class construct_func_t;
};
class named_semaphore::construct_func_t
{
public:
enum CreationType { open_only, open_or_create, create_only };
construct_func_t(CreationType type, int init_count)
: m_creation_type(type), m_init_count(init_count){}
bool operator()(const mapped_region &region, bool created) const
{
switch(m_creation_type){
case open_only:
return true;
break;
case create_only:
case open_or_create:
if(created){
new(region.get_address())interprocess_semaphore(m_init_count);
}
return true;
break;
default:
return false;
break;
}
return true;
}
private:
CreationType m_creation_type;
int m_init_count;
};
inline named_semaphore::~named_semaphore()
{}
inline named_semaphore::named_semaphore
(detail::create_only_t, const char *name, int initialCount)
: m_shmem (create_only
,name
,sizeof(interprocess_semaphore)
,memory_mapping::rw_mode
,0
,construct_func_t(construct_func_t::create_only, initialCount))
{}
inline named_semaphore::named_semaphore
(detail::open_or_create_t, const char *name, int initialCount)
: m_shmem (open_or_create
,name
,sizeof(interprocess_semaphore)
,memory_mapping::rw_mode
,0
,construct_func_t(construct_func_t::open_or_create, initialCount))
{}
inline named_semaphore::named_semaphore
(detail::open_only_t, const char *name)
: m_shmem (open_only
,name
,memory_mapping::rw_mode
,0
,construct_func_t(construct_func_t::open_only, 0))
{}
inline void named_semaphore::post()
{ static_cast<interprocess_semaphore*>(m_shmem.get_address())->post(); }
inline void named_semaphore::wait()
{ static_cast<interprocess_semaphore*>(m_shmem.get_address())->wait(); }
inline bool named_semaphore::try_wait()
{ return static_cast<interprocess_semaphore*>(m_shmem.get_address())->try_wait(); }
inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
{ return static_cast<interprocess_semaphore*>(m_shmem.get_address())->timed_wait(abs_time); }
inline bool named_semaphore::remove(const char *name)
{ return shared_memory::remove(name); }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP

View File

@@ -0,0 +1,71 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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_NULL_MUTEX_HPP
#define BOOST_INTERPROCESS_NULL_MUTEX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
/*!\file
Describes null_mutex classes
*/
namespace boost {
namespace posix_time
{ class ptime; }
namespace interprocess {
/*!Wraps a interprocess_mutex that does nothing */
class null_mutex
{
null_mutex(const null_mutex&);
null_mutex &operator= (const null_mutex&);
public:
/*!Empty constructor */
null_mutex(){}
/*!Empty destructor */
~null_mutex(){}
/*!Does nothing */
void lock(){}
/*!Returns true */
bool try_lock(){ return true; }
/*!Returns true */
bool timed_lock(const boost::posix_time::ptime &abs_time){ return true; }
/*!Does nothing */
void unlock(){}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
private:
char dummy; // BCB would by default use 8 B for empty structure
#endif
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP

View File

@@ -0,0 +1,81 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztañaga 2005-2006. 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.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
namespace boost {
namespace interprocess {
inline interprocess_condition::interprocess_condition()
{
int res;
pthread_condattr_t cond_attr;
res = pthread_condattr_init(&cond_attr);
if(res != 0){
throw interprocess_exception();
}
res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
if(res != 0){
pthread_condattr_destroy(&cond_attr);
throw interprocess_exception();
}
res = pthread_cond_init(&m_condition, &cond_attr);
pthread_condattr_destroy(&cond_attr);
if(res != 0){
throw interprocess_exception();
}
}
inline interprocess_condition::~interprocess_condition()
{
int res = 0;
res = pthread_cond_destroy(&m_condition);
assert(res == 0);
}
inline void interprocess_condition::notify_one()
{
int res = 0;
res = pthread_cond_signal(&m_condition);
assert(res == 0);
}
inline void interprocess_condition::notify_all()
{
int res = 0;
res = pthread_cond_broadcast(&m_condition);
assert(res == 0);
}
inline void interprocess_condition::do_wait(interprocess_mutex &mut)
{
pthread_mutex_t* pmutex = &mut.m_mut;
int res = 0;
res = pthread_cond_wait(&m_condition, pmutex);
assert(res == 0);
}
inline bool interprocess_condition::do_timed_wait
(const boost::posix_time::ptime &abs_time, interprocess_mutex &mut)
{
timespec ts = detail::ptime_to_timespec(abs_time);
pthread_mutex_t* pmutex = &mut.m_mut;
int res = 0;
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
assert(res == 0 || res == ETIMEDOUT);
return res != ETIMEDOUT;
}
} //namespace interprocess
} // namespace boost

Some files were not shown because too many files have changed in this diff Show More