mirror of
https://github.com/boostorg/interprocess.git
synced 2026-01-19 04:12:13 +00:00
no message
[SVN r34285]
This commit is contained in:
96
.gitattributes
vendored
Normal file
96
.gitattributes
vendored
Normal 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
|
||||
875
include/boost/interprocess/Attic/intersegment_ptr.hpp
Normal file
875
include/boost/interprocess/Attic/intersegment_ptr.hpp
Normal 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
|
||||
|
||||
376
include/boost/interprocess/Attic/managed_multi_shared_memory.hpp
Normal file
376
include/boost/interprocess/Attic/managed_multi_shared_memory.hpp
Normal 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 ®ion, 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 ®ion, 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
|
||||
|
||||
50
include/boost/interprocess/allocators/allocation_type.hpp
Normal file
50
include/boost/interprocess/allocators/allocation_type.hpp
Normal 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
|
||||
|
||||
223
include/boost/interprocess/allocators/allocator.hpp
Normal file
223
include/boost/interprocess/allocators/allocator.hpp
Normal 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
|
||||
|
||||
429
include/boost/interprocess/allocators/cached_node_allocator.hpp
Normal file
429
include/boost/interprocess/allocators/cached_node_allocator.hpp
Normal 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
|
||||
|
||||
341
include/boost/interprocess/allocators/detail/node_pool.hpp
Normal file
341
include/boost/interprocess/allocators/detail/node_pool.hpp
Normal 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
|
||||
|
||||
318
include/boost/interprocess/allocators/node_allocator.hpp
Normal file
318
include/boost/interprocess/allocators/node_allocator.hpp
Normal 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
|
||||
|
||||
249
include/boost/interprocess/allocators/private_node_allocator.hpp
Normal file
249
include/boost/interprocess/allocators/private_node_allocator.hpp
Normal 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
|
||||
|
||||
830
include/boost/interprocess/containers/Attic/tree.hpp
Normal file
830
include/boost/interprocess/containers/Attic/tree.hpp
Normal 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
|
||||
|
||||
1356
include/boost/interprocess/containers/deque.hpp
Normal file
1356
include/boost/interprocess/containers/deque.hpp
Normal file
File diff suppressed because it is too large
Load Diff
857
include/boost/interprocess/containers/detail/Attic/tree_func.hpp
Normal file
857
include/boost/interprocess/containers/detail/Attic/tree_func.hpp
Normal 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
|
||||
|
||||
629
include/boost/interprocess/containers/detail/flat_tree.hpp
Normal file
629
include/boost/interprocess/containers/detail/flat_tree.hpp
Normal 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
|
||||
857
include/boost/interprocess/containers/detail/tree_func.hpp
Normal file
857
include/boost/interprocess/containers/detail/tree_func.hpp
Normal 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
|
||||
|
||||
505
include/boost/interprocess/containers/flat_map.hpp
Normal file
505
include/boost/interprocess/containers/flat_map.hpp
Normal 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 */
|
||||
|
||||
483
include/boost/interprocess/containers/flat_set.hpp
Normal file
483
include/boost/interprocess/containers/flat_set.hpp
Normal 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:
|
||||
947
include/boost/interprocess/containers/list.hpp
Normal file
947
include/boost/interprocess/containers/list.hpp
Normal 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_
|
||||
533
include/boost/interprocess/containers/map.hpp
Normal file
533
include/boost/interprocess/containers/map.hpp
Normal 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 */
|
||||
|
||||
1879
include/boost/interprocess/containers/old_string.hpp
Normal file
1879
include/boost/interprocess/containers/old_string.hpp
Normal file
File diff suppressed because it is too large
Load Diff
474
include/boost/interprocess/containers/set.hpp
Normal file
474
include/boost/interprocess/containers/set.hpp
Normal 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:
|
||||
1096
include/boost/interprocess/containers/slist.hpp
Normal file
1096
include/boost/interprocess/containers/slist.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1793
include/boost/interprocess/containers/string.hpp
Normal file
1793
include/boost/interprocess/containers/string.hpp
Normal file
File diff suppressed because it is too large
Load Diff
830
include/boost/interprocess/containers/tree.hpp
Normal file
830
include/boost/interprocess/containers/tree.hpp
Normal 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
|
||||
|
||||
1582
include/boost/interprocess/containers/vector.hpp
Normal file
1582
include/boost/interprocess/containers/vector.hpp
Normal file
File diff suppressed because it is too large
Load Diff
974
include/boost/interprocess/containers/vector_old.hpp
Normal file
974
include/boost/interprocess/containers/vector_old.hpp
Normal 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
|
||||
|
||||
34
include/boost/interprocess/detail/Attic/creation_tags.hpp
Normal file
34
include/boost/interprocess/detail/Attic/creation_tags.hpp
Normal 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
|
||||
|
||||
118
include/boost/interprocess/detail/Attic/generic_cast.hpp
Normal file
118
include/boost/interprocess/detail/Attic/generic_cast.hpp
Normal 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
|
||||
|
||||
@@ -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
|
||||
29
include/boost/interprocess/detail/cast_tags.hpp
Normal file
29
include/boost/interprocess/detail/cast_tags.hpp
Normal 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
|
||||
|
||||
24
include/boost/interprocess/detail/config_begin.hpp
Normal file
24
include/boost/interprocess/detail/config_begin.hpp
Normal 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
|
||||
11
include/boost/interprocess/detail/config_end.hpp
Normal file
11
include/boost/interprocess/detail/config_end.hpp
Normal 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
|
||||
34
include/boost/interprocess/detail/creation_tags.hpp
Normal file
34
include/boost/interprocess/detail/creation_tags.hpp
Normal 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
|
||||
|
||||
118
include/boost/interprocess/detail/generic_cast.hpp
Normal file
118
include/boost/interprocess/detail/generic_cast.hpp
Normal 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
|
||||
|
||||
127
include/boost/interprocess/detail/global_lock.hpp
Normal file
127
include/boost/interprocess/detail/global_lock.hpp
Normal 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
|
||||
551
include/boost/interprocess/detail/managed_memory_impl.hpp
Normal file
551
include/boost/interprocess/detail/managed_memory_impl.hpp
Normal 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
|
||||
|
||||
46
include/boost/interprocess/detail/multi_segment_services.hpp
Normal file
46
include/boost/interprocess/detail/multi_segment_services.hpp
Normal 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
|
||||
252
include/boost/interprocess/detail/named_proxy.hpp
Normal file
252
include/boost/interprocess/detail/named_proxy.hpp
Normal 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
|
||||
34
include/boost/interprocess/detail/null_create_func.hpp
Normal file
34
include/boost/interprocess/detail/null_create_func.hpp
Normal 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
|
||||
337
include/boost/interprocess/detail/os_file_functions.hpp
Normal file
337
include/boost/interprocess/detail/os_file_functions.hpp
Normal 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
|
||||
543
include/boost/interprocess/detail/utilities.hpp
Normal file
543
include/boost/interprocess/detail/utilities.hpp
Normal 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
|
||||
|
||||
137
include/boost/interprocess/detail/version_type.hpp
Normal file
137
include/boost/interprocess/detail/version_type.hpp
Normal 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
|
||||
119
include/boost/interprocess/detail/workaround.hpp
Normal file
119
include/boost/interprocess/detail/workaround.hpp
Normal 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
|
||||
228
include/boost/interprocess/errors.hpp
Normal file
228
include/boost/interprocess/errors.hpp
Normal 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
|
||||
142
include/boost/interprocess/exceptions.hpp
Normal file
142
include/boost/interprocess/exceptions.hpp
Normal 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
|
||||
443
include/boost/interprocess/fully_mapped_file.hpp
Normal file
443
include/boost/interprocess/fully_mapped_file.hpp
Normal 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
|
||||
71
include/boost/interprocess/indexes/flat_map_index.hpp
Normal file
71
include/boost/interprocess/indexes/flat_map_index.hpp
Normal 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
|
||||
83
include/boost/interprocess/indexes/map_index.hpp
Normal file
83
include/boost/interprocess/indexes/map_index.hpp
Normal 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
|
||||
42
include/boost/interprocess/indexes/null_index.hpp
Normal file
42
include/boost/interprocess/indexes/null_index.hpp
Normal 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
|
||||
97
include/boost/interprocess/indexes/unordered_map_index.hpp
Normal file
97
include/boost/interprocess/indexes/unordered_map_index.hpp
Normal 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
|
||||
428
include/boost/interprocess/interprocess_fwd.hpp
Normal file
428
include/boost/interprocess/interprocess_fwd.hpp
Normal 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
|
||||
|
||||
875
include/boost/interprocess/intersegment_ptr.hpp
Normal file
875
include/boost/interprocess/intersegment_ptr.hpp
Normal 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
|
||||
|
||||
616
include/boost/interprocess/ipc/message_queue.hpp
Normal file
616
include/boost/interprocess/ipc/message_queue.hpp
Normal 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 ®ion, 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
|
||||
21
include/boost/interprocess/ipc/named_fifo.hpp
Normal file
21
include/boost/interprocess/ipc/named_fifo.hpp
Normal 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
|
||||
70
include/boost/interprocess/managed_external_buffer.hpp
Normal file
70
include/boost/interprocess/managed_external_buffer.hpp
Normal 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
|
||||
|
||||
194
include/boost/interprocess/managed_heap_memory.hpp
Normal file
194
include/boost/interprocess/managed_heap_memory.hpp
Normal 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
|
||||
|
||||
229
include/boost/interprocess/managed_mapped_file.hpp
Normal file
229
include/boost/interprocess/managed_mapped_file.hpp
Normal 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 ®ion, 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
|
||||
|
||||
376
include/boost/interprocess/managed_multi_shared_memory.hpp
Normal file
376
include/boost/interprocess/managed_multi_shared_memory.hpp
Normal 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 ®ion, 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 ®ion, 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
|
||||
|
||||
181
include/boost/interprocess/managed_shared_memory.hpp
Normal file
181
include/boost/interprocess/managed_shared_memory.hpp
Normal 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 ®ion, 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
|
||||
|
||||
541
include/boost/interprocess/mapped_file.hpp
Normal file
541
include/boost/interprocess/mapped_file.hpp
Normal 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
61
include/boost/interprocess/mem_algo/multi_simple_seq_fit.hpp
Normal file
61
include/boost/interprocess/mem_algo/multi_simple_seq_fit.hpp
Normal 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
|
||||
|
||||
55
include/boost/interprocess/mem_algo/simple_seq_fit.hpp
Normal file
55
include/boost/interprocess/mem_algo/simple_seq_fit.hpp
Normal 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
|
||||
|
||||
407
include/boost/interprocess/memory_mapping.hpp
Normal file
407
include/boost/interprocess/memory_mapping.hpp
Normal 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 ®ion, bool) const
|
||||
{ return true; }
|
||||
};
|
||||
|
||||
|
||||
} //namespace interprocess {
|
||||
|
||||
} //namespace boost {
|
||||
|
||||
#include <boost/interprocess/detail/config_end.hpp>
|
||||
|
||||
#endif //BOOST_INTERPROCESS_MEMORY_MAPPING_HPP
|
||||
|
||||
336
include/boost/interprocess/offset_ptr.hpp
Normal file
336
include/boost/interprocess/offset_ptr.hpp
Normal 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
|
||||
|
||||
1117
include/boost/interprocess/segment_manager.hpp
Normal file
1117
include/boost/interprocess/segment_manager.hpp
Normal file
File diff suppressed because it is too large
Load Diff
704
include/boost/interprocess/shared_memory.hpp
Normal file
704
include/boost/interprocess/shared_memory.hpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
44
include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp
Normal file
44
include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp
Normal 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
|
||||
317
include/boost/interprocess/smart_ptr/detail/shared_count.hpp
Normal file
317
include/boost/interprocess/smart_ptr/detail/shared_count.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
114
include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp
Normal file
114
include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
254
include/boost/interprocess/smart_ptr/intrusive_ptr.hpp
Normal file
254
include/boost/interprocess/smart_ptr/intrusive_ptr.hpp
Normal 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
|
||||
140
include/boost/interprocess/smart_ptr/scoped_ptr.hpp
Normal file
140
include/boost/interprocess/smart_ptr/scoped_ptr.hpp
Normal 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
|
||||
276
include/boost/interprocess/smart_ptr/shared_ptr.hpp
Normal file
276
include/boost/interprocess/smart_ptr/shared_ptr.hpp
Normal 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
|
||||
419
include/boost/interprocess/smart_ptr/unique_ptr_emulation.hpp
Normal file
419
include/boost/interprocess/smart_ptr/unique_ptr_emulation.hpp
Normal 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
|
||||
407
include/boost/interprocess/smart_ptr/unique_ptr_reference.hpp
Normal file
407
include/boost/interprocess/smart_ptr/unique_ptr_reference.hpp
Normal 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
|
||||
149
include/boost/interprocess/smart_ptr/weak_ptr.hpp
Normal file
149
include/boost/interprocess/smart_ptr/weak_ptr.hpp
Normal 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
|
||||
422
include/boost/interprocess/streams/bufferstream.hpp
Normal file
422
include/boost/interprocess/streams/bufferstream.hpp
Normal 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 */
|
||||
629
include/boost/interprocess/streams/stringstream.hpp
Normal file
629
include/boost/interprocess/streams/stringstream.hpp
Normal 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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
explicit basic_stringbuf(const VectorParameter ¶m,
|
||||
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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
basic_istringstream(const VectorParameter ¶m,
|
||||
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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
basic_ostringstream(const VectorParameter ¶m,
|
||||
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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
basic_stringstream(const VectorParameter ¶m, 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 */
|
||||
544
include/boost/interprocess/streams/vectorstream.hpp
Normal file
544
include/boost/interprocess/streams/vectorstream.hpp
Normal 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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
explicit basic_vectorbuf(const VectorParameter ¶m,
|
||||
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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
basic_ivectorstream(const VectorParameter ¶m,
|
||||
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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
basic_ovectorstream(const VectorParameter ¶m,
|
||||
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 ¶m) throws.*/
|
||||
template<class VectorParameter>
|
||||
basic_vectorstream(const VectorParameter ¶m, 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 */
|
||||
159
include/boost/interprocess/sync/file_lock.hpp
Normal file
159
include/boost/interprocess/sync/file_lock.hpp
Normal 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
|
||||
156
include/boost/interprocess/sync/interprocess_barrier.hpp
Normal file
156
include/boost/interprocess/sync/interprocess_barrier.hpp
Normal 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
|
||||
146
include/boost/interprocess/sync/interprocess_condition.hpp
Normal file
146
include/boost/interprocess/sync/interprocess_condition.hpp
Normal 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
|
||||
105
include/boost/interprocess/sync/interprocess_mutex.hpp
Normal file
105
include/boost/interprocess/sync/interprocess_mutex.hpp
Normal 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
|
||||
114
include/boost/interprocess/sync/interprocess_recursive_mutex.hpp
Normal file
114
include/boost/interprocess/sync/interprocess_recursive_mutex.hpp
Normal 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
|
||||
108
include/boost/interprocess/sync/interprocess_semaphore.hpp
Normal file
108
include/boost/interprocess/sync/interprocess_semaphore.hpp
Normal 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
|
||||
1271
include/boost/interprocess/sync/interprocess_sharable_mutex.hpp
Normal file
1271
include/boost/interprocess/sync/interprocess_sharable_mutex.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
41
include/boost/interprocess/sync/lock_options.hpp
Normal file
41
include/boost/interprocess/sync/lock_options.hpp
Normal 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
|
||||
57
include/boost/interprocess/sync/mutex_family.hpp
Normal file
57
include/boost/interprocess/sync/mutex_family.hpp
Normal 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
|
||||
|
||||
|
||||
167
include/boost/interprocess/sync/named_mutex.hpp
Normal file
167
include/boost/interprocess/sync/named_mutex.hpp
Normal 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 ®ion, 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
|
||||
194
include/boost/interprocess/sync/named_recursive_mutex.hpp
Normal file
194
include/boost/interprocess/sync/named_recursive_mutex.hpp
Normal 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
|
||||
181
include/boost/interprocess/sync/named_semaphore.hpp
Normal file
181
include/boost/interprocess/sync/named_semaphore.hpp
Normal 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 ®ion, 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
|
||||
71
include/boost/interprocess/sync/null_mutex.hpp
Normal file
71
include/boost/interprocess/sync/null_mutex.hpp
Normal 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
|
||||
@@ -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
Reference in New Issue
Block a user