commit ae47bde01858f4ea8bd4f881dc82ab5d5fb98e78 Author: Ion Gaztañaga Date: Mon Jun 12 17:23:18 2006 +0000 no message [SVN r34285] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/include/boost/interprocess/Attic/intersegment_ptr.hpp b/include/boost/interprocess/Attic/intersegment_ptr.hpp new file mode 100644 index 0000000..a008c28 --- /dev/null +++ b/include/boost/interprocess/Attic/intersegment_ptr.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 +struct flat_map_intersegment +{ + typedef flat_map_intersegment 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 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 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 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 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 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 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 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 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 insert_ret; + std::size_t group = 0; + + BOOST_TRY{ + //------------------------------------------------------------------ + boost::interprocess::scoped_lock 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 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_ret_t; + typedef std::pair 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 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 + 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 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 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 + > ptr_to_segment_t; + /*!Maps segment group/id with base addresses*/ + typedef boost::interprocess::flat_map + 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 + 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 +typename flat_map_intersegment::mappings_t + flat_map_intersegment::s_map; + +/*!Static constant that shows the number of bits to shift to obtain the + group part of segment_t type*/ +template +const std::size_t flat_map_intersegment::s_shift; + +/*!Static constant that shows the number of bits to shift to obtain the + group part of segment_t type*/ +template +const std::size_t flat_map_intersegment::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 intersegment_ptr : public flat_map_intersegment //: public PT +{ + typedef flat_map_intersegment PT; + typedef boost::interprocess::workaround::random_it random_it_t; +// typedef intersegment_ptr self_t; + typedef intersegment_ptr 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 + 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 + intersegment_ptr(const intersegment_ptr &ptr) + { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } + + /*!Emulates static_cast operator. Never throws. */ + template + intersegment_ptr(const intersegment_ptr &r, detail::static_cast_tag) + //{ base_t::set_from_pointer(static_cast(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(this); + std::ptrdiff_t difference = detail::char_ptr_cast(static_cast(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 + intersegment_ptr(const intersegment_ptr &r, detail::const_cast_tag) + { base_t::set_from_pointer(const_cast(r.get())); } + /* + { + //Make sure const conversion is correct + pointer p = const_cast((U*)0); (void)p; + base_t::set_from_other(r); + }*/ + + /*!Emulates dynamic_cast operator. Never throws.*/ + template + intersegment_ptr(const intersegment_ptr &r, detail::dynamic_cast_tag) + { base_t::set_from_pointer(dynamic_cast(r.get())); } + + /*!Emulates reinterpret_cast operator. Never throws.*/ + template + intersegment_ptr(const intersegment_ptr &r, detail::reinterpret_cast_tag) + { base_t::set_from_pointer(reinterpret_cast(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 + intersegment_ptr& operator= (const intersegment_ptr & 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 + bool _diff(const intersegment_ptr &other) const + { return base_t::less(other); } + + /*!Returns true if both point to the same object*/ + template + bool _equal(const intersegment_ptr &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 + bool _less(const intersegment_ptr &other) const + { return base_t::less(other); } +}; + +/*!Compares the equality of two intersegment_ptr-s. + Never throws.*/ +template inline +bool operator ==(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) == + typename intersegment_ptr::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 inline +bool operator <(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) < + typename intersegment_ptr::pointer(0); + (void)e; + return left._less(right); +} + +template inline +bool operator!= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 ==pt2); } + +/*!intersegment_ptr <= intersegment_ptr. Never throws.*/ +template inline +bool operator<= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 > pt2); } + +/*!intersegment_ptr > intersegment_ptr. Never throws.*/ +template inline +bool operator> (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return (pt2 < pt1); } + +/*!intersegment_ptr >= intersegment_ptr. Never throws.*/ +template inline +bool operator>= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 < pt2); } + +/*!operator<< */ +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, const intersegment_ptr & p) +{ return os << p.get(); } + +/*!operator>> */ +template inline +std::basic_istream & operator>> + (std::basic_istream & os, intersegment_ptr & p) +{ U * tmp; return os >> tmp; p = tmp; } + +/*!std::ptrdiff_t + intersegment_ptr. + The result is another pointer of the same segment */ +template inline +intersegment_ptr operator+ + (std::ptrdiff_t diff, const intersegment_ptr& right) +{ return right + diff; } + +/*!intersegment_ptr - intersegment_ptr. + This only works with two intersegment_ptr-s that point to the + same segment*/ +template inline +std::ptrdiff_t operator- (const intersegment_ptr &pt, + const intersegment_ptr &pt2) +{ return pt._diff(pt2); } + +/*! swap specialization */ +template inline +void swap (boost::interprocess::intersegment_ptr &pt, + boost::interprocess::intersegment_ptr &pt2) +{ pt.swap(pt2); } + +/*!get_pointer() enables boost::mem_fn to recognize intersegment_ptr. + Never throws.*/ +template inline +T * get_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } + +/*!Simulation of static_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr static_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::static_cast_tag()); } + +/*!Simulation of const_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr const_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::const_cast_tag()); } + +/*!Simulation of dynamic_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr dynamic_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::dynamic_cast_tag()); } + +/*!Simulation of reinterpret_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::reinterpret_cast_tag()); } + +/*!Trait class to detect if an smart pointer has + multi-segment addressing capabilities.*/ +template +struct is_multisegment_ptr + > +{ + enum { value = true }; +}; + +} //namespace interprocess { + + +/*!has_trivial_constructor<> == true_type specialization for optimizations*/ +template +struct has_trivial_constructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +/*!has_trivial_destructor<> == true_type specialization for optimizations*/ +template +struct has_trivial_destructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERSEGMENT_PTR_HPP + diff --git a/include/boost/interprocess/Attic/managed_multi_shared_memory.hpp b/include/boost/interprocess/Attic/managed_multi_shared_memory.hpp new file mode 100644 index 0000000..51d5d6a --- /dev/null +++ b/include/boost/interprocess/Attic/managed_multi_shared_memory.hpp @@ -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 +#include + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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*/ +template + < + class CharType, + class MemoryAlgorithm, + template class IndexType + > +class basic_managed_multi_shared_memory + : public detail::basic_managed_memory_impl + +{ + + typedef basic_managed_multi_shared_memory + 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 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 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 + 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 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(&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 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(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 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 + 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 + +#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + diff --git a/include/boost/interprocess/allocators/allocation_type.hpp b/include/boost/interprocess/allocators/allocation_type.hpp new file mode 100644 index 0000000..3896966 --- /dev/null +++ b/include/boost/interprocess/allocators/allocation_type.hpp @@ -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 +#include + +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 + +#endif //BOOST_INTERPROCESS_TYPE_COMMAND_HPP + diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp new file mode 100644 index 0000000..1c45029 --- /dev/null +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 allocator +{ + private: + /*!Self type*/ + typedef allocator 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 + ::type cvoid_ptr; + + /*!Pointer to the allocator*/ + typedef typename detail::pointer_to_other + ::type alloc_ptr_t; + + /*!Not assignable from related allocator*/ + template + allocator& operator=(const allocator&); + + /*!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 + ::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef typename workaround::random_it + ::reference reference; + typedef typename workaround::random_it + ::const_reference const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef detail::version_type version; + + + /*!Obtains an allocator of other type*/ + template + struct rebind + { + typedef allocator 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 + allocator(const allocator &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 + 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 + 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 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 + (static_cast(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 inline +bool operator==(const allocator &alloc1, + const allocator &alloc2) + { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); } + +/*!Inequality test for same type of allocator*/ +template inline +bool operator!=(const allocator &alloc1, + const allocator &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 +struct has_convertible_construct + > +{ + enum { value = true }; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP + diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp new file mode 100644 index 0000000..e6a80ab --- /dev/null +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 cached_node_allocator +{ + enum { NumAlloc = 64 }; + + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename detail:: + pointer_to_other::type cvoid_pointer; + typedef SegmentManager segment_manager; + typedef typename detail:: + pointer_to_other::type char_pointer; + typedef typename SegmentManager::mutex_family::mutex_t mutex_t; + typedef cached_node_allocator self_t; + enum { DEFAULT_MAX_CACHED_NODES = 64 }; + + public: + //------- + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename workaround::random_it + ::reference reference; + typedef typename workaround::random_it + ::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 + struct rebind + { + typedef cached_node_allocator other; + }; + + private: + + /*!Not assignable from related cached_node_allocator*/ + template + cached_node_allocator& operator= + (const cached_node_allocator&); + + /*!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 + node_pool_t; + node_pool_t *node_pool = static_cast(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 + cached_node_allocator + (const cached_node_allocator &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 + node_pool_t; + node_pool_t *node_pool = static_cast(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 + 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 + 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(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(detail::get_pointer(mp_node_pool)); + ret = node_pool->allocate(count); + } + return pointer(static_cast(ret)); + } + + /*!Deallocate allocated memory. Never throws*/ + void deallocate(const pointer &ptr, size_type count) + { + typedef detail::shared_node_pool + 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 + (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 + 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 + (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 + node_pool_t; + node_pool_t *node_pool = static_cast + (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 + node_pool_t; + node_pool_t *node_pool = static_cast + (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 + 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(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 + node_pool_t; + //Get segment manager + segment_manager *segment_mngr = this->get_segment_manager(); + //Get pool pointer + node_pool_t *node_pool = static_cast + (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 *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 inline +bool operator==(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +/*!Inequality test for same type of cached_node_allocator*/ +template inline +bool operator!=(const cached_node_allocator &alloc1, + const cached_node_allocator &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 +struct has_convertible_construct + > +{ + enum { value = true }; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP + diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp new file mode 100644 index 0000000..0aa5c25 --- /dev/null +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include + +/*!\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 private_node_pool : private boost::noncopyable +{ + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename pointer_to_other::type char_ptr_t; + + enum { RealNodeSize = + boost::math::static_lcm::value }; + enum { BlockSize = + detail::ct_rounded_size::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(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( + static_cast((detail::char_ptr_cast(chunk)+BlockSize))); + } + + private: + typedef typename pointer_to_other + ::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 shared_node_pool + : public private_node_pool + +{ + private: + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename pointer_to_other::type char_ptr_t; + typedef private_node_pool + 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 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 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 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 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 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 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 + +#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_ALGO_HPP + diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp new file mode 100644 index 0000000..6a9a0e9 --- /dev/null +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 node_allocator +{ + public: + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename detail:: + pointer_to_other::type cvoid_pointer; + typedef SegmentManager segment_manager; + typedef typename detail:: + pointer_to_other::type char_pointer; + typedef typename SegmentManager:: + mutex_family::mutex_t mutex_t; + typedef node_allocator + self_t; + + public: + //------- + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename workaround::random_it + ::reference reference; + typedef typename workaround::random_it + ::const_reference const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + /*!Obtains node_allocator from other node_allocator*/ + template + struct rebind + { + typedef node_allocator other; + }; + + private: + + /*!Not assignable from related node_allocator*/ + template + node_allocator& operator= + (const node_allocator&); + + /*!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 + node_pool_t; + node_pool_t *node_pool = static_cast(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 + node_allocator + (const node_allocator &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 + node_pool_t; + node_pool_t *node_pool = static_cast + (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 + 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 + node_pool_t; + node_pool_t *node_pool = static_cast + (detail::get_pointer(mp_node_pool)); + return pointer(static_cast(node_pool->allocate(count))); + } + + /*!Deallocate allocated memory. Never throws*/ + void deallocate(const pointer &ptr, size_type count) + { + typedef detail::shared_node_pool + node_pool_t; + node_pool_t *node_pool = static_cast + (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 + 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 + (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 + 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(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 + 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 + (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 *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 inline +bool operator==(const node_allocator &alloc1, + const node_allocator &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +/*!Inequality test for same type of node_allocator*/ +template inline +bool operator!=(const node_allocator &alloc1, + const node_allocator &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 +struct has_convertible_construct + > +{ + enum { value = true }; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_POOLED_NODE_ALLOCATOR_HPP + diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp new file mode 100644 index 0000000..429636d --- /dev/null +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 private_node_allocator +{ + private: + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename detail:: + pointer_to_other::type cvoid_pointer; + typedef SegmentManager segment_manager; + typedef typename detail:: + pointer_to_other::type char_pointer; + typedef typename detail::pointer_to_other + ::type segment_mngr_ptr_t; + typedef typename SegmentManager:: + mutex_family::mutex_t mutex_t; + typedef private_node_allocator + self_t; + + public: + //------- + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename workaround::random_it + ::reference reference; + typedef typename workaround::random_it + ::const_reference const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + /*!Obtains node_allocator from other node_allocator*/ + template + struct rebind + { + typedef private_node_allocator other; + }; + + /*!Not assignable from related private_node_allocator*/ + template + private_node_allocator& operator= + (const private_node_allocator&); + + /*!Not assignable from other private_node_allocator*/ + private_node_allocator& operator=(const private_node_allocator&); + + void priv_initialize() + { + typedef detail::private_node_pool + 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 + priv_node_pool_t; + //------------------------------------------------------------- + priv_node_pool_t *pnode_pool = static_cast + (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 + private_node_allocator + (const private_node_allocator &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 + 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 + priv_node_pool_t; + //---------------------------------------------------------- + if(!mp_node_pool) priv_initialize(); + priv_node_pool_t *node_pool = static_cast + (detail::get_pointer(mp_node_pool)); + return pointer(static_cast(node_pool->allocate(count))); + } + + /*!Deallocate allocated memory. Never throws*/ + void deallocate(const pointer &ptr, size_type count) + { + //---------------------------------------------------------- + typedef detail::private_node_pool + priv_node_pool_t; + //---------------------------------------------------------- + if(!mp_node_pool) priv_initialize(); + priv_node_pool_t *node_pool = static_cast( + 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 *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 inline +bool operator==(const private_node_allocator &alloc1, + const private_node_allocator &alloc2) +{ return &alloc1 == &alloc2; } + +/*!Inequality test for same type of private_node_allocator*/ +template inline +bool operator!=(const private_node_allocator &alloc1, + const private_node_allocator &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 +struct has_convertible_construct + > +{ + enum { value = true }; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP + diff --git a/include/boost/interprocess/containers/Attic/tree.hpp b/include/boost/interprocess/containers/Attic/tree.hpp new file mode 100644 index 0000000..5b8f06b --- /dev/null +++ b/include/boost/interprocess/containers/Attic/tree.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//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 +struct rb_tree_node + : rb_tree_node_base::type> +{ + typedef rb_tree_node_base::type> base_t; + typedef typename boost::detail::allocator:: + rebind_to >::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(upclass_pointer); + } + + const value_type &value() const { return m_value; } + value_type &value() { return m_value; } + private: + value_type m_value; +}; + +template +class rb_tree_alloc_base + //Inherit from node allocator +: public boost::detail::allocator:: + rebind_to >::type, + //Inherit from node_ptr allocator + public boost::detail::allocator:: + rebind_to >::type::value_type::basic_node_pointer>::type, + //Inherit from value_ptr allocator + public boost::detail::allocator::rebind_to::type +{ + + public: + typedef typename boost::detail::allocator:: + rebind_to >::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::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::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 NodeDeallocator; + typedef detail::scoped_destructor 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_ptrnode_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 + left_destroy(pleft, *this); + + basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t()); + scoped_ptr + right_destroy(pright, *this); + + basic_node_ptr_allocator_t::construct(pparent, basic_node_ptr_t()); + scoped_ptr + 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(*this); + node_allocator_t& other_alloc = static_cast(x); + if (this_alloc != other_alloc){ + detail::do_swap(static_cast(*this), + static_cast(x)); + detail::do_swap(static_cast(*this), + static_cast(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_ptrnode_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 + left_destroy(pleft, *this); + + basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t()); + scoped_ptr + 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 rb_tree_alloc_base + //Inherit from node allocator + : public boost::detail::allocator:: + rebind_to >::type +{ + public: + typedef typename boost::detail::allocator:: + rebind_to >::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::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::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 NodeDeallocator; + typedef detail::scoped_destructor 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 + node_pointer allocate_and_construct_node(const Convertible &x) + { + node_pointer p = node_allocator_t::allocate(1); + scoped_ptrnode_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(*this); + node_allocator_t& other_alloc = static_cast(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::value){ + basic_node_ptr_allocator_t node_ptr_allocator(*this); + scoped_ptrnode_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 + left_destroy(pleft, node_ptr_allocator); + + node_ptr_allocator.construct(pright, basic_node_ptr_t()); + scoped_ptr + 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::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 rb_tree + : protected rb_tree_alloc_base::value> +{ + private: + typedef rb_tree_alloc_base::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 rb_tree_algo_t; + typedef rb_tree_func 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 const_iterator; + typedef rb_tree_iterator iterator; + typedef boost::reverse_iterator reverse_iterator; + typedef boost::reverse_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 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(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(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 + 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 + 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 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 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(lower), iterator(upper)); + } + + std::pair 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(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(m_data); } + + Compare & get_compare() + { return static_cast(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 +inline bool +operator==(const rb_tree& x, + const rb_tree& y) +{ + return x.size() == y.size() && + std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const rb_tree& x, + const rb_tree& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); +} + +template +inline bool +operator!=(const rb_tree& x, + const rb_tree& y) { + return !(x == y); +} + +template +inline bool +operator>(const rb_tree& x, + const rb_tree& y) { + return y < x; +} + +template +inline bool +operator<=(const rb_tree& x, + const rb_tree& y) { + return !(y < x); +} + +template +inline bool +operator>=(const rb_tree& x, + const rb_tree& y) { + return !(x < y); +} + + +template +inline void +swap(rb_tree& x, + rb_tree& y) +{ + x.swap(y); +} + +} //namespace detail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_TREE_HPP + diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp new file mode 100644 index 0000000..c4c3242 --- /dev/null +++ b/include/boost/interprocess/containers/deque.hpp @@ -0,0 +1,1356 @@ +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, std::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_deque.h and stl_uninitialized.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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DEQUE_HPP +#define BOOST_INTERPROCESS_DEQUE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#ifdef max +#undef max +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { + +namespace interprocess { + +template +class deque; + +// Note: this function is simply a kludge to work around several compilers' +// bugs in handling constant expressions. +inline std::size_t deque_buf_size(std::size_t size) + { return size < 512 ? std::size_t(512 / size) : std::size_t(1); } + +// Deque base class. It has two purposes. First, its constructor +// and destructor allocate (but don't initialize) storage. This makes +// exception safety easier. +template +class deque_base + : public boost::detail::allocator:: + rebind_to::type, + public boost::detail::allocator:: + rebind_to::type +{ + public: + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename Alloc::value_type val_alloc_diff; + typedef typename boost::detail::allocator:: + rebind_to::type ptr_alloc; + typedef typename ptr_alloc::value_type ptr_alloc_val; + typedef typename ptr_alloc::pointer ptr_alloc_ptr; + typedef typename ptr_alloc::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc::reference ptr_alloc_ref; + typedef typename ptr_alloc::const_reference ptr_alloc_cref; + + typedef typename boost::detail::allocator:: + rebind_to::type allocator_type; + + allocator_type get_allocator() const + { return *this; } + + protected: + typedef typename boost::detail::allocator:: + rebind_to::type map_allocator_type; + + val_alloc_ptr priv_allocate_node() + { return this->allocator_type::allocate(deque_buf_size(sizeof(T))); } + + void priv_deallocate_node(val_alloc_ptr p) + { this->allocator_type::deallocate(p, deque_buf_size(sizeof(T))); } + + ptr_alloc_ptr priv_allocate_map(std::size_t n) + { return this->map_allocator_type::allocate(n); } + + void priv_deallocate_map(ptr_alloc_ptr p, std::size_t n) + { this->map_allocator_type::deallocate(p, n); } + + public: + // Class invariants: + // For any nonsingular iterator i: + // i.node is the address of an element in the map array. The + // contents of i.node is a pointer to the beginning of a node. + // i.first == //(i.node) + // i.last == i.first + node_size + // i.cur is a pointer in the range [i.first, i.last). NOTE: + // the implication of this is that i.cur is always a dereferenceable + // pointer, even if i is a past-the-end iterator. + // Start and Finish are always nonsingular iterators. NOTE: this means + // that an empty deque must have one node, and that a deque + // with N elements, where N is the buffer size, must have two nodes. + // For every node other than start.node and finish.node, every element + // in the node is an initialized object. If start.node == finish.node, + // then [start.cur, finish.cur) are initialized objects, and + // the elements outside that range are uninitialized storage. Otherwise, + // [start.cur, start.last) and [finish.first, finish.cur) are initialized + // objects, and [start.first, start.cur) and [finish.cur, finish.last) + // are uninitialized storage. + // [map, map + map_size) is a valid, non-empty range. + // [start.node, finish.node] is a valid range contained within + // [map, map + map_size). + // A pointer in the range [map, map + map_size) points to an allocated node + // if and only if the pointer is in the range [start.node, finish.node]. + class const_iterator + : public boost::iterator + { + public: + static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); } + + typedef std::random_access_iterator_tag iterator_category; + typedef val_alloc_val value_type; + typedef val_alloc_cptr pointer; + typedef val_alloc_cref reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef ptr_alloc_ptr index_pointer; + typedef const_iterator self_t; + + friend class deque; + friend class deque_base; + + protected: + val_alloc_ptr m_cur; + val_alloc_ptr m_first; + val_alloc_ptr m_last; + index_pointer m_node; + + public: + const_iterator(val_alloc_ptr x, index_pointer y) + : m_cur(x), m_first(*y), + m_last(*y + s_buffer_size()), m_node(y) {} + + const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} + + const_iterator(const const_iterator& x) + : m_cur(x.m_cur), m_first(x.m_first), + m_last(x.m_last), m_node(x.m_node) {} + + reference operator*() const + { return *this->m_cur; } + + pointer operator->() const + { return this->m_cur; } + + difference_type operator-(const self_t& x) const + { + return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + + (this->m_cur - this->m_first) + (x.m_last - x.m_cur); + } + + self_t& operator++() + { + ++this->m_cur; + if (this->m_cur == this->m_last) { + this->priv_set_node(this->m_node + 1); + this->m_cur = this->m_first; + } + return *this; + } + + self_t operator++(int) + { + self_t tmp = *this; + ++*this; + return tmp; + } + + self_t& operator--() + { + if (this->m_cur == this->m_first) { + this->priv_set_node(this->m_node - 1); + this->m_cur = this->m_last; + } + --this->m_cur; + return *this; + } + + self_t operator--(int) + { + self_t tmp = *this; + --*this; + return tmp; + } + + self_t& operator+=(difference_type n) + { + difference_type offset = n + (this->m_cur - this->m_first); + if (offset >= 0 && offset < difference_type(this->s_buffer_size())) + this->m_cur += n; + else { + difference_type node_offset = + offset > 0 ? offset / difference_type(this->s_buffer_size()) + : -difference_type((-offset - 1) / this->s_buffer_size()) - 1; + this->priv_set_node(this->m_node + node_offset); + this->m_cur = this->m_first + + (offset - node_offset * difference_type(this->s_buffer_size())); + } + return *this; + } + + self_t operator+(difference_type n) const + { self_t tmp = *this; return tmp += n; } + + self_t& operator-=(difference_type n) + { return *this += -n; } + + self_t operator-(difference_type n) const + { self_t tmp = *this; return tmp -= n; } + + reference operator[](difference_type n) const + { return *(*this + n); } + + bool operator==(const self_t& x) const + { return this->m_cur == x.m_cur; } + + bool operator!=(const self_t& x) const + { return !(*this == x); } + + bool operator<(const self_t& x) const + { + return (this->m_node == x.m_node) ? + (this->m_cur < x.m_cur) : (this->m_node < x.m_node); + } + + bool operator>(const self_t& x) const + { return x < *this; } + + bool operator<=(const self_t& x) const + { return !(x < *this); } + + bool operator>=(const self_t& x) const + { return !(*this < x); } + + void priv_set_node(index_pointer new_node) + { + this->m_node = new_node; + this->m_first = *new_node; + this->m_last = this->m_first + difference_type(this->s_buffer_size()); + } + + friend const_iterator operator+(std::ptrdiff_t n, const const_iterator& x) + { return x + n; } + }; + + //Vector iterator + class iterator : public const_iterator + { + public: + typedef std::random_access_iterator_tag iterator_category; + typedef val_alloc_val value_type; + typedef ptr_alloc_ptr pointer; + typedef val_alloc_ref reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef ptr_alloc_ptr index_pointer; + typedef const_iterator self_t; + + friend class deque; + friend class deque_base; + + private: + explicit iterator(const const_iterator& x) : const_iterator(x){} + + public: + //Constructors + iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} + iterator() : const_iterator(){} + //iterator(const const_iterator &cit) : const_iterator(cit){} + iterator(const iterator& x) : const_iterator(x){} + + //Pointer like operators + reference operator*() const { return *this->m_cur; } + pointer operator->() const { return this->m_cur; } + + reference operator[](difference_type n) const { return *(*this + n); } + + //Increment / Decrement + iterator& operator++() + { this->const_iterator::operator++(); return *this; } + + iterator operator++(int) + { iterator tmp = *this; ++*this; return tmp; } + + iterator& operator--() + { this->const_iterator::operator--(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + + // Arithmetic + iterator& operator+=(difference_type off) + { this->const_iterator::operator+=(off); return *this; } + + iterator operator+(difference_type off) const + { return iterator(this->const_iterator::operator+(off)); } + + friend iterator operator+(difference_type off, const iterator& right) + { return iterator(off+static_cast(right)); } + + iterator& operator-=(difference_type off) + { this->const_iterator::operator-=(off); return *this; } + + iterator operator-(difference_type off) const + { return iterator(this->const_iterator::operator-(off)); } + + difference_type operator-(const const_iterator& right) const + { return static_cast(*this) - right; } + }; + + deque_base(const allocator_type& a, std::size_t num_elements) + : allocator_type(a), map_allocator_type(a), + m_map(0), m_map_size(0), + m_start(), m_finish() + { this->priv_initialize_map(num_elements); } + + deque_base(const allocator_type& a) + : allocator_type(a), map_allocator_type(a), + m_map(0), m_map_size(0), m_start(), m_finish() {} + + ~deque_base() + { + if (this->m_map) { + this->priv_destroy_nodes(this->m_start.m_node, this->m_finish.m_node + 1); + this->priv_deallocate_map(this->m_map, this->m_map_size); + } + } + + protected: + void priv_initialize_map(std::size_t num_elements) + { + std::size_t num_nodes = num_elements / deque_buf_size(sizeof(T)) + 1; + + this->m_map_size = std::max((std::size_t) InitialMapSize, num_nodes + 2); + this->m_map = this->priv_allocate_map(this->m_map_size); + + ptr_alloc_ptr nstart = this->m_map + (this->m_map_size - num_nodes) / 2; + ptr_alloc_ptr nfinish = nstart + num_nodes; + + BOOST_TRY { + this->priv_create_nodes(nstart, nfinish); + } + BOOST_CATCH(...){ + this->priv_deallocate_map(this->m_map, this->m_map_size); + this->m_map = 0; + this->m_map_size = 0; + BOOST_RETHROW + } + BOOST_CATCH_END + + this->m_start.priv_set_node(nstart); + this->m_finish.priv_set_node(nfinish - 1); + this->m_start.m_cur = this->m_start.m_first; + this->m_finish.m_cur = this->m_finish.m_first + + num_elements % deque_buf_size(sizeof(T)); + + } + + void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + ptr_alloc_ptr cur; + BOOST_TRY { + for (cur = nstart; cur < nfinish; ++cur) + *cur = this->priv_allocate_node(); + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(nstart, cur); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) + this->priv_deallocate_node(*n); + } + + enum { InitialMapSize = 8 }; + + protected: + ptr_alloc_ptr m_map; + std::size_t m_map_size; + iterator m_start; + iterator m_finish; +}; + +template +class deque : protected deque_base +{ + + typedef deque_base Base; + public: // Basic types + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename boost::detail::allocator:: + rebind_to::type ptr_alloc; + typedef typename ptr_alloc::value_type ptr_alloc_val; + typedef typename ptr_alloc::pointer ptr_alloc_ptr; + typedef typename ptr_alloc::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc::reference ptr_alloc_ref; + typedef typename ptr_alloc::const_reference ptr_alloc_cref; + + typedef T value_type; + typedef val_alloc_ptr pointer; + typedef val_alloc_cptr const_pointer; + typedef val_alloc_ref reference; + typedef val_alloc_cref const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef typename Base::allocator_type allocator_type; + allocator_type get_allocator() const { return Base::get_allocator(); } + + public: // Iterators + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + typedef reverse_iterator const_reverse_iterator; + typedef reverse_iterator reverse_iterator; + + protected: // Internal typedefs + typedef ptr_alloc_ptr index_pointer; + static std::size_t s_buffer_size() + { return deque_buf_size(sizeof(T)); } + + protected: + using Base::priv_initialize_map; + using Base::priv_create_nodes; + using Base::priv_destroy_nodes; + using Base::priv_allocate_node; + using Base::priv_deallocate_node; + using Base::priv_allocate_map; + using Base::priv_deallocate_map; + + using Base::m_map; + using Base::m_map_size; + using Base::m_start; + using Base::m_finish; + + public: // Basic accessors + iterator begin() + { return this->m_start; } + + iterator end() + { return this->m_finish; } + + const_iterator begin() const + { return this->m_start; } + + const_iterator end() const + { return this->m_finish; } + + reverse_iterator rbegin() + { return reverse_iterator(this->m_finish); } + + reverse_iterator rend() + { return reverse_iterator(this->m_start); } + + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->m_finish); } + + const_reverse_iterator rend() const + { return const_reverse_iterator(this->m_start); } + + reference operator[](size_type n) + { return this->m_start[difference_type(n)]; } + + const_reference operator[](size_type n) const + { return this->m_start[difference_type(n)]; } + + void priv_range_check(size_type n) const + { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } + + reference at(size_type n) + { this->priv_range_check(n); return (*this)[n]; } + + const_reference at(size_type n) const + { this->priv_range_check(n); return (*this)[n]; } + + reference front() { return *this->m_start; } + + reference back() + { + iterator tmp = this->m_finish; + --tmp; + return *tmp; + } + + const_reference front() const + { return *this->m_start; } + + const_reference back() const + { const_iterator tmp = this->m_finish; --tmp; return *tmp; } + + size_type size() const + { return this->m_finish - this->m_start; } + + size_type max_size() const + { return size_type(-1); } + + bool empty() const + { return this->m_finish == this->m_start; } + + public: // Constructor, destructor. + explicit deque(const allocator_type& a = allocator_type()) + : Base(a, 0) {} + + deque(const deque& x) : Base(x.get_allocator(), x.size()) + { std::uninitialized_copy(x.begin(), x.end(), this->m_start); } + + deque(size_type n, const value_type& value, + const allocator_type& a = allocator_type()) : Base(a, n) + { this->priv_fill_initialize(value); } + + explicit deque(size_type n) : Base(allocator_type(), n) + { this->priv_fill_initialize(value_type()); } + + // Check whether it's an integral type. If so, it's not an iterator. + template + deque(InpIt first, InpIt last, + const allocator_type& a = allocator_type()) : Base(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_initialize_dispatch(first, last, Result()); + } + + template + void priv_initialize_dispatch(Integer n, Integer x, boost::mpl::true_) + { + this->priv_initialize_map(n); + this->priv_fill_initialize(x); + } + + template + void priv_initialize_dispatch(InpIt first, InpIt last, boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_initialize(first, last, ItCat()); + } + + void priv_destroy_range(iterator p, iterator p2) + { for(;p != p2; ++p) this->allocator_type::destroy(&*p); } + + void priv_destroy_range(pointer p, pointer p2) + { for(;p != p2; ++p) this->allocator_type::destroy(p); } + + ~deque() + { priv_destroy_range(this->m_start, this->m_finish); } + + deque& operator= (const deque& x) + { + const size_type len = size(); + if (&x != this) { + if (len >= x.size()) + this->erase(std::copy(x.begin(), x.end(), this->m_start), this->m_finish); + else { + const_iterator mid = x.begin() + difference_type(len); + std::copy(x.begin(), mid, this->m_start); + this->insert(this->m_finish, mid, x.end()); + } + } + return *this; + } + + void swap(deque& x) { + std::swap(this->m_start, x.m_start); + std::swap(this->m_finish, x.m_finish); + std::swap(this->m_map, x.m_map); + std::swap(this->m_map_size, x.m_map_size); + } + + public: + // 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 priv_fill_assign(size_type n, const T& val) { + if (n > size()) { + std::fill(begin(), end(), val); + this->insert(end(), n - size(), val); + } + else { + this->erase(begin() + n, end()); + std::fill(begin(), end(), val); + } + } + + void assign(size_type n, const T& val) { + this->priv_fill_assign(n, val); + } + + template + void assign(InpIt first, InpIt last) { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + private: // helper functions for assign() + + template + void priv_assign_dispatch(Integer n, Integer val, boost::mpl::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) + { + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first) + *cur = *first; + if (first == last) + this->erase(cur, end()); + else + this->insert(end(), first, last); + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, + std::forward_iterator_tag) { + size_type len = 0; + std::distance(first, last, len); + if (len > size()) { + FwdIt mid = first; + std::advance(mid, size()); + std::copy(first, mid, begin()); + this->insert(end(), mid, last); + } + else + this->erase(std::copy(first, last, begin()), end()); + } + + public: // push_* and pop_* + + void push_back(const value_type& t) + { + if (this->m_finish.m_cur != this->m_finish.m_last - 1) { + this->allocator_type::construct(this->m_finish.m_cur, t); + ++this->m_finish.m_cur; + } + else + this->priv_push_back_aux(t); + } + + void push_back() + { + if (this->m_finish.m_cur != this->m_finish.m_last - 1) { + this->allocator_type::construct(this->m_finish.m_cur, value_type()); + ++this->m_finish.m_cur; + } + else + this->priv_push_back_aux(); + } + + void push_front(const value_type& t) { + if (this->m_start.m_cur != this->m_start.m_first) { + this->allocator_type::construct(this->m_start.m_cur - 1, t); + --this->m_start.m_cur; + } + else + this->priv_push_front_aux(t); + } + + void push_front() + { + if (this->m_start.m_cur != this->m_start.m_first) { + this->allocator_type::construct(this->m_start.m_cur - 1, value_type()); + --this->m_start.m_cur; + } + else + this->priv_push_front_aux(); + } + + + void pop_back() + { + if (this->m_finish.m_cur != this->m_finish.m_first) { + --this->m_finish.m_cur; + this->allocator_type::destroy(this->m_finish.m_cur); + } + else + this->priv_pop_back_aux(); + } + + void pop_front() + { + if (this->m_start.m_cur != this->m_start.m_last - 1) { + this->allocator_type::destroy(this->m_start.m_cur); + ++this->m_start.m_cur; + } + else + this->priv_pop_front_aux(); + } + + public: // Insert + + iterator insert(iterator position, const value_type& x) + { + if (position.m_cur == this->m_start.m_cur) { + this->push_front(x); + return this->m_start; + } + else if (position.m_cur == this->m_finish.m_cur) { + this->push_back(x); + iterator tmp = this->m_finish; + --tmp; + return tmp; + } + else { + return this->priv_insert_aux(position, x); + } + } + + iterator insert(iterator position) + { return insert(position, value_type()); } + + void insert(iterator pos, size_type n, const value_type& x) + { this->priv_fill_insert(pos, n, x); } + + // Check whether it's an integral type. If so, it's not an iterator. + template + void insert(iterator pos, InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + template + void priv_insert_dispatch(iterator pos, Integer n, Integer x, + boost::mpl::true_) + { + this->priv_fill_insert(pos, (size_type) n, (value_type) x); + } + + template + void priv_insert_dispatch(iterator pos, + InpIt first, InpIt last, + boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->insert(pos, first, last, ItCat()); + } + + void resize(size_type new_size, const value_type& x) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->m_start + new_size, this->m_finish); + else + this->insert(this->m_finish, new_size - len, x); + } + + void resize(size_type new_size) + { resize(new_size, value_type()); } + + template + void insert(iterator pos, InpIt first, InpIt last, std::input_iterator_tag) + { std::copy(first, last, std::inserter(*this, pos)); } + + template + void insert(iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) + { + + size_type n = 0; + n = std::distance(first, last); + + if (pos.m_cur == this->m_start.m_cur) { + iterator new_start = this->priv_reserve_elements_at_front(n); + BOOST_TRY{ + std::uninitialized_copy(first, last, new_start); + this->m_start = new_start; + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(new_start.m_node, this->m_start.m_node); + BOOST_RETHROW + } + BOOST_CATCH_END + } + else if (pos.m_cur == this->m_finish.m_cur) { + iterator new_finish = this->priv_reserve_elements_at_back(n); + BOOST_TRY{ + std::uninitialized_copy(first, last, this->m_finish); + this->m_finish = new_finish; + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(this->m_finish.m_node + 1, new_finish.m_node + 1); + BOOST_RETHROW + } + BOOST_CATCH_END + } + else + this->priv_insert_aux(pos, first, last, n); + } + + public: // Erase + iterator erase(iterator pos) + { + iterator next = pos; + ++next; + difference_type index = pos - this->m_start; + if (size_type(index) < (this->size() >> 1)) { + std::copy_backward(this->m_start, pos, next); + pop_front(); + } + else { + std::copy(next, this->m_finish, pos); + pop_back(); + } + return this->m_start + index; + } + + private: // Internal insert functions + + iterator priv_insert_aux(iterator pos, const value_type& x = value_type()) + { + size_type n = pos - begin(); + this->priv_insert_aux(pos, size_type(1), x); + return iterator(this->begin() + n); + } + + void priv_insert_aux(iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + this->insert(pos, c_it(x, n), c_it()); + } + + template + void priv_insert_aux(iterator pos, FwdIt first, FwdIt last, size_type n) + { + const difference_type elemsbefore = pos - this->m_start; + size_type length = size(); + if (elemsbefore < static_cast(length / 2)) { + iterator new_start = this->priv_reserve_elements_at_front(n); + iterator old_start = this->m_start; + pos = this->m_start + elemsbefore; + BOOST_TRY { + if (elemsbefore >= difference_type(n)) { + iterator start_n = this->m_start + difference_type(n); + std::uninitialized_copy(this->m_start, start_n, new_start); + this->m_start = new_start; + std::copy(start_n, pos, old_start); + std::copy(first, last, pos - difference_type(n)); + } + else { + FwdIt mid = first; + std::advance(mid, difference_type(n) - elemsbefore); + this->priv_uninitialized_copy_copy(this->m_start, pos, first, mid, new_start); + this->m_start = new_start; + std::copy(mid, last, old_start); + } + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(new_start.m_node, this->m_start.m_node); + BOOST_RETHROW + } + BOOST_CATCH_END + } + else { + iterator new_finish = this->priv_reserve_elements_at_back(n); + iterator old_finish = this->m_finish; + const difference_type elemsafter = + difference_type(length) - elemsbefore; + pos = this->m_finish - elemsafter; + BOOST_TRY { + if (elemsafter > difference_type(n)) { + iterator finish_n = this->m_finish - difference_type(n); + std::uninitialized_copy(finish_n, this->m_finish, this->m_finish); + this->m_finish = new_finish; + std::copy_backward(pos, finish_n, old_finish); + std::copy(first, last, pos); + } + else { + FwdIt mid = first; + std::advance(mid, elemsafter); + this->priv_uninitialized_copy_copy(mid, last, pos, this->m_finish, this->m_finish); + this->m_finish = new_finish; + std::copy(first, mid, pos); + } + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(this->m_finish.m_node + 1, new_finish.m_node + 1); + BOOST_RETHROW + } + BOOST_CATCH_END + } + } + + void priv_fill_insert(iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + this->insert(pos, c_it(x, n), c_it()); + } + + iterator erase(iterator first, iterator last) + { + if (first == this->m_start && last == this->m_finish) { + this->clear(); + return this->m_finish; + } + else { + difference_type n = last - first; + difference_type elems_before = first - this->m_start; + if (elems_before < difference_type((this->size() - n) / 2)) { + std::copy_backward(this->m_start, first, last); + iterator new_start = this->m_start + n; + this->priv_destroy_range(this->m_start, new_start); + this->priv_destroy_nodes(new_start.m_node, this->m_start.m_node); + this->m_start = new_start; + } + else { + std::copy(last, this->m_finish, first); + iterator new_finish = this->m_finish - n; + this->priv_destroy_range(new_finish, this->m_finish); + this->priv_destroy_nodes(new_finish.m_node + 1, this->m_finish.m_node + 1); + this->m_finish = new_finish; + } + return this->m_start + elems_before; + } + } + + void clear() + { + for (index_pointer node = this->m_start.m_node + 1; + node < this->m_finish.m_node; + ++node) { + this->priv_destroy_range(*node, *node + this->s_buffer_size()); + this->priv_deallocate_node(*node); + } + + if (this->m_start.m_node != this->m_finish.m_node) { + this->priv_destroy_range(this->m_start.m_cur, this->m_start.m_last); + this->priv_destroy_range(this->m_finish.m_first, this->m_finish.m_cur); + this->priv_deallocate_node(this->m_finish.m_first); + } + else + this->priv_destroy_range(this->m_start.m_cur, this->m_finish.m_cur); + + this->m_finish = this->m_start; + } + + private: // Internal construction/destruction + + // Precondition: this->m_start and this->m_finish have already been initialized, + // but none of the deque's elements have yet been constructed. + void priv_fill_initialize(const value_type& value) + { + index_pointer cur; + BOOST_TRY { + for (cur = this->m_start.m_node; cur < this->m_finish.m_node; ++cur){ + std::uninitialized_fill(*cur, *cur + this->s_buffer_size(), value); + } + std::uninitialized_fill(this->m_finish.m_first, this->m_finish.m_cur, value); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->m_start, iterator(*cur, cur)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) + { + this->priv_initialize_map(0); + BOOST_TRY { + for ( ; first != last; ++first) + this->push_back(*first); + } + BOOST_CATCH(...){ + this->clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = 0; + n = std::distance(first, last); + this->priv_initialize_map(n); + + index_pointer cur_node; + BOOST_TRY { + for (cur_node = this->m_start.m_node; + cur_node < this->m_finish.m_node; + ++cur_node) { + FwdIt mid = first; + std::advance(mid, this->s_buffer_size()); + std::uninitialized_copy(first, mid, *cur_node); + first = mid; + } + std::uninitialized_copy(first, last, this->m_finish.m_first); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->m_start, iterator(*cur_node, cur_node)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->m_finish.m_cur == this->m_finish.m_last - 1. + void priv_push_back_aux(const value_type& t) + { + value_type t_copy = t; + this->priv_reserve_map_at_back(); + *(this->m_finish.m_node + 1) = this->priv_allocate_node(); + BOOST_TRY { + this->allocator_type::construct(this->m_finish.m_cur, t_copy); + this->m_finish.priv_set_node(this->m_finish.m_node + 1); + this->m_finish.m_cur = this->m_finish.m_first; + } + BOOST_CATCH(...){ + this->priv_deallocate_node(*(this->m_finish.m_node + 1)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->m_finish.m_cur == this->m_finish.m_last - 1. + void priv_push_back_aux() + { + this->priv_reserve_map_at_back(); + *(this->m_finish.m_node + 1) = this->priv_allocate_node(); + BOOST_TRY { + this->allocator_type::construct(this->m_finish.m_cur, value_type()); + this->m_finish.priv_set_node(this->m_finish.m_node + 1); + this->m_finish.m_cur = this->m_finish.m_first; + } + BOOST_CATCH(...){ + this->priv_deallocate_node(*(this->m_finish.m_node + 1)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->m_start.m_cur == this->m_start.m_first. + void priv_push_front_aux(const value_type& t = value_type()) + { + const value_type &t_copy = t; + this->priv_reserve_map_at_front(); + *(this->m_start.m_node - 1) = this->priv_allocate_node(); + BOOST_TRY { + this->m_start.priv_set_node(this->m_start.m_node - 1); + this->m_start.m_cur = this->m_start.m_last - 1; + this->allocator_type::construct(this->m_start.m_cur, t_copy); + } + BOOST_CATCH(...){ + ++this->m_start; + this->priv_deallocate_node(*(this->m_start.m_node - 1)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->m_finish.m_cur == this->m_finish.m_first. + void priv_pop_back_aux() + { + this->priv_deallocate_node(this->m_finish.m_first); + this->m_finish.priv_set_node(this->m_finish.m_node - 1); + this->m_finish.m_cur = this->m_finish.m_last - 1; + this->allocator_type::destroy(this->m_finish.m_cur); + } + + // Called only if this->m_start.m_cur == this->m_start.m_last - 1. Note that + // if the deque has at least one element (a precondition for this member + // function), and if this->m_start.m_cur == this->m_start.m_last, then the deque + // must have at least two nodes. + void priv_pop_front_aux() + { + this->allocator_type::destroy(this->m_start.m_cur); + this->priv_deallocate_node(this->m_start.m_first); + this->m_start.priv_set_node(this->m_start.m_node + 1); + this->m_start.m_cur = this->m_start.m_first; + } + + iterator priv_reserve_elements_at_front(size_type n) + { + size_type vacancies = this->m_start.m_cur - this->m_start.m_first; + if (n > vacancies) + this->priv_new_elements_at_front(n - vacancies); + return this->m_start - difference_type(n); + } + + iterator priv_reserve_elements_at_back(size_type n) + { + size_type vacancies = (this->m_finish.m_last - this->m_finish.m_cur) - 1; + if (n > vacancies) + this->priv_new_elements_at_back(n - vacancies); + return this->m_finish + difference_type(n); + } + + void priv_new_elements_at_front(size_type new_elems) + { + size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / + this->s_buffer_size(); + this->priv_reserve_map_at_front(new_nodes); + size_type i; + BOOST_TRY { + for (i = 1; i <= new_nodes; ++i) + *(this->m_start.m_node - i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->m_start.m_node - j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void priv_new_elements_at_back(size_type new_elems) + { + size_type new_nodes = (new_elems + this->s_buffer_size() - 1) + / this->s_buffer_size(); + this->priv_reserve_map_at_back(new_nodes); + size_type i; + BOOST_TRY { + for (i = 1; i <= new_nodes; ++i) + *(this->m_finish.m_node + i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->m_finish.m_node + j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + private: // Allocation of this->m_map and nodes + + // Makes sure the this->m_map has space for new nodes. Does not actually + // add the nodes. Can invalidate this->m_map pointers. (And consequently, + // deque iterators.) + void priv_reserve_map_at_back (size_type nodes_to_add = 1) + { + if (nodes_to_add + 1 > this->m_map_size - (this->m_finish.m_node - this->m_map)) + this->priv_reallocate_map(nodes_to_add, false); + } + + void priv_reserve_map_at_front (size_type nodes_to_add = 1) + { + if (nodes_to_add > size_type(this->m_start.m_node - this->m_map)) + this->priv_reallocate_map(nodes_to_add, true); + } + + void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) + { + size_type old_num_nodes = this->m_finish.m_node - this->m_start.m_node + 1; + size_type new_num_nodes = old_num_nodes + nodes_to_add; + + index_pointer new_nstart; + if (this->m_map_size > 2 * new_num_nodes) { + new_nstart = this->m_map + (this->m_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + if (new_nstart < this->m_start.m_node) + std::copy(this->m_start.m_node, this->m_finish.m_node + 1, new_nstart); + else + std::copy_backward(this->m_start.m_node, this->m_finish.m_node + 1, + new_nstart + old_num_nodes); + } + else { + size_type new_map_size = + this->m_map_size + std::max(this->m_map_size, nodes_to_add) + 2; + + index_pointer new_map = this->priv_allocate_map(new_map_size); + new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + std::copy(this->m_start.m_node, this->m_finish.m_node + 1, new_nstart); + this->priv_deallocate_map(this->m_map, this->m_map_size); + + this->m_map = new_map; + this->m_map_size = new_map_size; + } + + this->m_start.priv_set_node(new_nstart); + this->m_finish.priv_set_node(new_nstart + old_num_nodes - 1); + } + + private: + + // this->priv_uninitialized_copy_fill + // Copies [first1, last1) into [first2, first2 + (last1 - first1)), and + // fills [first2 + (last1 - first1), last2) with x. + void priv_uninitialized_copy_fill(iterator first1, iterator last1, + iterator first2, iterator last2, + const T& x) + { + iterator mid2 = std::uninitialized_copy(first1, last1, first2); + BOOST_TRY { + std::uninitialized_fill(mid2, last2, x); + } + BOOST_CATCH(...){ + for(;first2 != mid2; ++first2){ + this->allocator_type::destroy(&*first2); + } + } + BOOST_CATCH_END + } + + // this->priv_uninitialized_fill_copy + // Fills [result, mid) with x, and copies [first, last) into + // [mid, mid + (last - first)). + iterator priv_uninitialized_fill_copy(iterator result, iterator mid, + const T& x, + iterator first, iterator last) + { + std::uninitialized_fill(result, mid, x); + BOOST_TRY { + return std::uninitialized_copy(first, last, mid); + } + BOOST_CATCH(...){ + for(;result != mid; ++result){ + this->allocator_type::destroy(&*result); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // this->priv_uninitialized_copy_copy + // Copies [first1, last1) into [result, result + (last1 - first1)), and + // copies [first2, last2) into + // [result, result + (last1 - first1) + (last2 - first2)). + template + FwdIt priv_uninitialized_copy_copy(InpIt1 first1, InpIt1 last1, + InpIt2 first2, InpIt2 last2, + FwdIt result) + { + FwdIt mid = std::uninitialized_copy(first1, last1, result); + BOOST_TRY { + return std::uninitialized_copy(first2, last2, mid); + } + BOOST_CATCH(...){ + for(;result != mid; ++result){ + this->allocator_type::destroy(&*result); + } + BOOST_RETHROW + } + BOOST_CATCH_END + } +}; + +// Nonmember functions. +template +inline bool operator==(const deque& x, + const deque& y) +{ + return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool operator<(const deque& x, + const deque& y) +{ + return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const deque& x, + const deque& y) + { return !(x == y); } + +template +inline bool operator>(const deque& x, + const deque& y) + { return y < x; } + +template +inline bool operator<=(const deque& x, + const deque& y) + { return !(y < x); } + +template +inline bool operator>=(const deque& x, + const deque& y) + { return !(x < y); } + +template +inline void swap(deque& x, deque& y) + { x.swap(y); } + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DEQUE_HPP + diff --git a/include/boost/interprocess/containers/detail/Attic/tree_func.hpp b/include/boost/interprocess/containers/detail/Attic/tree_func.hpp new file mode 100644 index 0000000..8aee602 --- /dev/null +++ b/include/boost/interprocess/containers/detail/Attic/tree_func.hpp @@ -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 +#include + +#include + +namespace boost { +namespace interprocess { +namespace detail { + +template +struct rb_tree_node_base +{ + typedef typename boost::interprocess::detail::pointer_to_other + >::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 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 rb_tree_func : public rb_tree_algo +{ + typedef rb_tree_algo::type> > rb_tree_algo_t; + +// typedef rb_tree_algo 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::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::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 rb_tree_const_iterator + : public boost::iterator +{ + private: + typedef boost::iterator base_t; + + protected: + typedef typename Node::node_pointer node_pointer; + typedef typename Node::basic_node_pointer basic_node_pointer; + typedef rb_tree_algo 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 rb_tree_iterator : public rb_tree_const_iterator +{ + private: + typedef rb_tree_const_iterator 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 + +#endif //BOOST_INTERPROCESS_TREE_FUNC_HPP + diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/detail/flat_tree.hpp new file mode 100644 index 0000000..65bbb70 --- /dev/null +++ b/include/boost/interprocess/containers/detail/flat_tree.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace detail { + +template +class flat_tree +{ + typedef boost::interprocess::vector 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 reverse_iterator; + typedef boost::reverse_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 insert_unique(const value_type& val) + { return this->priv_insert_unique(this->begin(), this->end(), val); } + + // insert/erase + std::pair 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 + void insert_unique(InIt first, InIt last) + { + for ( ; first != last; ++first) + this->insert_unique(*first); + } + + template + 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 itp = this->equal_range(k); + size_type ret = static_cast(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 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 equal_range(const key_type& k) + { + return this->priv_equal_range(this->begin(), this->end(), k); + } + + std::pair 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 + 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 + 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 + std::pair + 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(left, right); + } + } + return std::pair(first, first); + } + + template + void priv_insert_unique(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type len = static_cast(std::distance(first, last)); + this->reserve(this->size()+len); + priv_insert_unique(first, last, std::input_iterator_tag()); + } + + template + void priv_insert_equal(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type len = static_cast(std::distance(first, last)); + this->reserve(this->size()+len); + this->priv_insert_equal(first, last, std::input_iterator_tag()); + } + + template + void priv_insert_unique(InIt first, InIt last, std::input_iterator_tag) + { + for ( ; first != last; ++first) + this->insert_unique(*first); + } + + template + void priv_insert_equal(InIt first, InIt last, std::input_iterator_tag) + { + for ( ; first != last; ++first) + this->insert_equal(*first); + } +}; + +template +inline bool +operator==(const flat_tree& x, + const flat_tree& y) +{ + return x.size() == y.size() && + std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const flat_tree& x, + const flat_tree& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); +} + +template +inline bool +operator!=(const flat_tree& x, + const flat_tree& y) + { return !(x == y); } + +template +inline bool +operator>(const flat_tree& x, + const flat_tree& y) + { return y < x; } + +template +inline bool +operator<=(const flat_tree& x, + const flat_tree& y) + { return !(y < x); } + +template +inline bool +operator>=(const flat_tree& x, + const flat_tree& y) + { return !(x < y); } + + +template +inline void +swap(flat_tree& x, + flat_tree& y) + { x.swap(y); } + +} //namespace detail { + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif // BOOST_INTERPROCESS_FLAT_TREE_HPP diff --git a/include/boost/interprocess/containers/detail/tree_func.hpp b/include/boost/interprocess/containers/detail/tree_func.hpp new file mode 100644 index 0000000..8aee602 --- /dev/null +++ b/include/boost/interprocess/containers/detail/tree_func.hpp @@ -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 +#include + +#include + +namespace boost { +namespace interprocess { +namespace detail { + +template +struct rb_tree_node_base +{ + typedef typename boost::interprocess::detail::pointer_to_other + >::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 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 rb_tree_func : public rb_tree_algo +{ + typedef rb_tree_algo::type> > rb_tree_algo_t; + +// typedef rb_tree_algo 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::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::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 rb_tree_const_iterator + : public boost::iterator +{ + private: + typedef boost::iterator base_t; + + protected: + typedef typename Node::node_pointer node_pointer; + typedef typename Node::basic_node_pointer basic_node_pointer; + typedef rb_tree_algo 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 rb_tree_iterator : public rb_tree_const_iterator +{ + private: + typedef rb_tree_const_iterator 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 + +#endif //BOOST_INTERPROCESS_TREE_FUNC_HPP + diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp new file mode 100644 index 0000000..23d63c7 --- /dev/null +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -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 +#include + +#include +#include +#include +#include +#include + + +namespace boost { namespace interprocess { + +// Forward declarations of operators == and <, needed for friend declarations. +template +class flat_map; + +template +inline bool operator==(const flat_map& x, + const flat_map& y); + +template +inline bool operator<(const flat_map& x, + const flat_map& y); + +template +class flat_map +{ + private: + typedef detail::flat_tree, + detail::select1st< std::pair >, + 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 + flat_map(InputIterator first, InputIterator last) + : m_flat_tree(Pred(), allocator_type()) + { m_flat_tree.insert_unique(first, last); } + + template + 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& x) + : m_flat_tree(x.m_flat_tree) {} + + flat_map& operator=(const flat_map& 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& x) + { m_flat_tree.swap(x.m_flat_tree); } + + // insert/erase + + std::pair 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 + 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 equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + std::pair 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 + friend bool operator== (const flat_map&, + const flat_map&); + template + friend bool operator< (const flat_map&, + const flat_map&); +}; + +template +inline bool operator==(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_map& x, + const flat_map& y) + { return !(x == y); } + +template +inline bool operator>(const flat_map& x, + const flat_map& y) + { return y < x; } + +template +inline bool operator<=(const flat_map& x, + const flat_map& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_map& x, + const flat_map& y) + { return !(x < y); } + +template +inline void swap(flat_map& x, + flat_map& y) + { x.swap(y); } + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +class flat_multimap; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y); + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y); + +template +class flat_multimap +{ + private: + typedef detail::flat_tree, + detail::select1st< std::pair >, + 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 + 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& x) + : m_flat_tree(x.m_flat_tree) { } + + flat_multimap& + operator=(const flat_multimap& 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& 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 + 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 equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + std::pair + 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 + friend bool operator== (const flat_multimap& x, + const flat_multimap& y); + + template + friend bool operator< (const flat_multimap& x, + const flat_multimap& y); +}; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multimap& x, + const flat_multimap& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multimap& x, + const flat_multimap& y) + { return y < x; } + +template +inline bool operator<=(const flat_multimap& x, + const flat_multimap& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multimap& x, + const flat_multimap& y) + { return !(x < y); } + +template +inline void swap(flat_multimap& x, + flat_multimap& y) + { x.swap(y); } + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_FLAT_MAP_HPP */ + diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp new file mode 100644 index 0000000..913a4b5 --- /dev/null +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -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 +#include + +#include +#include +#include +#include +#include + + +namespace boost { namespace interprocess { + +// Forward declarations of operators < and ==, needed for friend declaration. + +template +class flat_set; + +template +inline bool operator==(const flat_set& x, + const flat_set& y); + +template +inline bool operator<(const flat_set& x, + const flat_set& y); + + +template +class flat_set +{ + private: + typedef detail::flat_tree, 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 + 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& x) + : m_flat_tree(x.m_flat_tree) {} + + flat_set& operator=(const flat_set& 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& x) + { m_flat_tree.swap(x.m_flat_tree); } + + // insert/erase + std::pair 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 + 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 + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + std::pair + 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 + friend bool operator== (const flat_set&, const flat_set&); + + template + friend bool operator< (const flat_set&, const flat_set&); +}; + +template +inline bool operator==(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_set& x, + const flat_set& y) + { return !(x == y); } + +template +inline bool operator>(const flat_set& x, + const flat_set& y) + { return y < x; } + +template +inline bool operator<=(const flat_set& x, + const flat_set& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_set& x, + const flat_set& y) + { return !(x < y); } + +template +inline void swap(flat_set& x, + flat_set& y) + { x.swap(y); } + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +class flat_multiset; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y); + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y); + +template +class flat_multiset +{ + private: + typedef detail::flat_tree, 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 + 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& x) + : m_flat_tree(x.m_flat_tree) {} + + flat_multiset& operator=(const flat_multiset& 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& 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 + 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 + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + std::pair + 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 + friend bool operator== (const flat_multiset&, + const flat_multiset&); + template + friend bool operator< (const flat_multiset&, + const flat_multiset&); +}; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multiset& x, + const flat_multiset& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multiset& x, + const flat_multiset& y) + { return y < x; } + +template +inline bool operator<=(const flat_multiset& x, + const flat_multiset& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multiset& x, + const flat_multiset& y) +{ return !(x < y); } + +template +inline void swap(flat_multiset& x, + flat_multiset& y) + { x.swap(y); } + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_SHMEM_FLAT_SET_HPP */ + +// Local Variables: +// mode:C++ +// End: diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp new file mode 100644 index 0000000..364a3e7 --- /dev/null +++ b/include/boost/interprocess/containers/list.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace detail { + +template +struct interprocess_list_node; + +template +struct interprocess_list_node_base +{ + typedef typename boost::detail::allocator:: + rebind_to >::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 +struct interprocess_list_node + : public interprocess_list_node_base +{ + typedef typename boost::detail::allocator:: + rebind_to >::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 +struct interprocess_list_alloc + : public boost::detail::allocator:: + rebind_to >::type, + public boost::detail::allocator:: + rebind_to >:: + type::pointer >::type, + public A +{ + typedef interprocess_list_node Node; + typedef typename boost::detail::allocator:: + rebind_to >::type NodeAlloc; + typedef typename boost::detail::allocator:: + rebind_to::type PtrAlloc; + typedef A ValAlloc; + typedef typename NodeAlloc::pointer NodePtr; + typedef detail::scoped_deallocator Deallocator; + typedef detail::scoped_destructor PtrDestructor; + + enum { + node_has_trivial_destructor = + boost::has_trivial_destructor::value | + boost::has_trivial_destructor::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::value){ + scoped_ptrnode_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 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::value){ + PtrAlloc::destroy(&m_node->m_next); + PtrAlloc::destroy(&m_node->m_prev); + } + NodeAlloc::deallocate(m_node, 1); + } + + template + NodePtr create_node(NodePtr next, NodePtr prev, const Convertible& x) + { + NodePtr p = NodeAlloc::allocate(1); + scoped_ptrnode_deallocator(m_node, *this); + + //Make sure destructors are called before memory is freed + //if an exception is thrown + { + if(!boost::has_trivial_constructor::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 next_destroy(pnext, *this); + + PtrAlloc::construct(pprev, prev); + + scoped_ptr 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(*this) != + static_cast(x)){ + detail::do_swap(static_cast(*this), + static_cast(x)); + detail::do_swap(static_cast(*this), + static_cast(x)); + detail::do_swap(static_cast(*this), + static_cast(x)); + } + detail::do_swap(this->m_node, x.m_node); + } + + protected: + typename NodeAlloc::pointer m_node; +}; + +template +struct interprocess_list_alloc + : public boost::detail::allocator:: + rebind_to >::type +{ + typedef interprocess_list_node Node; + typedef typename boost::detail::allocator:: + rebind_to >::type NodeAlloc; + typedef typename boost::detail::allocator:: + rebind_to::type PtrAlloc; + typedef A ValAlloc; + typedef typename NodeAlloc::pointer NodePtr; + typedef detail::scoped_deallocator Deallocator; + typedef detail::scoped_destructor PtrDestructor; + + enum { + node_has_trivial_destructor = + boost::has_trivial_destructor::value | + boost::has_trivial_destructor::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 + NodePtr create_node(NodePtr next, NodePtr prev, const Convertible& x) + { + NodePtr p = NodeAlloc::allocate(1); + scoped_ptrnode_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(*this); + NodeAlloc& other_alloc = static_cast(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::value){ + typedef typename PtrAlloc::pointer NodePtrPtr; + scoped_ptrnode_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 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::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 list + : protected detail::interprocess_list_alloc::value> +{ + typedef detail::interprocess_list_alloc::value> AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef list ThisType; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::PtrAlloc PtrAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef detail::interprocess_list_node 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 + { + 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; + 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; + 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 reverse_iterator; + typedef boost::reverse_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 + 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 + void insert(iterator pos, InpIt first, InpIt last) + { + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ 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 + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ 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 + 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 + 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& x) + { this->merge(x, value_less()); } + + template + void merge(list& 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 + 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 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 + void priv_insert_dispatch(iterator position, + InputIter first, InputIter last, + boost::mpl::false_) + { + for ( ; first != last; ++first){ + this->insert(position, *first); + } + } + + template + 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 + 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 + 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 +inline bool operator==(const list& x, const list& y) +{ + typedef typename list::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 +inline bool operator<(const list& x, + const list& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const list& x, const list& y) +{ + return !(x == y); +} + +template +inline bool operator>(const list& x, const list& y) +{ + return y < x; +} + +template +inline bool operator<=(const list& x, const list& y) +{ + return !(y < x); +} + +template +inline bool operator>=(const list& x, const list& y) +{ + return !(x < y); +} + +template +inline void swap(list& x, list& y) +{ + x.swap(y); +} + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif // BOOST_INTERPROCESS_LIST_HPP_ diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp new file mode 100644 index 0000000..8a1e49b --- /dev/null +++ b/include/boost/interprocess/containers/map.hpp @@ -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 +#include + +#include +#include +#include +#include +#include + + +namespace boost { namespace interprocess { + +// Forward declarations of operators == and <, needed for friend declarations. +template +inline bool operator==(const map& x, + const map& y); + +template +inline bool operator<(const map& x, + const map& y); + +template +class map +{ + private: + typedef detail::rb_tree, + detail::select1st< std::pair >, + 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 + { + friend class map; + 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 + map(InputIterator first, InputIterator last) + : m_tree(Pred(), allocator_type()) + { m_tree.insert_unique(first, last); } + + template + 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& x) + : m_tree(x.m_tree) {} + + map& operator=(const map& 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& x) + { m_tree.swap(x.m_tree); } + + // insert/erase + + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + std::pair 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 + 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 equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + std::pair equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + template + friend bool operator== (const map&, + const map&); + template + friend bool operator< (const map&, + const map&); +}; + +template +inline bool operator==(const map& x, + const map& y) + { return x.m_tree == y.m_tree; } + +template +inline bool operator<(const map& x, + const map& y) + { return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const map& x, + const map& y) + { return !(x == y); } + +template +inline bool operator>(const map& x, + const map& y) + { return y < x; } + +template +inline bool operator<=(const map& x, + const map& y) + { return !(y < x); } + +template +inline bool operator>=(const map& x, + const map& y) + { return !(x < y); } + +template +inline void swap(map& x, + map& y) + { x.swap(y); } + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multimap& x, + const multimap& y); + +template +inline bool operator<(const multimap& x, + const multimap& y); + +template +class multimap +{ + private: + typedef detail::rb_tree, + detail::select1st< std::pair >, + 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 + { + friend class multimap; + 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 + multimap(InputIterator first, InputIterator last) + : m_tree(Pred(), allocator_type()) + { m_tree.insert_equal(first, last); } + + template + 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& x) + : m_tree(x.m_tree) { } + + multimap& + operator=(const multimap& 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& 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 + 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 equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + template + friend bool operator== (const multimap& x, + const multimap& y); + + template + friend bool operator< (const multimap& x, + const multimap& y); +}; + +template +inline bool operator==(const multimap& x, + const multimap& y) + { return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multimap& x, + const multimap& y) + { return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multimap& x, + const multimap& y) + { return !(x == y); } + +template +inline bool operator>(const multimap& x, + const multimap& y) + { return y < x; } + +template +inline bool operator<=(const multimap& x, + const multimap& y) + { return !(y < x); } + +template +inline bool operator>=(const multimap& x, + const multimap& y) + { return !(x < y); } + +template +inline void swap(multimap& x, + multimap& y) + { x.swap(y); } + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_SHMEM_MAP_HPP */ + diff --git a/include/boost/interprocess/containers/old_string.hpp b/include/boost/interprocess/containers/old_string.hpp new file mode 100644 index 0000000..d93a9f6 --- /dev/null +++ b/include/boost/interprocess/containers/old_string.hpp @@ -0,0 +1,1879 @@ +/* + * Copyright (c) 1997-1999 + * 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. 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/shmem for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This file comes from SGI's string 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_SHMEM_STRING_HPP +#define BOOST_SHMEM_STRING_HPP + +#include +#include + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +// Standard C++ string class. This class has performance +// characteristics very much like vector<>, meaning, for example, that +// it does not perform reference-count or copy-on-write, and that +// concatenation of two strings is an O(N) operation. + +// There are three reasons why basic_string is not identical to +// vector. First, basic_string always stores a null character at the +// end; this makes it possible for c_str to be a fast operation. +// Second, the C++ standard requires basic_string to copy elements +// using char_traits<>::assign, char_traits<>::copy, and +// char_traits<>::move. This means that all of vector<>'s low-level +// operations must be rewritten. Third, basic_string<> has a lot of +// extra functions in its interface that are convenient but, strictly +// speaking, redundant. + +namespace boost { namespace shmem { + +// ------------------------------------------------------------ +// Class basic_string_base. + +// basic_string_base is a helper class that makes it it easier to write +// an exception-safe version of basic_string. The constructor allocates, +// but does not initialize, a block of memory. The destructor +// deallocates, but does not destroy elements within, a block of +// memory. The destructor assumes that this->m_start either is null, or else +// points to a block of memory that was allocated using _String_base's +// allocator and whose size is this->m_end_of_storage - this->m_start. +template +class basic_string_base : public Alloc +{ + public: + typedef Alloc allocator_type; + typedef typename Alloc::pointer pointer; + typedef typename Alloc::value_type value_type; + + allocator_type get_allocator() const { return *this; } + + basic_string_base(const allocator_type& a) + : allocator_type(a), + m_start(0), + m_finish(0), + m_end_of_storage(0) + {} + + basic_string_base(const allocator_type& a, std::size_t n) + : allocator_type(a), + m_start(0), + m_finish(0), + m_end_of_storage(0) + { allocate_block(n); } + + ~basic_string_base() + { deallocate_block(); } + +protected: + pointer allocate(std::size_t n) + { return allocator_type::allocate(n); } + + void deallocate(pointer p, std::size_t n) + { if (p) allocator_type::deallocate(p, n); } + + void construct(pointer p, const value_type &value = value_type()) + { allocator_type::construct(p, value); } + + void destroy(pointer p, pointer p2) + { for(;p != p2; ++p) allocator_type::destroy(p); } + + void destroy(pointer p) + { allocator_type::destroy(p); } + + void allocate_block(std::size_t n) { + if (n <= max_size()) { + m_start = allocate(n); + m_finish = m_start; + m_end_of_storage = m_start + n; + } + else + throw_length_error(); + } + + void deallocate_block() + { deallocate(m_start, m_end_of_storage - m_start); } + + std::size_t max_size() const { return (std::size_t(-1) / sizeof(value_type)) - 1; } + + // Helper functions for exception handling. + void throw_length_error() const + { throw(std::length_error("basic_string")); } + + void throw_out_of_range() const + { throw(std::out_of_range("basic_string")); } + +protected: + pointer m_start; + pointer m_finish; + pointer m_end_of_storage; +}; + +// ------------------------------------------------------------ +// Class basic_string. + +// Class invariants: +// (1) [start, finish) is a valid range. +// (2) Each iterator in [start, finish) points to a valid object +// of type value_type. +// (3) *finish is a valid object of type value_type; in particular, +// it is value_type(). +// (4) [finish + 1, end_of_storage) is a valid range. +// (5) Each iterator in [finish + 1, end_of_storage) points to +// uninitialized memory. + +// Note one important consequence: a string of length n must manage +// a block of memory whose size is at least n + 1. + + +template +class basic_string : private basic_string_base +{ + private: + typedef basic_string_base base_t; + + protected: + // A helper class to use a char_traits as a function object. + + template + struct Eq_traits + : public std::binary_function + { + bool operator()(const typename Tr::char_type& x, + const typename Tr::char_type& y) const + { return Tr::eq(x, y); } + }; + + template + struct Not_within_traits + : public std::unary_function + { + typedef const typename Tr::char_type* Pointer; + const Pointer m_first; + const Pointer m_last; + + Not_within_traits(Pointer f, Pointer l) + : m_first(f), m_last(l) {} + + bool operator()(const typename Tr::char_type& x) const + { + return find_if(m_first, m_last, + bind1st(Eq_traits(), x)) == m_last; + } + }; + + public: + typedef Alloc allocator_type; + typedef CharT value_type; + typedef Traits traits_type; + typedef typename Alloc::pointer pointer; + typedef typename Alloc::const_pointer const_pointer; + typedef typename Alloc::reference reference; + typedef typename Alloc::const_reference const_reference; + typedef typename Alloc::size_type size_type; + typedef typename Alloc::difference_type difference_type; + typedef const_pointer const_iterator; + typedef pointer iterator; + typedef boost::reverse_iterator reverse_iterator; + typedef boost::reverse_iterator const_reverse_iterator; + static const size_type npos; + + public: // Constructor, destructor, assignment. + allocator_type get_allocator() const + { return base_t::get_allocator(); } + + explicit basic_string(const allocator_type& a = allocator_type()) + : base_t(a, 8) { this->priv_terminate_string(); } + + struct reserve_t {}; + + basic_string(reserve_t, std::size_t n, + const allocator_type& a = allocator_type()) + : base_t(a, n + 1) { this->priv_terminate_string(); } + + basic_string(const basic_string& s) + : base_t(s.get_allocator()) + { this->priv_range_initialize(s.begin(), s.end()); } + + basic_string(const basic_string& s, size_type pos, size_type n = npos, + const allocator_type& a = allocator_type()) + : base_t(a) + { + if (pos > s.size()) + this->throw_out_of_range(); + else + this->priv_range_initialize + (s.begin() + pos, s.begin() + pos + std::min(n, s.size() - pos)); + } + + basic_string(const CharT* s, size_type n, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + n); } + + basic_string(const CharT* s, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + Traits::length(s)); } + + basic_string(size_type n, CharT c, + const allocator_type& a = allocator_type()) + : base_t(a, n + 1) + { + priv_uninitialized_fill_n(this->m_start, n, c, *this); + this->m_finish = this->m_start+n; + this->priv_terminate_string(); + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string(InputIterator f, InputIterator l, + const allocator_type& a = allocator_type()) + : base_t(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_initialize_dispatch(f, l, Result()); + } + + ~basic_string() + { this->destroy(this->m_start, this->m_finish + 1); } + + basic_string& operator=(const basic_string& s) { + if (&s != this) + assign(s.begin(), s.end()); + return *this; + } + + basic_string& operator=(const CharT* s) + { return assign(s, s + Traits::length(s)); } + + basic_string& operator=(CharT c) + { return assign(static_cast(1), c); } + + private: // Helper functions used by constructors + // and elsewhere. + void priv_construct_null(pointer p) { + this->construct(p, 0); + } + + static CharT priv_null() { + return (CharT) 0; + } + + private: + // Helper functions used by constructors. It is a severe error for + // any of them to be called anywhere except from within constructors. + void priv_terminate_string() + { + BOOST_TRY{ + this->priv_construct_null(this->m_finish); + } + BOOST_CATCH(...){ + this->destroy(this->m_start, this->m_finish); + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(InputIter f, InputIter l, + std::input_iterator_tag) { + this->allocate_block(8); + this->priv_construct_null(this->m_finish); + BOOST_TRY{ + append(f, l); + } + BOOST_CATCH(...){ + this->destroy(this->m_start, this->m_finish + 1); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(ForwardIter f, ForwardIter l, + std::forward_iterator_tag) { + difference_type n = 0; + n = std::distance(f, l); + this->allocate_block(n + 1); + this->m_finish = priv_uninitialized_copy(f, l, this->m_start, *this); + this->priv_terminate_string(); + } + + template + void priv_range_initialize(InputIter f, InputIter l) { + typedef typename std::iterator_traits::iterator_category Category; + this->priv_range_initialize(f, l, Category()); + } + + template + void priv_initialize_dispatch(Integer n, Integer x, boost::mpl::true_) { + this->allocate_block(n + 1); + priv_uninitialized_fill_n(this->m_start, n, x, *this); + this->m_finish = this->m_start + n; + this->priv_terminate_string(); + } + + template + void priv_initialize_dispatch(InputIter f, InputIter l, boost::mpl::false_) { + this->priv_range_initialize(f, l); + } + + public: // Iterators. + iterator begin() { return this->m_start; } + iterator end() { return this->m_finish; } + const_iterator begin() const { return this->m_start; } + const_iterator end() const { return this->m_finish; } + + reverse_iterator rbegin() + { return reverse_iterator(this->m_finish); } + reverse_iterator rend() + { return reverse_iterator(this->m_start); } + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->m_finish); } + const_reverse_iterator rend() const + { return const_reverse_iterator(this->m_start); } + + public: // Size, capacity, etc. + size_type size() const { return this->m_finish - this->m_start; } + size_type length() const { return size(); } + + size_type max_size() const { return base_t::max_size(); } + + + void resize(size_type n, CharT c) { + if (n <= size()) + erase(begin() + n, end()); + else + append(n - size(), c); + } + + void resize(size_type n) { resize(n, this->priv_null()); } + + // Change the string's capacity so that it is large enough to hold + // at least priv_res_arg elements, plus the terminating null. Note that, + // if priv_res_arg < capacity(), this member function may actually decrease + // the string's capacity. + void reserve(size_type res_arg) + { + if (res_arg > this->max_size()) + this->throw_length_error(); + + size_type n = std::max(res_arg, size()) + 1; + pointer new_start = this->allocate(n); + pointer new_finish = new_start; + + BOOST_TRY{ + new_finish = priv_uninitialized_copy + (this->m_start, this->m_finish, new_start, *this); + this->priv_construct_null(new_finish); + } + BOOST_CATCH(...){ + this->destroy(new_start, new_finish); + this->deallocate(new_start, n); + } + BOOST_CATCH_END + + this->destroy(this->m_start, this->m_finish + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_finish = new_finish; + this->m_end_of_storage = new_start + n; + } + + size_type capacity() const { return (this->m_end_of_storage - this->m_start) - 1; } + + void clear() { + if (!empty()) { + Traits::assign(*this->m_start, this->priv_null()); + this->destroy(this->m_start+1, this->m_finish+1); + this->m_finish = this->m_start; + } + } + + bool empty() const { return this->m_start == this->m_finish; } + + public: // Element access. + + const_reference operator[](size_type n) const + { return *(this->m_start + n); } + reference operator[](size_type n) + { return *(this->m_start + n); } + + const_reference at(size_type n) const { + if (n >= size()) + this->throw_out_of_range(); + return *(this->m_start + n); + } + + reference at(size_type n) { + if (n >= size()) + this->throw_out_of_range(); + return *(this->m_start + n); + } + + public: // Append, operator+=, push_back. + + basic_string& operator+=(const basic_string& s) { return append(s); } + basic_string& operator+=(const CharT* s) { return append(s); } + basic_string& operator+=(CharT c) { push_back(c); return *this; } + + basic_string& append(const basic_string& s) + { return append(s.begin(), s.end()); } + + basic_string& append(const basic_string& s, + size_type pos, size_type n) + { + if (pos > s.size()) + this->throw_out_of_range(); + return append(s.begin() + pos, + s.begin() + pos + std::min(n, s.size() - pos)); + } + + basic_string& append(const CharT* s, size_type n) + { return append(s, s+n); } + + basic_string& append(const CharT* s) + { return append(s, s + Traits::length(s)); } + + basic_string& append(size_type n, CharT c) + { + if (n > this->max_size() || size() > this->max_size() - n) + this->throw_length_error(); + if (size() + n > capacity()) + reserve(size() + std::max(size(), n)); + if (n > 0) { + priv_uninitialized_fill_n(this->m_finish + 1, n - 1, c, *this); + BOOST_TRY{ + this->priv_construct_null(this->m_finish + n); + } + BOOST_CATCH(...){ + this->destroy(this->m_finish + 1, this->m_finish + n); + } + BOOST_CATCH_END + Traits::assign(*this->m_finish, c); + this->m_finish += n; + } + return *this; + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string& append(InputIter first, InputIter last) { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + return this->priv_append_dispatch(first, last, Result()); + } + + void push_back(CharT c) { + if (this->m_finish + 1 == this->m_end_of_storage) + reserve(size() + std::max(size(), static_cast(1))); + this->priv_construct_null(this->m_finish + 1); + Traits::assign(*this->m_finish, c); + ++this->m_finish; + } + + void pop_back() { + Traits::assign(*(this->m_finish - 1), this->priv_null()); + this->destroy(this->m_finish); + --this->m_finish; + } + + private: // Helper functions for append. + + template inline + void priv_uninitialized_fill_n(FwdIt first, Count count, + const CharT val, A& 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 inline + FwdIt priv_uninitialized_copy(InpIt first, InpIt last, + FwdIt dest, A& 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 + basic_string& append(InputIter first, InputIter last, std::input_iterator_tag) + { + for ( ; first != last ; ++first) + push_back(*first); + return *this; + } + + template + basic_string& append(ForwardIter first, ForwardIter last, + std::forward_iterator_tag) + { + if (first != last) { + const size_type old_size = size(); + difference_type n = 0; + n = std::distance(first, last); + if (static_cast(n) > this->max_size() || + old_size > this->max_size() - static_cast(n)) + this->throw_length_error(); + if (old_size + static_cast(n) > capacity()) { + const size_type len = old_size + + std::max(old_size, static_cast(n)) + 1; + pointer new_start = this->allocate(len); + pointer new_finish = new_start; + BOOST_TRY{ + new_finish = priv_uninitialized_copy + (this->m_start, this->m_finish, new_start, *this); + new_finish = priv_uninitialized_copy + (first, last, new_finish, *this); + this->priv_construct_null(new_finish); + } + BOOST_CATCH(...){ + this->destroy(new_start,new_finish); + this->deallocate(new_start,len); + } + BOOST_CATCH_END + + this->destroy(this->m_start, this->m_finish + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_finish = new_finish; + this->m_end_of_storage = new_start + len; + } + else { + ForwardIter f1 = first; + ++f1; + priv_uninitialized_copy(f1, last, this->m_finish + 1, *this); + BOOST_TRY{ + this->priv_construct_null(this->m_finish + n); + } + BOOST_CATCH(...){ + this->destroy(this->m_finish + 1, this->m_finish + n); + } + BOOST_CATCH_END + Traits::assign(*this->m_finish, *first); + this->m_finish += n; + } + } + return *this; + + } + + template + basic_string& priv_append_dispatch(Integer n, Integer x, boost::mpl::true_) { + return append((size_type) n, (CharT) x); + } + + template + basic_string& priv_append_dispatch(InputIter f, InputIter l, + boost::mpl::false_) { + typedef typename std::iterator_traits::iterator_category Category; + return append(f, l, Category()); + } + + public: // Assign + + basic_string& assign(const basic_string& s) + { return assign(s.begin(), s.end()); } + + basic_string& assign(const basic_string& s, + size_type pos, size_type n) { + if (pos > s.size()) + this->throw_out_of_range(); + return assign(s.begin() + pos, + s.begin() + pos + std::min(n, s.size() - pos)); + } + + basic_string& assign(const CharT* s, size_type n) + { return assign(s, s + n); } + + basic_string& assign(const CharT* s) + { return assign(s, s + Traits::length(s)); } + + basic_string& assign(size_type n, CharT c) + { + if (n <= size()) { + Traits::assign(detail::get_pointer(this->m_start), n, c); + erase(this->m_start + n, this->m_finish); + } + else { + Traits::assign(detail::get_pointer(this->m_start), size(), c); + append(n - size(), c); + } + return *this; + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string& assign(InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + return this->priv_assign_dispatch(first, last, Result()); + } + + basic_string& assign(const CharT* f, const CharT* l) + { + const std::ptrdiff_t n = l - f; + if (static_cast(n) <= size()) { + Traits::copy(detail::get_pointer(this->m_start), f, n); + erase(this->m_start + n, this->m_finish); + } + else { + Traits::copy(detail::get_pointer(this->m_start), f, size()); + append(f + size(), l); + } + return *this; + } + + private: // Helper functions for assign. + + template + basic_string& priv_assign_dispatch(Integer n, Integer x, boost::mpl::true_) + { return assign((size_type) n, (CharT) x); } + + template + basic_string& priv_assign_dispatch(InputIter f, InputIter l, + boost::mpl::false_) + { + pointer cur = this->m_start; + while (f != l && cur != this->m_finish) { + Traits::assign(*cur, *f); + ++f; + ++cur; + } + if (f == l) + erase(cur, this->m_finish); + else + append(f, l); + return *this; + + } + + public: // Insert + + basic_string& insert(size_type pos, const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + if (size() > this->max_size() - s.size()) + this->throw_length_error(); + insert(this->m_start + pos, s.begin(), s.end()); + return *this; + } + + basic_string& insert(size_type pos, const basic_string& s, + size_type beg, size_type n) + { + if (pos > size() || beg > s.size()) + this->throw_out_of_range(); + size_type len = std::min(n, s.size() - beg); + if (size() > this->max_size() - len) + this->throw_length_error(); + insert(this->m_start + pos, s.begin() + beg, s.begin() + beg + len); + return *this; + } + + basic_string& insert(size_type pos, const CharT* s, size_type n) + { + if (pos > size()) + this->throw_out_of_range(); + if (size() > this->max_size() - n) + this->throw_length_error(); + insert(this->m_start + pos, s, s + n); + return *this; + } + + basic_string& insert(size_type pos, const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + size_type len = Traits::length(s); + if (size() > this->max_size() - len) + this->throw_length_error(); + insert(this->m_start + pos, s, s + len); + return *this; + } + + basic_string& insert(size_type pos, size_type n, CharT c) + { + if (pos > size()) + this->throw_out_of_range(); + if (size() > this->max_size() - n) + this->throw_length_error(); + insert(this->m_start + pos, n, c); + return *this; + } + + iterator insert(iterator p, CharT c) + { + if (p == this->m_finish) { + push_back(c); + return this->m_finish - 1; + } + else + return this->priv_insert_aux(p, c); + } + + void insert(iterator position, std::size_t n, CharT c) + { + if (n != 0) { + if (size_type(this->m_end_of_storage - this->m_finish) >= n + 1) { + const size_type elems_after = this->m_finish - position; + iterator old_finish = this->m_finish; + if (elems_after >= n) { + priv_uninitialized_copy((this->m_finish - n) + 1, + this->m_finish + 1, + this->m_finish + 1, *this); + this->m_finish += n; + Traits::move(detail::get_pointer(position + n), + detail::get_pointer(position), + (elems_after - n) + 1); + Traits::assign(detail::get_pointer(position), n, c); + } + else { + priv_uninitialized_fill_n + (this->m_finish + 1, n - elems_after - 1, c, *this); + this->m_finish += n - elems_after; + BOOST_TRY{ + priv_uninitialized_copy + (position, old_finish + 1, this->m_finish, *this); + this->m_finish += elems_after; + } + BOOST_CATCH(...){ + this->destroy(old_finish + 1, this->m_finish); + this->m_finish = old_finish; + } + BOOST_CATCH_END + Traits::assign(detail::get_pointer(position), elems_after + 1, c); + } + } + else { + const size_type old_size = size(); + const size_type len = old_size + std::max(old_size, n) + 1; + iterator new_start = this->allocate(len); + iterator new_finish = new_start; + BOOST_TRY{ + new_finish = priv_uninitialized_copy + (this->m_start, position, new_start, *this); + priv_uninitialized_fill_n(new_finish, n, c, *this); + new_finish = new_finish + n; + new_finish = priv_uninitialized_copy(position, this->m_finish, + new_finish, *this); + this->priv_construct_null(new_finish); + } + BOOST_CATCH(...){ + this->destroy(new_start,new_finish); + this->deallocate(new_start,len); + } + BOOST_CATCH_END + this->destroy(this->m_start, this->m_finish + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_finish = new_finish; + this->m_end_of_storage = new_start + len; + } + } + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + void insert(iterator p, InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + private: // Helper functions for insert. + + template + void insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) + { + for ( ; first != last; ++first) { + p = insert(p, *first); + ++p; + } + } + + template + void insert(iterator position, ForwardIter first, + ForwardIter last, std::forward_iterator_tag) + { + if (first != last) { + difference_type n = 0; + n = std::distance(first, last); + if (this->m_end_of_storage - this->m_finish >= n + 1) { + const difference_type elems_after = this->m_finish - position; + iterator old_finish = this->m_finish; + if (elems_after >= n) { + priv_uninitialized_copy((this->m_finish - n) + 1, this->m_finish + 1, + this->m_finish + 1, *this); + this->m_finish += n; + Traits::move(detail::get_pointer(position + n), + detail::get_pointer(position), + (elems_after - n) + 1); + this->priv_copy(first, last, position); + } + else { + ForwardIter mid = first; + std::advance(mid, elems_after + 1); + priv_uninitialized_copy(mid, last, this->m_finish + 1, *this); + this->m_finish += n - elems_after; + BOOST_TRY{ + priv_uninitialized_copy + (position, old_finish + 1, this->m_finish, *this); + this->m_finish += elems_after; + } + BOOST_CATCH(...){ + this->destroy(old_finish + 1, this->m_finish); + this->m_finish = old_finish; + } + BOOST_CATCH_END + this->priv_copy(first, mid, position); + } + } + else { + const size_type old_size = size(); + const size_type len + = old_size + std::max(old_size, static_cast(n)) + 1; + pointer new_start = this->allocate(len); + pointer new_finish = new_start; + BOOST_TRY{ + new_finish = priv_uninitialized_copy + (this->m_start, position, new_start, *this); + new_finish = priv_uninitialized_copy + (first, last, new_finish, *this); + new_finish = priv_uninitialized_copy + (position, this->m_finish, new_finish, *this); + this->priv_construct_null(new_finish); + } + BOOST_CATCH(...){ + this->destroy(new_start,new_finish); + this->deallocate(new_start,len); + } + BOOST_CATCH_END + this->destroy(this->m_start, this->m_finish + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_finish = new_finish; + this->m_end_of_storage = new_start + len; + } + } + } + + template + void priv_insert_dispatch(iterator p, Integer n, Integer x, + boost::mpl::true_) + { insert(p, (size_type) n, (CharT) x); } + + template + void priv_insert_dispatch(iterator p, InputIter first, InputIter last, + boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + insert(p, first, last, Category()); + } + + template + void priv_copy(InputIterator first, InputIterator last, iterator result) + { + for ( ; first != last; ++first, ++result) + Traits::assign(*result, *first); + } + + iterator priv_insert_aux(iterator p, CharT c) + { + iterator new_pos = p; + if (this->m_finish + 1 < this->m_end_of_storage) { + this->priv_construct_null(this->m_finish + 1); + Traits::move(detail::get_pointer(p + 1), + detail::get_pointer(p), + this->m_finish - p); + Traits::assign(*p, c); + ++this->m_finish; + } + else { + const size_type old_len = size(); + const size_type len = old_len + + std::max(old_len, static_cast(1)) + 1; + iterator new_start = this->allocate(len); + iterator new_finish = new_start; + BOOST_TRY{ + new_pos = priv_uninitialized_copy + (this->m_start, p, new_start, *this); + this->construct(new_pos, c); + new_finish = new_pos + 1; + new_finish = priv_uninitialized_copy + (p, this->m_finish, new_finish, *this); + this->priv_construct_null(new_finish); + } + BOOST_CATCH(...){ + this->destroy(new_start,new_finish); + this->deallocate(new_start,len); + } + BOOST_CATCH_END + this->destroy(this->m_start, this->m_finish + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_finish = new_finish; + this->m_end_of_storage = new_start + len; + } + return new_pos; + } + + void priv_copy(const CharT* first, const CharT* last, CharT* result) + { Traits::copy(result, first, last - first); } + + public: // Erase. + + basic_string& erase(size_type pos = 0, size_type n = npos) + { + if (pos > size()) + this->throw_out_of_range(); + erase(this->m_start + pos, this->m_start + pos + std::min(n, size() - pos)); + return *this; + } + + iterator erase(iterator position) + { + // The move includes the terminating null. + Traits::move(detail::get_pointer(position), + detail::get_pointer(position + 1), + this->m_finish - position); + this->destroy(this->m_finish); + --this->m_finish; + return position; + } + + iterator erase(iterator first, iterator last) + { + if (first != last) { // The move includes the terminating null. + Traits::move(detail::get_pointer(first), + detail::get_pointer(last), + (this->m_finish - last) + 1); + const iterator new_finish = this->m_finish - (last - first); + this->destroy(new_finish + 1, this->m_finish + 1); + this->m_finish = new_finish; + } + return first; + } + + public: // Replace. (Conceptually equivalent + // to erase followed by insert.) + basic_string& replace(size_type pos, size_type n, + const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n, size() - pos); + if (size() - len >= this->max_size() - s.size()) + this->throw_length_error(); + return replace(this->m_start + pos, this->m_start + pos + len, + s.begin(), s.end()); + } + + basic_string& replace(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) + { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + const size_type len1 = std::min(n1, size() - pos1); + const size_type len2 = std::min(n2, s.size() - pos2); + if (size() - len1 >= this->max_size() - len2) + this->throw_length_error(); + return replace(this->m_start + pos1, this->m_start + pos1 + len1, + s.m_start + pos2, s.m_start + pos2 + len2); + } + + basic_string& replace(size_type pos, size_type n1, + const CharT* s, size_type n2) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return replace(this->m_start + pos, this->m_start + pos + len, + s, s + n2); + } + + basic_string& replace(size_type pos, size_type n1, + const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n1, size() - pos); + const size_type n2 = Traits::length(s); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return replace(this->m_start + pos, this->m_start + pos + len, + s, s + Traits::length(s)); + } + + basic_string& replace(size_type pos, size_type n1, + size_type n2, CharT c) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return replace(this->m_start + pos, this->m_start + pos + len, n2, c); + } + + basic_string& replace(iterator first, iterator last, + const basic_string& s) + { return replace(first, last, s.begin(), s.end()); } + + basic_string& replace(iterator first, iterator last, + const CharT* s, size_type n) + { return replace(first, last, s, s + n); } + + basic_string& replace(iterator first, iterator last, + const CharT* s) + { return replace(first, last, s, s + Traits::length(s)); } + + basic_string& replace(iterator first, iterator last, + size_type n, CharT c) + { + const size_type len = static_cast(last - first); + if (len >= n) { + Traits::assign(detail::get_pointer(first), n, c); + erase(first + n, last); + } + else { + Traits::assign(detail::get_pointer(first), len, c); + insert(last, n - len, c); + } + return *this; + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string& replace(iterator first, iterator last, + InputIter f, InputIter l) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + return this->priv_replace_dispatch(first, last, f, l, Result()); + } + + private: // Helper functions for replace. + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + Integer n, Integer x, + boost::mpl::true_) + { return replace(first, last, (size_type) n, (CharT) x); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + InputIter f, InputIter l, + boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + return replace(first, last, f, l, Category()); + } + + + template + basic_string& replace(iterator first, iterator last, + InputIter f, InputIter l, std::input_iterator_tag) + { + for ( ; first != last && f != l; ++first, ++f) + Traits::assign(*first, *f); + + if (f == l) + erase(first, last); + else + insert(last, f, l); + return *this; + } + + template + basic_string& replace(iterator first, iterator last, + ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = 0; + n = std::distance(f, l); + const difference_type len = last - first; + if (len >= n) { + this->priv_copy(f, l, first); + erase(first + n, last); + } + else { + ForwardIter m = f; + std::advance(m, len); + this->priv_copy(f, m, first); + insert(last, m, l); + } + return *this; + } + + public: // Other modifier member functions. + + size_type copy(CharT* s, size_type n, size_type pos = 0) const + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n, size() - pos); + Traits::copy(s, detail::get_pointer(this->m_start + pos), len); + return len; + } + + void swap(basic_string& s) + { + detail::do_swap(this->m_start, s.m_start); + detail::do_swap(this->m_finish, s.m_finish); + detail::do_swap(this->m_end_of_storage, s.m_end_of_storage); + allocator_type & this_al = *this, &s_al = s; + if(this_al != s_al){ + detail::do_swap(this_al, s_al); + } + } + + public: // Conversion to C string. + + const CharT* c_str() const + { return detail::get_pointer(this->m_start); } + + const CharT* data() const + { return detail::get_pointer(this->m_start); } + + public: // find. + + size_type find(const basic_string& s, size_type pos = 0) const + { return find(s.c_str(), pos, s.size()); } + + size_type find(const CharT* s, size_type pos = 0) const + { return find(s, pos, Traits::length(s)); } + + size_type find(const CharT* s, size_type pos, size_type n) const + { + if (pos + n > size()) + return npos; + else { + const const_iterator result = + search(detail::get_pointer(this->m_start + pos), + detail::get_pointer(this->m_finish), + s, s + n, Eq_traits()); + return result != this->m_finish ? result - begin() : npos; + } + } + + size_type find(CharT c, size_type pos = 0) const + { + if (pos >= size()) + return npos; + else { + const const_iterator result = + find_if(this->m_start + pos, this->m_finish, + std::bind2nd(Eq_traits(), c)); + return result != this->m_finish ? result - begin() : npos; + } + } + + public: // rfind. + + size_type rfind(const basic_string& s, size_type pos = npos) const + { return rfind(s.c_str(), pos, s.size()); } + + size_type rfind(const CharT* s, size_type pos = npos) const + { return rfind(s, pos, Traits::length(s)); } + + size_type rfind(const CharT* s, size_type pos, size_type n) const + { + const std::size_t len = size(); + + if (n > len) + return npos; + else if (n == 0) + return std::min(len, pos); + else { + const const_iterator last = begin() + std::min(len - n, pos) + n; + const const_iterator result = find_end(begin(), last, + s, s + n, + Eq_traits()); + return result != last ? result - begin() : npos; + } + } + + size_type rfind(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + std::min(len - 1, pos) + 1; + const_reverse_iterator rresult = + find_if(const_reverse_iterator(last), rend(), + std::bind2nd(Eq_traits(), c)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + public: // find_first_of + + size_type find_first_of(const basic_string& s, size_type pos = 0) const + { return find_first_of(s.c_str(), pos, s.size()); } + + size_type find_first_of(const CharT* s, size_type pos = 0) const + { return find_first_of(s, pos, Traits::length(s)); } + + size_type find_first_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos >= size()) + return npos; + else { + const_iterator result = std::find_first_of(begin() + pos, end(), + s, s + n, + Eq_traits()); + return result != this->m_finish ? result - begin() : npos; + } + } + + size_type find_first_of(CharT c, size_type pos = 0) const + { return find(c, pos); } + + public: // find_last_of + + size_type find_last_of(const basic_string& s, + size_type pos = npos) const + { return find_last_of(s.c_str(), pos, s.size()); } + + size_type find_last_of(const CharT* s, size_type pos = npos) const + { return find_last_of(s, pos, Traits::length(s)); } + + size_type find_last_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = this->m_start + std::min(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_first_of(const_reverse_iterator(last), rend(), + s, s + n, + Eq_traits()); + return rresult != rend() ? (rresult.base() - 1) - this->m_start : npos; + } + } + + size_type find_last_of(CharT c, size_type pos = npos) const + { return rfind(c, pos); } + + public: // find_first_not_of + + size_type find_first_not_of(const basic_string& s, + size_type pos = 0) const + { return find_first_not_of(s.c_str(), pos, s.size()); } + + size_type find_first_not_of(const CharT* s, size_type pos = 0) const + { return find_first_not_of(s, pos, Traits::length(s)); } + + size_type find_first_not_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos > size()) + return npos; + else { + const_iterator result = find_if(this->m_start + pos, this->m_finish, + Not_within_traits(s, s + n)); + return result != this->m_finish ? result - this->m_start : npos; + } + } + + size_type find_first_not_of(CharT c, size_type pos = 0) const + { + if (pos > size()) + return npos; + else { + const_iterator result + = find_if(begin() + pos, end(), + not1(std::bind2nd(Eq_traits(), c))); + return result != this->m_finish ? result - begin() : npos; + } + } + + public: // find_last_not_of + + size_type find_last_not_of(const basic_string& s, + size_type pos = npos) const + { return find_last_not_of(s.c_str(), pos, s.size()); } + + size_type find_last_not_of(const CharT* s, size_type pos = npos) const + { return find_last_not_of(s, pos, Traits::length(s)); } + + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + std::min(len - 1, pos) + 1; + const const_reverse_iterator rresult = + find_if(const_reverse_iterator(last), rend(), + Not_within_traits(s, s + n)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + size_type find_last_not_of(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + std::min(len - 1, pos) + 1; + const_reverse_iterator rresult = + find_if(const_reverse_iterator(last), rend(), + not1(std::bind2nd(Eq_traits(), c))); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + public: // Substring. + + basic_string substr(size_type pos = 0, size_type n = npos) const + { + if (pos > size()) + this->throw_out_of_range(); + return basic_string(this->m_start + pos, + this->m_start + pos + std::min(n, size() - pos), *this); + } + + public: // Compare + + int compare(const basic_string& s) const + { return this->s_compare(this->m_start, this->m_finish, s.m_start, s.m_finish); } + + int compare(size_type pos1, size_type n1, const basic_string& s) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s.m_start, s.m_finish); + } + + int compare(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) const { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s.m_start + pos2, + s.m_start + pos2 + std::min(n2, size() - pos2)); + } + + int compare(const CharT* s) const + { return this->s_compare(this->m_start, this->m_finish, s, s + Traits::length(s)); } + + int compare(size_type pos1, size_type n1, const CharT* s) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s, s + Traits::length(s)); + } + + int compare(size_type pos1, size_type n1, const CharT* s, + size_type n2) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s, s + n2); + } + +public: // Helper function for compare. + static int s_compare(const_pointer f1, const_pointer l1, + const_pointer f2, const_pointer l2) + { + const std::ptrdiff_t n1 = l1 - f1; + const std::ptrdiff_t n2 = l2 - f2; + const int cmp = Traits::compare(detail::get_pointer(f1), + detail::get_pointer(f2), + std::min(n1, n2)); + return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); + } +}; + +template +const typename basic_string::size_type +basic_string::npos + = (typename basic_string::size_type) -1; + +// ------------------------------------------------------------ +// Non-member functions. + +// Operator+ + +template +inline basic_string +operator+(const basic_string& x, + const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + y.size(), x.get_allocator()); + result.append(x); + result.append(y); + return result; +} + +template +inline basic_string +operator+(const CharT* s, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, n + y.size()); + result.append(s, s + n); + result.append(y); + return result; +} + +template +inline basic_string +operator+(CharT c, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, 1 + y.size()); + result.push_back(c); + result.append(y); + return result; +} + +template +inline basic_string +operator+(const basic_string& x, const CharT* s) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, x.size() + n, x.get_allocator()); + result.append(x); + result.append(s, s + n); + return result; +} + +template +inline basic_string +operator+(const basic_string& x, const CharT c) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + 1, x.get_allocator()); + result.append(x); + result.push_back(c); + return result; +} + +// Operator== and operator!= + +template +inline bool +operator==(const basic_string& x, + const basic_string& y) +{ + return x.size() == y.size() && + Traits::compare(x.data(), y.data(), x.size()) == 0; +} + +template +inline bool +operator==(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return n == y.size() && Traits::compare(s, y.data(), n) == 0; +} + +template +inline bool +operator==(const basic_string& x, const CharT* s) +{ + std::size_t n = Traits::length(s); + return x.size() == n && Traits::compare(x.data(), s, n) == 0; +} + +template +inline bool +operator!=(const basic_string& x, + const basic_string& y) + { return !(x == y); } + +template +inline bool +operator!=(const CharT* s, const basic_string& y) + { return !(s == y); } + +template +inline bool +operator!=(const basic_string& x, const CharT* s) + { return !(x == s); } + + +// Operator< (and also >, <=, and >=). + +template +inline bool +operator<(const basic_string& x, + const basic_string& y) +{ + return basic_string + ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return basic_string + ::s_compare(s, s + n, y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const basic_string& x, + const CharT* s) +{ + std::size_t n = Traits::length(s); + return basic_string + ::s_compare(x.begin(), x.end(), s, s + n) < 0; +} + +template +inline bool +operator>(const basic_string& x, + const basic_string& y) { + return y < x; +} + +template +inline bool +operator>(const CharT* s, const basic_string& y) { + return y < s; +} + +template +inline bool +operator>(const basic_string& x, const CharT* s) +{ + return s < x; +} + +template +inline bool +operator<=(const basic_string& x, + const basic_string& y) +{ + return !(y < x); +} + +template +inline bool +operator<=(const CharT* s, const basic_string& y) + { return !(y < s); } + +template +inline bool +operator<=(const basic_string& x, const CharT* s) + { return !(s < x); } + +template +inline bool +operator>=(const basic_string& x, + const basic_string& y) + { return !(x < y); } + +template +inline bool +operator>=(const CharT* s, const basic_string& y) + { return !(s < y); } + +template +inline bool +operator>=(const basic_string& x, const CharT* s) + { return !(x < s); } + +// Swap. + +template +inline void swap(basic_string& x, + basic_string& y) + { x.swap(y); } + +// I/O. + +template +inline bool +sgi_string_fill(std::basic_ostream& os, + std::basic_streambuf* buf, + std::size_t n) +{ + CharT f = os.fill(); + std::size_t i; + bool ok = true; + + for (i = 0; i < n; i++) + ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); + return ok; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const basic_string& s) +{ + typename std::basic_ostream::sentry sentry(os); + bool ok = false; + + if (sentry) { + ok = true; + std::size_t n = s.size(); + std::size_t pad_len = 0; + const bool left = (os.flags() & std::ios::left) != 0; + const std::size_t w = os.width(0); + std::basic_streambuf* buf = os.rdbuf(); + + if (w != 0 && n < w) + pad_len = w - n; + + if (!left) + ok = sgi_string_fill(os, buf, pad_len); + + ok = ok && + buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); + + if (left) + ok = ok && sgi_string_fill(os, buf, pad_len); + } + + if (!ok) + os.setstate(std::ios_base::failbit); + + return os; +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, + basic_string& s) +{ + typename std::basic_istream::sentry sentry(is); + + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + const std::ctype& ctype = std::use_facet >(is.getloc()); + + s.clear(); + std::size_t n = is.width(0); + if (n == 0) + n = static_cast(-1); + else + s.reserve(n); + + while (n-- > 0) { + typename Traits::int_type c1 = buf->sbumpc(); + + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + CharT c = Traits::to_char_type(c1); + + if (ctype.is(std::ctype::space, c)) { + if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) + is.setstate(std::ios_base::failbit); + break; + } + else + s.push_back(c); + } + } + + // If we have read no characters, then set failbit. + if (s.size() == 0) + is.setstate(std::ios_base::failbit); + } + else + is.setstate(std::ios_base::failbit); + + return is; +} + +template +std::basic_istream& +getline(std::istream& is, + basic_string& s, + CharT delim) +{ + std::size_t nread = 0; + typename std::basic_istream::sentry sentry(is, true); + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + s.clear(); + + int c1; + while (nread < s.max_size()) { + int c1 = buf->sbumpc(); + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + ++nread; + CharT c = Traits::to_char_type(c1); + if (!Traits::eq(c, delim)) + s.push_back(c); + else + break; // Character is extracted but not appended. + } + } + } + if (nread == 0 || nread >= s.max_size()) + is.setstate(std::ios_base::failbit); + + return is; +} + +template +inline std::basic_istream& +getline(std::basic_istream& is, + basic_string& s) +{ + return getline(is, s, '\n'); +} + +template +inline std::size_t hash_value(std::basic_string, A> const& v) +{ + return hash_range(v.begin(), v.end()); +} + +typedef basic_string, std::allocator > string; + +}} //namespace boost { namespace shmem + +#include + +#endif // BOOST_SHMEM_STRING_HPP + + +// Local Variables: +// mode:C++ +// End: + diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp new file mode 100644 index 0000000..7304188 --- /dev/null +++ b/include/boost/interprocess/containers/set.hpp @@ -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 +#include + +#include +#include +#include +#include +#include + + +namespace boost { namespace interprocess { + +// Forward declarations of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const set& x, + const set& y); + +template +inline bool operator<(const set& x, + const set& y); + + +template +class set +{ + private: + typedef detail::rb_tree, 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 + set(InputIterator first, InputIterator last) + : m_tree(Pred(), allocator_type()) + { m_tree.insert_unique(first, last); } + + template + 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& x) + : m_tree(x.m_tree) {} + + set& operator=(const set& 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& x) + { m_tree.swap(x.m_tree); } + + // insert/erase + std::pair 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 + 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 + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + template + friend bool operator== (const set&, const set&); + + template + friend bool operator< (const set&, const set&); +}; + +template +inline bool operator==(const set& x, + const set& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const set& x, + const set& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const set& x, + const set& y) +{ return !(x == y); } + +template +inline bool operator>(const set& x, + const set& y) +{ return y < x; } + +template +inline bool operator<=(const set& x, + const set& y) +{ return !(y < x); } + +template +inline bool operator>=(const set& x, + const set& y) +{ return !(x < y); } + +template +inline void swap(set& x, + set& y) +{ x.swap(y); } + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multiset& x, + const multiset& y); + +template +inline bool operator<(const multiset& x, + const multiset& y); + +template +class multiset +{ + private: + typedef detail::rb_tree, 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 + multiset(InputIterator first, InputIterator last) + : m_tree(Pred(), allocator_type()) + { m_tree.insert_equal(first, last); } + + template + 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& x) + : m_tree(x.m_tree) {} + + multiset& operator=(const multiset& 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& 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 + 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 + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + template + friend bool operator== (const multiset&, + const multiset&); + template + friend bool operator< (const multiset&, + const multiset&); +}; + +template +inline bool operator==(const multiset& x, + const multiset& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multiset& x, + const multiset& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multiset& x, + const multiset& y) +{ return !(x == y); } + +template +inline bool operator>(const multiset& x, + const multiset& y) +{ return y < x; } + +template +inline bool operator<=(const multiset& x, + const multiset& y) +{ return !(y < x); } + +template +inline bool operator>=(const multiset& x, + const multiset& y) +{ return !(x < y); } + +template +inline void swap(multiset& x, + multiset& y) +{ x.swap(y); } + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_SET_HPP */ + +// Local Variables: +// mode:C++ +// End: diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp new file mode 100644 index 0000000..a97764e --- /dev/null +++ b/include/boost/interprocess/containers/slist.hpp @@ -0,0 +1,1096 @@ +/* + * + * 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 2004-2005. 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_slist.h file. Modified by Ion Gazta�ga 2004-2005 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_SLIST_HPP +#define BOOST_INTERPROCESS_SLIST_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +#include +#include +#include +#include + +namespace boost{ namespace interprocess{ + +template +struct shmem_slist_node; + + +template +struct shmem_slist_node_base +{ + typedef typename boost::detail::allocator:: + rebind_to >::type NodeAlloc; + typedef typename NodeAlloc::pointer NodePtr; + typedef typename NodeAlloc::const_pointer NodeCPtr; + + NodePtr m_next; + + //Inserts new node after prev_node and returns new_node + static NodePtr make_link(NodePtr prev_node, NodePtr new_node) + { + new_node->m_next = prev_node->m_next; + prev_node->m_next = new_node; + return new_node; + } + + //Returns the previous node of node "node", starting from node head + static NodePtr previous(NodePtr head, NodeCPtr node) + { + while (head->m_next != node) + head = head->m_next; + return head; + } + + //Moves elements of a list (before_first, before_last] after prev_pos + //Example from two lists A and B: + // A: prev_pos -> pos + // B: before_first -> first -> c -> d-> before_last -> after + //becomes + // A: prev_pos -> first -> c -> d-> before_last -> pos + // B: before_first -> after + static void splice_after(NodePtr prev_pos, NodePtr before_first, NodePtr before_last) + { + if (prev_pos != before_first && prev_pos != before_last) { + NodePtr first = before_first->m_next; + NodePtr after = prev_pos->m_next; + before_first->m_next = before_last->m_next; + prev_pos->m_next = first; + before_last->m_next = after; + } + } + + //Inverses elements of a list defined by [head, last) + //The new final node points to last + //Returns new first node + //Example: + // first -> b -> c -> d-> last + //becomes + // d -> c -> b -> first -> last + //returns: d + static NodePtr reverse(NodePtr first, NodePtr last) + { + NodePtr result = first; + first = first->m_next; + result->m_next = last; + while(first != last) { + NodePtr next = first->m_next; + first->m_next = result; + result = first; + first = next; + } + return result; + } + + //Returns the number of nodes [first, last) + //Example: + // first -> last + //returns: 1 + static std::size_t size(NodePtr first, NodePtr last) + { + std::size_t result = 0; + for ( ; first->m_next != last; first = first->m_next) + ++result; + return result; + } +}; + +template +struct shmem_slist_node + : public shmem_slist_node_base +{ + typedef shmem_slist_node_base base_t; + typedef typename boost::detail::allocator:: + rebind_to >::type NodeAlloc; + typedef typename NodeAlloc::pointer NodePtr; + typedef typename NodeAlloc::const_pointer NodeCPtr; + typedef typename Alloc::value_type value_t; + + shmem_slist_node(const value_t & value) + : m_data(value){} + + value_t m_data; +}; + +template +struct shmem_slist_alloc + : public boost::detail::allocator:: + rebind_to >::type, + public boost::detail::allocator:: + rebind_to >:: + type::pointer >::type, + public A +{ + typedef shmem_slist_node Node; + typedef typename boost::detail::allocator:: + rebind_to >::type NodeAlloc; + typedef typename boost::detail::allocator:: + rebind_to::type PtrAlloc; + typedef A ValAlloc; + typedef typename NodeAlloc::pointer NodePtr; + typedef detail::scoped_deallocator Deallocator; + typedef detail::scoped_destructor PtrDestructor; + + enum { + node_has_trivial_destructor = + boost::has_trivial_destructor::value | + boost::has_trivial_destructor::value + }; + + shmem_slist_alloc(const ValAlloc &a) + : NodeAlloc(a), PtrAlloc(a), ValAlloc(a) + { priv_init(); } + + shmem_slist_alloc(const NodeAlloc &a) + : NodeAlloc(a), PtrAlloc(a), ValAlloc(a) + { priv_init(); } + + shmem_slist_alloc(const shmem_slist_alloc &other) + : NodeAlloc(other), PtrAlloc(other), ValAlloc(other) + { priv_init(); } + + ~shmem_slist_alloc() + { + if(!boost::has_trivial_constructor::value){ + PtrAlloc::destroy(&m_node->m_next); + } + NodeAlloc::deallocate(m_node, 1); + } + + typename NodeAlloc::size_type max_size() const + { return NodeAlloc::max_size(); } + + void priv_init() + { + m_node = NodeAlloc::allocate(1); + + if(!boost::has_trivial_constructor::value){ + scoped_ptrnode_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)); + PtrAlloc::construct(pnext, m_node); + scoped_ptrnext_destroy(pnext, *this); + next_destroy.release(); + } + node_deallocator.release(); + } + else{ + m_node->m_next = m_node; + } + } + + template + NodePtr create_node(const Convertible& x) + { + NodePtr p = NodeAlloc::allocate(1); + scoped_ptrnode_deallocator(p, *this); + + + //Make sure destructors are called before memory is freed + //if an exception is thrown + { + if(!boost::has_trivial_constructor::value){ + typedef typename PtrAlloc::pointer NodePtrPtr; + NodePtrPtr pnext(PtrAlloc::address(p->m_next)); + PtrAlloc::construct(pnext, NodePtr(0)); + scoped_ptrnext_destroy(pnext, *this); + ValAlloc::construct(ValAlloc::address(p->m_data), x); + next_destroy.release(); + } + else{ + p->m_next = 0; + 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(shmem_slist_alloc &x) + { + if (static_cast(*this) != + static_cast(x)){ + detail::do_swap(static_cast(*this), + static_cast(x)); + detail::do_swap(static_cast(*this), + static_cast(x)); + detail::do_swap(static_cast(*this), + static_cast(x)); + } + detail::do_swap(this->m_node, x.m_node); + } + + protected: + typename NodeAlloc::pointer m_node; +}; + +template +struct shmem_slist_alloc + : public boost::detail::allocator:: + rebind_to >::type +{ + typedef shmem_slist_node Node; + typedef typename boost::detail::allocator:: + rebind_to >::type NodeAlloc; + typedef typename boost::detail::allocator:: + rebind_to::type PtrAlloc; + typedef A ValAlloc; + typedef typename NodeAlloc::pointer NodePtr; + typedef detail::scoped_deallocator Deallocator; + typedef detail::scoped_destructor PtrDestructor; + + enum { + node_has_trivial_destructor = + boost::has_trivial_destructor::value | + boost::has_trivial_destructor::value + }; + + shmem_slist_alloc(const ValAlloc &a) + : NodeAlloc(a) + { priv_init(); } + + shmem_slist_alloc(const NodeAlloc &a) + : NodeAlloc(a) + { priv_init(); } + + shmem_slist_alloc(const shmem_slist_alloc &other) + : NodeAlloc(other) + { priv_init(); } + + ~shmem_slist_alloc() + { + if(!boost::has_trivial_destructor::value){ + PtrAlloc ptr_alloc(*this); + ptr_alloc.destroy(ptr_alloc.address(m_node->m_next)); + } + NodeAlloc::deallocate(m_node, 1); + } + + typename NodeAlloc::size_type max_size() const + { return NodeAlloc::max_size(); } + + template + NodePtr create_node(const Convertible& x) + { + NodePtr p = NodeAlloc::allocate(1); + scoped_ptrnode_deallocator(p, *this); + NodeAlloc::construct(p, x); + node_deallocator.release(); + p->m_next = NodePtr(0); + return (p); + } + + void destroy_node(NodePtr node) + { + if(!node_has_trivial_destructor){ + NodeAlloc::destroy(node); + } + NodeAlloc::deallocate(node, 1); + } + + void swap(shmem_slist_alloc &x) + { + NodeAlloc& this_alloc = static_cast(*this); + NodeAlloc& other_alloc = static_cast(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::value){ + typedef typename PtrAlloc::pointer NodePtrPtr; + scoped_ptrnode_deallocator(m_node, *this); + PtrAlloc ptr_alloc(*this); + NodePtrPtr pnext(ptr_alloc.address(m_node->m_next)); + + //Make sure destructors are called before memory is freed + //if an exception is thrown + { + ptr_alloc.construct(pnext, m_node); + scoped_ptrnext_destroy(pnext, ptr_alloc); + next_destroy.release(); + } + node_deallocator.release(); + } + else{ + m_node->m_next = m_node; + } + } +}; + +template +class slist + : protected shmem_slist_alloc::value> +{ + typedef shmem_slist_alloc::value> Base; + + typedef typename Base::NodePtr NodePtr; + public: + typedef Alloc allocator_type; + typedef T value_type; + typedef typename Alloc::pointer pointer; + typedef typename Alloc::const_pointer const_pointer; + typedef typename Alloc::reference reference; + typedef typename Alloc::const_reference const_reference; + typedef typename Alloc::size_type size_type; + typedef typename Alloc::difference_type difference_type; + + allocator_type get_allocator() const + { return allocator_type(*this); } + + 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; + + //list const_iterator + class const_iterator + : public boost::iterator + { + protected: + typedef typename slist::NodePtr NodePtr; + + NodePtr m_ptr; + explicit const_iterator(NodePtr ptr) : m_ptr(ptr){} + void prot_incr() { m_ptr = m_ptr->m_next; } + + public: + friend class slist; + 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); } + + //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 + { + //typedef typename const_iterator::NodePtr NodePtr; + typedef typename slist::NodePtr NodePtr; + protected: + explicit iterator(NodePtr ptr) : const_iterator(ptr){} + + public: + friend class slist; + 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); } + }; + + private: + typedef shmem_slist_node Node; + typedef typename Base::NodeAlloc NodeAlloc; + typedef typename Base::PtrAlloc PtrAlloc; + typedef typename Base::ValAlloc ValAlloc; + typedef typename NodeAlloc::const_pointer NodeCPtr; + + public: + explicit slist(const allocator_type& a = allocator_type()) : Base(a) {} + + explicit slist(size_type n, const value_type& x = value_type(), + const allocator_type& a = allocator_type()) : Base(a) + { this->insert_after_fill(this->m_node, n, x); } + + // We don't need any dispatching tricks here, because insert_after_range + // already does them. + template + slist(InpIt first, InpIt last, + const allocator_type& a = allocator_type()) + : Base(a) + { insert_after_range(this->m_node, first, last); } + + slist(const slist& x) + : Base(static_cast(x)) + { insert_after_range(this->m_node, x.begin(), x.end()); } + + slist& operator= (const slist& x) + { + if (&x != this) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + ~slist() { this->clear();} + +public: + // 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->fill_assign(n, val); } + + void fill_assign(size_type n, const T& val) + { + NodePtr prev = this->m_node; + NodePtr node = this->m_node->m_next; + for ( ; node != this->m_node && n > 0 ; --n) { + node->m_data = val; + prev = node; + node = node->m_next; + } + if (n > 0) + this->insert_after_fill(prev, n, val); + else + this->erase_after(prev, this->m_node); + } + + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->assign_dispatch(first, last, Result()); + } + + template + void assign_dispatch(Int n, Int val, boost::mpl::true_) + { this->fill_assign((size_type) n, (T) val); } + + template + void assign_dispatch(InpIt first, InpIt last, + boost::mpl::false_) + { + NodePtr prev = this->m_node; + NodePtr node = this->m_node->m_next; + while (node != this->m_node && first != last) { + node->m_data = *first; + prev = node; + node = node->m_next; + ++first; + } + if (first != last) + this->insert_after_range(prev, first, last); + else + this->erase_after(prev, this->m_node); + } + +public: + + 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); } + + // Experimental new feature: before_begin() returns a + // non-dereferenceable iterator that, when incremented, yields + // begin(). This iterator may be used as the argument to + // insert_after, erase_after, etc. + iterator before_begin() + { return iterator(this->m_node); } + + const_iterator before_begin() const + { return const_iterator(this->m_node); } + + size_type size() const + { return Node::size(this->m_node->m_next, this->m_node->m_next); } + + size_type maxsize() const + { return size_type(-1); } + + bool empty() const + { return this->m_node->m_next == this->m_node; } + + void swap(slist& x) + { Base::swap(x); } + + public: + + reference front() + { return this->m_node->m_next->m_data; } + + const_reference front() const + { return this->m_node->m_next->m_data; } + + void push_front(const value_type& x = value_type()) + { Node::make_link(this->m_node, this->create_node(x)); } + + void pop_front() + { + NodePtr node = this->m_node->m_next; + this->m_node->m_next = node->m_next; + this->destroy_node(node); + } + + iterator previous(const_iterator pos) + { return iterator( Node::previous(this->m_node, pos.m_ptr)); } + + const_iterator previous(const_iterator pos) const + { return const_iterator(Node::previous(this->m_node, pos.m_ptr)); } + + iterator insert_after(iterator prev_pos, const value_type& x = value_type()) + { return iterator(insert_after(prev_pos.m_ptr, x)); } + + void insert_after(iterator prev_pos, size_type n, const value_type& x) + { this->insert_after_fill(prev_pos.m_ptr, n, x); } + + // We don't need any dispatching tricks here, because insert_after_range + // already does them. + template + void insert_after(iterator prev_pos, InIter first, InIter last) + { this->insert_after_range(prev_pos.m_ptr, first, last); } + + iterator insert(iterator prev_pos, const value_type& x = value_type()) + { + return iterator(insert_after( + Node::previous(this->m_node, prev_pos.m_ptr), x)); + } + + void insert(iterator pos, size_type n, const value_type& x) + { + this->insert_after_fill(Node::previous(this->m_node, pos.m_ptr), n, x); + } + + // We don't need any dispatching tricks here, because insert_after_range + // already does them. + template + void insert(iterator pos, InIter first, InIter last) + { + this->insert_after_range(Node::previous(this->m_node, pos.m_ptr), + first, last); + } + + iterator erase_after(iterator prev_pos) + { return iterator(this->erase_after(prev_pos.m_ptr)); } + + iterator erase_after(iterator before_first, iterator last) + { return iterator(this->erase_after(before_first.m_ptr, last.m_ptr)); } + + iterator erase(iterator pos) + { return iterator(this->erase_after(Node::previous(this->m_node, pos.m_ptr))); } + + iterator erase(iterator first, iterator last) + { + return iterator(this->erase_after( + Node::previous(this->m_node, first.m_ptr), last.m_ptr)); + } + + void resize(size_type newsize, const T& x = T()) + { + NodePtr cur = this->m_node; + while (cur->m_next != this->m_node && newsize > 0) { + --newsize; + cur = cur->m_next; + } + if (cur->m_next != this->m_node) + this->erase_after(cur, this->m_node); + else + this->insert_after_fill(cur, newsize, x); + } + + void clear() + { this->erase_after(this->m_node, this->m_node); } + +public: + // Removes all of the elements from the list x to *this, inserting + // them immediately after pos. x must not be *this. Complexity: + // linear in x.size(). + void splice_after(iterator prev_pos, slist& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + if (!x.empty()){ + Node::splice_after(prev_pos.m_ptr, x.m_node, + Node::previous(x.m_node, x.m_node)); + } + } + else{ + this->insert_after(prev_pos, x.begin(), x.end()); + x.clear(); + } + } + + // Moves the element that follows prev to *this, inserting it immediately + // after pos. This is constant time. + void splice_after(iterator prev_pos, slist& x, iterator prev) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + Node::splice_after(prev_pos.m_ptr, prev.m_ptr, prev.m_ptr->m_next); + } + else{ + this->insert_after(prev_pos, *prev); + x.erase_after(prev); + } + } + + // Moves the range [before_first + 1, before_last + 1) to *this, + // inserting it immediately after pos. This is constant time. + void splice_after(iterator prev_pos, slist& x, + iterator before_first, iterator before_last) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + if (before_first != before_last){ + Node::splice_after(prev_pos.m_ptr, + before_first.m_ptr, before_last.m_ptr); + } + } + else{ + this->insert_after(prev_pos, x.begin(), x.end()); + x.erase_after(before_first, before_last); + } + } + + // Linear in distance(begin(), pos), and linear in x.size(). + void splice(iterator pos, slist& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + if (!x.empty()){ + Node::splice_after + ( + Node::previous(this->m_node, pos.m_ptr), + x.m_node, + Node::previous(x.m_node, x.m_node) + ); + } + } + else{ + insert(pos, x.begin(), x.end()); + x.clear(); + } + } + + // Linear in distance(begin(), pos), and in distance(x.begin(), i). + void splice(iterator pos, slist& x, iterator i) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + iterator j = i; + ++j; + if (pos == i || pos == j) return; + Node::splice_after + ( + Node::previous(this->m_node, pos.m_ptr), + Node::previous(x.m_node, i.m_ptr), + i.m_ptr + ); + } + else{ + insert(pos, *i); + x.erase(i); + } + } + + // Linear in distance(begin(), pos), in distance(x.begin(), first), + // and in distance(first, last). + void splice(iterator pos, slist& x, iterator first, iterator last) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + if (first != last){ + Node::splice_after + ( + Node::previous(this->m_node, pos.m_ptr), + Node::previous(x.m_node, first.m_ptr), + Node::previous(first.m_ptr, last.m_ptr) + ); + } + } + else{ + insert(pos, x.begin(), x.end()); + x.erase(first, last); + } + } + + void reverse() + { + if (this->m_node->m_next != this->m_node) + this->m_node->m_next = Node::reverse(this->m_node->m_next, + this->m_node->m_next); + } + + void remove(const T& value) + { this->remove_if(value_equal_to_this(value)); } + + template + void remove_if(Pred pred) + { + NodePtr cur = this->m_node; + while (cur->m_next != this->m_node) { + if (pred(cur->m_next->m_data)) + this->erase_after(cur); + else + cur = cur->m_next; + } + } + + void unique() + { this->unique(value_equal()); } + + template + void unique(Pred pred) + { + NodePtr cur = this->m_node->m_next; + if (cur != this->m_node) { + while (cur->m_next != this->m_node) { + if (pred(cur->m_data, cur->m_next->m_data)) + this->erase_after(cur); + else + cur = cur->m_next; + } + } + } + + void merge(slist& x) + { this->merge(x, value_less()); } + + template + void merge(slist& x, StrictWeakOrdering comp) + { + NodePtr n1 = this->m_node; + while ((n1->m_next != this->m_node) && !x.empty()) { + if (comp(x.m_node->m_next->m_data, n1->m_next->m_data)){ + this->splice_after(iterator(n1), x, x.before_begin(), x.begin()); + } + n1 = n1->m_next; + } + + if (!x.empty()) { + this->splice_after(iterator(n1), x); + } + } + + void sort() + { this->sort(value_less()); } + + template + void sort(StrictWeakOrdering comp) + { + //Check if not empty or just 1 element + if (!this->empty() && + this->m_node->m_next->m_next != this->m_node) { + const allocator_type &alloc = static_cast(*this); + slist carry(alloc); + vector counter(64, carry); + int fill = 0; + while (!empty()) { + this->splice_after(iterator(carry.m_node), *this, + iterator(this->m_node), + iterator(this->m_node->m_next)); + int i = 0; + while (i < fill && !counter[i].empty()) { + counter[i].merge(carry, comp); + carry.swap(counter[i]); + ++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: + NodePtr erase_after(NodePtr prev_pos) + { + NodePtr toerase = prev_pos->m_next; + NodePtr toerase_next = toerase->m_next; + prev_pos->m_next = toerase_next; + this->destroy_node(toerase); + return toerase_next; + } + + NodePtr erase_after(NodePtr before_first, + NodePtr last_node) + { + NodePtr cur = before_first->m_next; + while (cur != last_node) { + NodePtr tmp = cur; + cur = cur->m_next; + this->destroy_node(tmp); + } + before_first->m_next = last_node; + return last_node; + } + + NodePtr insert_after(NodePtr prev_pos, const value_type& x = value_type()) + { + return Node::make_link(prev_pos, this->create_node(x)); + } + + void insert_after_fill(NodePtr prev_pos, size_type n, const value_type& x) + { + for (size_type i = 0; i < n; ++i) + prev_pos = Node::make_link(prev_pos, this->create_node(x)); + } + + // Check whether it's an integral type. If so, it's not an iterator. + template + void insert_after_range(NodePtr prev_pos, InIter first, InIter last) + { + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->insert_after_range(prev_pos, first, last, Result()); + } + + template + void insert_after_range(NodePtr prev_pos, Int n, Int x, boost::mpl::true_) + { this->insert_after_fill(prev_pos, n, x); } + + template + void insert_after_range(NodePtr prev_pos, InIter first, InIter last, boost::mpl::false_) + { + while (first != last) { + prev_pos = Node::make_link(prev_pos, this->create_node(*first)); + ++first; + } + } + + //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; } + }; + + struct value_equal_to_this + { + explicit value_equal_to_this(const value_type &ref) + : m_ref(ref){} + + bool operator()(const value_type &val) const + { return m_ref == val; } + + const value_type &m_ref; + }; +}; + +template +inline bool +operator==(const slist& sL1, const slist& sL2) +{ + typedef typename slist::const_iterator const_iterator; + const_iterator end1 = sL1.end(); + const_iterator end2 = sL2.end(); + + const_iterator i1 = sL1.begin(); + const_iterator i2 = sL2.begin(); + while (i1 != end1 && i2 != end2 && *i1 == *i2) { + ++i1; + ++i2; + } + return i1 == end1 && i2 == end2; +} + + +template +inline bool +operator<(const slist& sL1, const slist& sL2) +{ + return lexicographical_compare(sL1.begin(), sL1.end(), + sL2.begin(), sL2.end()); +} + +template +inline bool +operator!=(const slist& sL1, const slist& sL2) + { return !(sL1 == sL2); } + +template +inline bool +operator>(const slist& sL1, const slist& sL2) + { return sL2 < sL1; } + +template +inline bool +operator<=(const slist& sL1, const slist& sL2) + { return !(sL2 < sL1); } + +template +inline bool +operator>=(const slist& sL1, const slist& sL2) + { return !(sL1 < sL2); } + +template +inline void swap(slist& x, slist& y) + { x.swap(y); } + +}} //namespace boost{ namespace interprocess{ + +// Specialization of insert_iterator so that insertions will be constant +// time rather than linear time. + +//iG +//Ummm, I don't like to define things in namespace std, but +//there is no other way +namespace std { + +template +class insert_iterator > +{ + protected: + typedef boost::interprocess::slist Container; + Container* container; + typename Container::iterator iter; + public: + typedef Container container_type; + typedef output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + insert_iterator(Container& x, + typename Container::iterator i, + bool is_previous = false) + : container(&x), iter(is_previous ? i : x.previous(i)) { } + + insert_iterator& + operator=(const typename Container::value_type& value) + { + iter = container->insert_after(iter, value); + return *this; + } + insert_iterator& operator*() { return *this; } + insert_iterator& operator++() { return *this; } + insert_iterator& operator++(int) { return *this; } +}; + +} //namespace std; + + + +#include + +#endif /* BOOST_INTERPROCESS_SLIST_HPP */ diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp new file mode 100644 index 0000000..c4e2b8f --- /dev/null +++ b/include/boost/interprocess/containers/string.hpp @@ -0,0 +1,1793 @@ +/* + * Copyright (c) 1997-1999 + * 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 string file. Modified by Ion Gaztañaga 2004-2006 +// Renaming, isolating and porting to generic algorithms. Pointer typedef +// set to allocator::pointer to allow placing it in shared memory. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_STRING_HPP +#define BOOST_INTERPROCESS_STRING_HPP + +#include +#include + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +// Standard C++ string class. This class has performance +// characteristics very much like vector<>, meaning, for example, that +// it does not perform reference-count or copy-on-write, and that +// concatenation of two strings is an O(N) operation. + +// There are three reasons why basic_string is not identical to +// vector. First, basic_string always stores a null character at the +// end; this makes it possible for c_str to be a fast operation. +// Second, the C++ standard requires basic_string to copy elements +// using char_traits<>::assign, char_traits<>::copy, and +// char_traits<>::move. This means that all of vector<>'s low-level +// operations must be rewritten. Third, basic_string<> has a lot of +// extra functions in its interface that are convenient but, strictly +// speaking, redundant. + +namespace boost { namespace interprocess { + +// ------------------------------------------------------------ +// Class basic_string_base. + +// basic_string_base is a helper class that makes it it easier to write +// an exception-safe version of basic_string. The constructor allocates, +// but does not initialize, a block of memory. The destructor +// deallocates, but does not destroy elements within, a block of +// memory. The destructor assumes that this->m_start either is the internal buffer, +// or else points to a block of memory that was allocated using _String_base's +// allocator and whose size is this->m_storage. +template +class basic_string_base : private A +{ + public: + typedef A allocator_type; + typedef typename A::pointer pointer; + typedef typename A::value_type value_type; + typedef typename A::size_type size_type; + + allocator_type get_allocator() const { return *this; } + + basic_string_base(const allocator_type& a) + : allocator_type(a), + m_start(0), + m_length(0), + m_storage(0) + {} + + basic_string_base(const allocator_type& a, std::size_t n) + : allocator_type(a), + m_start(0), + m_length(0), + m_storage(0) + { if(n) this->allocate_block(n); } + + ~basic_string_base() + { this->deallocate_block(); } + + protected: + enum { InternalBufferSize = 16 }; + enum { MinAllocation = InternalBufferSize*2 }; + + typedef boost::integral_constant allocator_v1; + typedef boost::integral_constant allocator_v2; + typedef boost::integral_constant::value> alloc_version; + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + if (limit_size > InternalBufferSize) + return this->allocation_command + (command, limit_size, preferred_size, received_size, reuse, alloc_version()); + received_size = InternalBufferSize; + return std::pair(m_buf_holder.m_buf + ,reuse == pointer(m_buf_holder.m_buf)); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + if(!(command & allocate_new)) + return std::pair(0, 0); + received_size = preferred_size; + return std::make_pair(A::allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v2) + { + return A::allocation_command(command, limit_size, preferred_size, + received_size, reuse); + } + + size_type next_capacity(size_type additional_objects) const + { return get_next_capacity(A::max_size(), this->m_storage, additional_objects); } + + void deallocate(pointer p, std::size_t n) + { + if (p && (n > InternalBufferSize)) + allocator_type::deallocate(p, n); + } + + void construct(pointer p, const value_type &value = value_type()) + { allocator_type::construct(p, value); } + + void destroy(pointer p, size_type n) + { for(; n--; ++p) allocator_type::destroy(p); } + + void destroy(pointer p) + { allocator_type::destroy(p); } + + void allocate_block(std::size_t n) + { + if (n <= this->max_size()) { + size_type new_cap = this->next_capacity(n); + m_start = this->allocation_command(allocate_new, n, new_cap, new_cap).first; + this->m_length = 0; + m_storage = new_cap; + } + else + throw_length_error(); + } + + void deallocate_block() + { this->deallocate(m_start, m_storage); } + + std::size_t max_size() const + { return A::max_size() - 1; } + + // Helper functions for exception handling. + void throw_length_error() const + { throw(std::length_error("basic_string")); } + + void throw_out_of_range() const + { throw(std::out_of_range("basic_string")); } + + A & get_alloc() + { return *this; } + + const A & get_alloc() const + { return *this; } + + private: + union Buffer + { + value_type m_buf[InternalBufferSize]; + value_type dummy; + } m_buf_holder; + + protected: + pointer m_start; + size_type m_length; // current length of string + size_type m_storage; // current storage reserved for string + + void swap(basic_string_base& other) + { + detail::do_swap(this->m_start, other.m_start); + detail::do_swap(this->m_buf_holder, other.m_buf_holder); + value_type *this_buf = detail::get_pointer(this->m_start); + value_type *other_buf = detail::get_pointer(other.m_start); + + if(this_buf == other.m_buf_holder.m_buf){ + this->m_start = this->m_buf_holder.m_buf; + } + + if(other_buf == this->m_buf_holder.m_buf){ + other.m_start = other.m_buf_holder.m_buf; + } + + detail::do_swap(this->m_length, other.m_length); + detail::do_swap(this->m_storage, other.m_storage); + + allocator_type & this_al = this->get_alloc(), &other_al = other.get_alloc(); + if(this_al != other_al){ + detail::do_swap(this_al, other_al); + } + } +}; + +// ------------------------------------------------------------ +// Class basic_string. + +// Class invariants: +// (1) [start, finish) is a valid range. +// (2) Each iterator in [start, finish) points to a valid object +// of type value_type. +// (3) *finish is a valid object of type value_type; in particular, +// it is value_type(). +// (4) [finish + 1, end_of_storage) is a valid range. +// (5) Each iterator in [finish + 1, end_of_storage) points to +// uninitialized memory. + +// Note one important consequence: a string of length n must manage +// a block of memory whose size is at least n + 1. + + +template +class basic_string : private basic_string_base +{ + private: + typedef basic_string_base base_t; + enum { InternalBufferSize = base_t::InternalBufferSize }; + + protected: + // A helper class to use a char_traits as a function object. + + template + struct Eq_traits + : public std::binary_function + { + bool operator()(const typename Tr::char_type& x, + const typename Tr::char_type& y) const + { return Tr::eq(x, y); } + }; + + template + struct Not_within_traits + : public std::unary_function + { + typedef const typename Tr::char_type* Pointer; + const Pointer m_first; + const Pointer m_last; + + Not_within_traits(Pointer f, Pointer l) + : m_first(f), m_last(l) {} + + bool operator()(const typename Tr::char_type& x) const + { + return std::find_if(m_first, m_last, + std::bind1st(Eq_traits(), x)) == m_last; + } + }; + + public: + typedef A allocator_type; + typedef CharT value_type; + typedef Traits traits_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 const_pointer const_iterator; + typedef pointer iterator; + typedef boost::reverse_iterator reverse_iterator; + typedef boost::reverse_iterator const_reverse_iterator; + static const size_type npos; + + private: + typedef constant_iterator cvalue_iterator; + + public: // Constructor, destructor, assignment. + allocator_type get_allocator() const + { return base_t::get_allocator(); } + + explicit basic_string(const allocator_type& a = allocator_type()) + : base_t(a, InternalBufferSize) + { this->priv_terminate_string(); } + + struct reserve_t {}; + + basic_string(reserve_t, std::size_t n, + const allocator_type& a = allocator_type()) + : base_t(a, n + 1) + { this->priv_terminate_string(); } + + basic_string(const basic_string& s) + : base_t(s.get_allocator()) + { this->priv_range_initialize(s.begin(), s.end()); } + + basic_string(const basic_string& s, size_type pos, size_type n = npos, + const allocator_type& a = allocator_type()) + : base_t(a) + { + if (pos > s.size()) + this->throw_out_of_range(); + else + this->priv_range_initialize + (s.begin() + pos, s.begin() + pos + std::min(n, s.size() - pos)); + } + + basic_string(const CharT* s, size_type n, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + n); } + + basic_string(const CharT* s, + const allocator_type& a = allocator_type()) + : base_t(a) + { this->priv_range_initialize(s, s + Traits::length(s)); } + + basic_string(size_type n, CharT c, + const allocator_type& a = allocator_type()) + : base_t(a) + { + this->priv_range_initialize(cvalue_iterator(c, n), + cvalue_iterator()); + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string(InputIterator f, InputIterator l, + const allocator_type& a = allocator_type()) + : base_t(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_initialize_dispatch(f, l, Result()); + } + + ~basic_string() + { this->destroy(this->m_start, this->m_length + 1); } + + basic_string& operator=(const basic_string& s) + { + if (&s != this) + this->assign(s.begin(), s.end()); + return *this; + } + + basic_string& operator=(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + basic_string& operator=(CharT c) + { return this->assign(static_cast(1), c); } + + private: // Helper functions used by constructors + // and elsewhere. + void priv_construct_null(pointer p) + { this->construct(p, 0); } + + static CharT priv_null() + { return (CharT) 0; } + + private: + // Helper functions used by constructors. It is a severe error for + // any of them to be called anywhere except from within constructors. + void priv_terminate_string() + { + BOOST_TRY{ + this->priv_construct_null(this->m_start + this->m_length); + } + BOOST_CATCH(...){ + this->destroy(this->m_start, this->m_length); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(InputIter f, InputIter l, + std::input_iterator_tag) + { + this->allocate_block(InternalBufferSize); + this->priv_construct_null(this->m_start + this->m_length); + BOOST_TRY{ + this->append(f, l); + } + BOOST_CATCH(...){ + this->destroy(this->m_start, this->m_length + 1); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + this->allocate_block(std::max(n+1, InternalBufferSize)); + priv_uninitialized_copy(f, l, this->m_start, this->get_alloc()); + this->m_length = n; + this->priv_terminate_string(); + } + + template + void priv_range_initialize(InputIter f, InputIter l) + { + typedef typename std::iterator_traits::iterator_category Category; + this->priv_range_initialize(f, l, Category()); + } + + template + void priv_initialize_dispatch(Integer n, Integer x, boost::mpl::true_) + { + this->allocate_block(std::max(n+1, InternalBufferSize)); + priv_uninitialized_fill_n(this->m_start, n, x, this->get_alloc()); + this->m_length = n; + this->priv_terminate_string(); + } + + template + void priv_initialize_dispatch(InputIter f, InputIter l, boost::mpl::false_) + { this->priv_range_initialize(f, l); } + + public: // Iterators. + iterator begin() { return this->m_start; } + iterator end() { return this->m_start + this->m_length; } + const_iterator begin() const { return this->m_start; } + const_iterator end() const { return this->m_start + this->m_length; } + + reverse_iterator rbegin() + { return reverse_iterator(this->m_start + this->m_length); } + reverse_iterator rend() + { return reverse_iterator(this->m_start); } + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->m_start + this->m_length); } + const_reverse_iterator rend() const + { return const_reverse_iterator(this->m_start); } + + public: // Size, capacity, etc. + size_type size() const { return this->m_length; } + size_type length() const { return this->size(); } + + size_type max_size() const { return base_t::max_size(); } + + void resize(size_type n, CharT c) + { + if (n <= size()) + this->erase(this->begin() + n, this->end()); + else + this->append(n - this->size(), c); + } + + void resize(size_type n) { resize(n, this->priv_null()); } + + // Change the string's capacity so that it is large enough to hold + // at least priv_res_arg elements, plus the terminating null. + void reserve(size_type res_arg) + { + if (res_arg > this->max_size()) + this->throw_length_error(); + + if (this->capacity() < res_arg){ + size_type n = std::max(res_arg, this->size()) + 1; + size_type new_cap = this->next_capacity(n); + pointer new_start = this->allocation_command + (allocate_new, n, new_cap, new_cap).first; + size_type new_length = 0; + + BOOST_TRY{ + new_length += priv_uninitialized_copy + (this->m_start, this->m_start + this->m_length, new_start, this->get_alloc()); + this->priv_construct_null(new_start + new_length); + } + BOOST_CATCH(...){ + this->destroy(new_start, new_length); + this->deallocate(new_start, new_cap); + BOOST_RETHROW + } + BOOST_CATCH_END + + this->destroy(this->m_start, this->m_length + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_length = new_length; + this->m_storage = new_cap; + } + } + + size_type capacity() const + { return this->m_storage - 1; } + + void clear() + { + if (!empty()) { + Traits::assign(*this->m_start, this->priv_null()); + this->destroy(this->m_start+1, this->m_length); + this->m_length = 0; + } + } + + bool empty() const { return !this->m_length; } + + public: // Element access. + + const_reference operator[](size_type n) const + { return *(this->m_start + n); } + reference operator[](size_type n) + { return *(this->m_start + n); } + + const_reference at(size_type n) const { + if (n >= size()) + this->throw_out_of_range(); + return *(this->m_start + n); + } + + reference at(size_type n) { + if (n >= size()) + this->throw_out_of_range(); + return *(this->m_start + n); + } + + public: // Append, operator+=, push_back. + + basic_string& operator+=(const basic_string& s) + { return this->append(s); } + + basic_string& operator+=(const CharT* s) + { return this->append(s); } + + basic_string& operator+=(CharT c) + { this->push_back(c); return *this; } + + basic_string& append(const basic_string& s) + { return this->append(s.begin(), s.end()); } + + basic_string& append(const basic_string& s, size_type pos, size_type n) + { + if (pos > s.size()) + this->throw_out_of_range(); + return this->append(s.begin() + pos, + s.begin() + pos + std::min(n, s.size() - pos)); + } + + basic_string& append(const CharT* s, size_type n) + { return this->append(s, s + n); } + + basic_string& append(const CharT* s) + { return this->append(s, s + Traits::length(s)); } + + basic_string& append(size_type n, CharT c) + { return this->append(cvalue_iterator(c, n), cvalue_iterator()); } + + template + basic_string& append(InputIter first, InputIter last) + { this->insert(this->end(), first, last); return *this; } + + void push_back(CharT c) + { + if ((this->m_length + 1) < this->m_storage){ + this->priv_construct_null(this->m_start + (this->m_length + 1)); + Traits::assign(this->m_start[this->m_length], c); + ++this->m_length; + } + else{ + //No enough memory, insert a new object at the end + this->append((size_type)1, c); + } + } + + void pop_back() + { + Traits::assign(this->m_start[this->m_length-1], this->priv_null()); + this->destroy(this->m_start + this->m_length); + --this->m_length; + } + + private: // Helper functions for append. + + template inline + void priv_uninitialized_fill_n(FwdIt first, Count count, + const CharT 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 inline + size_type priv_uninitialized_copy(InpIt first, InpIt last, + FwdIt dest, Alloc& al) + { + //Save initial destination position + FwdIt dest_init = dest; + size_type constructed = 0; + + BOOST_TRY{ + //Try to build objects + for (; first != last; ++dest, ++first, ++constructed){ + al.construct(dest, *first); + } + } + BOOST_CATCH(...){ + //Call destructors + for (; constructed--; ++dest_init){ + al.destroy(dest_init); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return (constructed); + } + + public: // Assign + + basic_string& assign(const basic_string& s) + { return this->assign(s.begin(), s.end()); } + + basic_string& assign(const basic_string& s, + size_type pos, size_type n) { + if (pos > s.size()) + this->throw_out_of_range(); + return this->assign(s.begin() + pos, + s.begin() + pos + std::min(n, s.size() - pos)); + } + + basic_string& assign(const CharT* s, size_type n) + { return this->assign(s, s + n); } + + basic_string& assign(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + basic_string& assign(size_type n, CharT c) + { return this->assign(cvalue_iterator(c, n), cvalue_iterator()); } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string& assign(InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + return this->priv_assign_dispatch(first, last, Result()); + } + + basic_string& assign(const CharT* f, const CharT* l) + { + const std::ptrdiff_t n = l - f; + if (static_cast(n) <= size()) { + Traits::copy(detail::get_pointer(this->m_start), f, n); + this->erase(this->m_start + n, this->m_start + this->m_length); + } + else { + Traits::copy(detail::get_pointer(this->m_start), f, size()); + this->append(f + size(), l); + } + return *this; + } + + private: // Helper functions for assign. + + template + basic_string& priv_assign_dispatch(Integer n, Integer x, boost::mpl::true_) + { return this->assign((size_type) n, (CharT) x); } + + template + basic_string& priv_assign_dispatch(InputIter f, InputIter l, + boost::mpl::false_) + { + size_type cur = 0; + CharT *ptr = detail::get_pointer(this->m_start); + while (f != l && cur != this->m_length) { + Traits::assign(*ptr, *f); + ++f; + ++cur; + ++ptr; + } + if (f == l) + this->erase(this->m_start + cur, this->m_start + this->m_length); + else + this->append(f, l); + return *this; + } + + public: // Insert + + basic_string& insert(size_type pos, const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - s.size()) + this->throw_length_error(); + this->insert(this->m_start + pos, s.begin(), s.end()); + return *this; + } + + basic_string& insert(size_type pos, const basic_string& s, + size_type beg, size_type n) + { + if (pos > this->size() || beg > s.size()) + this->throw_out_of_range(); + size_type len = std::min(n, s.size() - beg); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + const CharT *beg_ptr = detail::get_pointer(s.begin()) + beg; + const CharT *end_ptr = beg_ptr + len; + this->insert(this->m_start + pos, beg_ptr, end_ptr); + return *this; + } + + basic_string& insert(size_type pos, const CharT* s, size_type n) + { + if (pos > this->size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - n) + this->throw_length_error(); + this->insert(this->m_start + pos, s, s + n); + return *this; + } + + basic_string& insert(size_type pos, const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + size_type len = Traits::length(s); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + this->insert(this->m_start + pos, s, s + len); + return *this; + } + + basic_string& insert(size_type pos, size_type n, CharT c) + { + if (pos > this->size()) + this->throw_out_of_range(); + if (this->size() > this->max_size() - n) + this->throw_length_error(); + this->insert(this->m_start + pos, n, c); + return *this; + } + + iterator insert(iterator position, CharT c) + { + size_type new_offset = position - this->m_start + 1; + this->insert(position, cvalue_iterator(c, 1), + cvalue_iterator()); + return this->m_start + new_offset; + } + + void insert(iterator position, std::size_t n, CharT c) + { + this->insert(position, cvalue_iterator(c, n), + cvalue_iterator()); + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + void insert(iterator p, InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + private: // Helper functions for insert. + + template + void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) + { + for ( ; first != last; ++first, ++p) { + p = this->insert(p, *first); + } + } + + template + void priv_insert(iterator position, ForwardIter first, + ForwardIter last, std::forward_iterator_tag) + { + if (first != last) { + size_type n = std::distance(first, last); + size_type remaining = this->m_storage - this->m_length - 1; + if (remaining >= n){ + const size_type elems_after = + this->m_length - (position - this->m_start); + size_type old_length = this->m_length; + if (elems_after >= n) { + pointer pointer_past_last = this->m_start + this->m_length + 1; + priv_uninitialized_copy(this->m_start + (this->m_length - n + 1), + pointer_past_last, + pointer_past_last, *this); + this->m_length += n; + Traits::move(detail::get_pointer(position + n), + detail::get_pointer(position), + (elems_after - n) + 1); + this->priv_copy(first, last, position); + } + else { + ForwardIter mid = first; + std::advance(mid, elems_after + 1); + priv_uninitialized_copy(mid, last, this->m_start + this->m_length + 1, *this); + this->m_length += n - elems_after; + BOOST_TRY{ + priv_uninitialized_copy + (position, this->m_start + old_length + 1, + this->m_start + this->m_length, *this); + this->m_length += elems_after; + } + BOOST_CATCH(...){ + this->destroy(this->m_start + (old_length + 1), this->m_length - (old_length + 1)); + this->m_length = old_length; + BOOST_RETHROW + } + BOOST_CATCH_END + this->priv_copy(first, mid, position); + } + } + else { + const size_type old_size = this->size(); + size_type new_cap = this->next_capacity(n); + pointer new_start = + this->allocation_command + (allocate_new, old_size + n + 1, new_cap, new_cap).first; + size_type new_length = 0; + BOOST_TRY{ + new_length += priv_uninitialized_copy + (this->m_start, position, new_start, *this); + new_length += priv_uninitialized_copy + (first, last, new_start + new_length, *this); + new_length += priv_uninitialized_copy + (position, this->m_start + this->m_length, + new_start + new_length, *this); + this->priv_construct_null(new_start + new_length); + } + BOOST_CATCH(...){ + this->destroy(new_start, new_length); + this->deallocate(new_start, new_cap); + BOOST_RETHROW + } + BOOST_CATCH_END + this->destroy(this->m_start, this->m_length + 1); + this->deallocate_block(); + this->m_start = new_start; + this->m_length = new_length; + this->m_storage = new_cap; + } + } + } + + template + void priv_insert_dispatch(iterator p, Integer n, Integer x, + boost::mpl::true_) + { insert(p, (size_type) n, (CharT) x); } + + template + void priv_insert_dispatch(iterator p, InputIter first, InputIter last, + boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + priv_insert(p, first, last, Category()); + } + + template + void priv_copy(InputIterator first, InputIterator last, iterator result) + { + for ( ; first != last; ++first, ++result) + Traits::assign(*result, *first); + } + + void priv_copy(const CharT* first, const CharT* last, CharT* result) + { Traits::copy(result, first, last - first); } + + public: // Erase. + + basic_string& erase(size_type pos = 0, size_type n = npos) + { + if (pos > size()) + this->throw_out_of_range(); + erase(this->m_start + pos, this->m_start + pos + std::min(n, size() - pos)); + return *this; + } + + iterator erase(iterator position) + { + // The move includes the terminating null. + Traits::move(detail::get_pointer(position), + detail::get_pointer(position + 1), + this->m_length - (position - this->m_start)); + this->destroy(this->m_start + this->m_length); + --this->m_length; + return position; + } + + iterator erase(iterator first, iterator last) + { + if (first != last) { // The move includes the terminating null. + size_type num_erased = last - first; + Traits::move(detail::get_pointer(first), + detail::get_pointer(last), + (this->m_length + 1)-(last - this->m_start)); + size_type new_length = this->m_length - num_erased; + this->destroy(this->m_start + new_length + 1, num_erased); + this->m_length = new_length; + } + return first; + } + + public: // Replace. (Conceptually equivalent + // to erase followed by insert.) + basic_string& replace(size_type pos, size_type n, + const basic_string& s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n, size() - pos); + if (this->size() - len >= this->max_size() - s.size()) + this->throw_length_error(); + return this->replace(this->m_start + pos, this->m_start + pos + len, + s.begin(), s.end()); + } + + basic_string& replace(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) + { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + const size_type len1 = std::min(n1, size() - pos1); + const size_type len2 = std::min(n2, s.size() - pos2); + if (this->size() - len1 >= this->max_size() - len2) + this->throw_length_error(); + return this->replace(this->m_start + pos1, this->m_start + pos1 + len1, + s.m_start + pos2, s.m_start + pos2 + len2); + } + + basic_string& replace(size_type pos, size_type n1, + const CharT* s, size_type n2) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->m_start + pos, this->m_start + pos + len, + s, s + n2); + } + + basic_string& replace(size_type pos, size_type n1, + const CharT* s) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n1, size() - pos); + const size_type n2 = Traits::length(s); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->m_start + pos, this->m_start + pos + len, + s, s + Traits::length(s)); + } + + basic_string& replace(size_type pos, size_type n1, + size_type n2, CharT c) + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n1, size() - pos); + if (n2 > this->max_size() || size() - len >= this->max_size() - n2) + this->throw_length_error(); + return this->replace(this->m_start + pos, this->m_start + pos + len, n2, c); + } + + basic_string& replace(iterator first, iterator last, + const basic_string& s) + { return this->replace(first, last, s.begin(), s.end()); } + + basic_string& replace(iterator first, iterator last, + const CharT* s, size_type n) + { return this->replace(first, last, s, s + n); } + + basic_string& replace(iterator first, iterator last, + const CharT* s) + { return this->replace(first, last, s, s + Traits::length(s)); } + + basic_string& replace(iterator first, iterator last, + size_type n, CharT c) + { + const size_type len = static_cast(last - first); + if (len >= n) { + Traits::assign(detail::get_pointer(first), n, c); + erase(first + n, last); + } + else { + Traits::assign(detail::get_pointer(first), len, c); + insert(last, n - len, c); + } + return *this; + } + + // Check to see if InputIterator is an integer type. If so, then + // it can't be an iterator. + template + basic_string& replace(iterator first, iterator last, + InputIter f, InputIter l) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + return this->priv_replace_dispatch(first, last, f, l, Result()); + } + + private: // Helper functions for replace. + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + Integer n, Integer x, + boost::mpl::true_) + { return this->replace(first, last, (size_type) n, (CharT) x); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + InputIter f, InputIter l, + boost::mpl::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + return this->priv_replace(first, last, f, l, Category()); + } + + + template + basic_string& priv_replace(iterator first, iterator last, + InputIter f, InputIter l, std::input_iterator_tag) + { + for ( ; first != last && f != l; ++first, ++f) + Traits::assign(*first, *f); + + if (f == l) + this->erase(first, last); + else + this->insert(last, f, l); + return *this; + } + + template + basic_string& priv_replace(iterator first, iterator last, + ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + const difference_type len = last - first; + if (len >= n) { + this->priv_copy(f, l, first); + this->erase(first + n, last); + } + else { + ForwardIter m = f; + std::advance(m, len); + this->priv_copy(f, m, first); + this->insert(last, m, l); + } + return *this; + } + + public: // Other modifier member functions. + + size_type copy(CharT* s, size_type n, size_type pos = 0) const + { + if (pos > size()) + this->throw_out_of_range(); + const size_type len = std::min(n, size() - pos); + Traits::copy(s, detail::get_pointer(this->m_start + pos), len); + return len; + } + + void swap(basic_string& s) + { base_t::swap(s); } + + public: // Conversion to C string. + + const CharT* c_str() const + { return detail::get_pointer(this->m_start); } + + const CharT* data() const + { return detail::get_pointer(this->m_start); } + + public: // find. + + size_type find(const basic_string& s, size_type pos = 0) const + { return find(s.c_str(), pos, s.size()); } + + size_type find(const CharT* s, size_type pos = 0) const + { return find(s, pos, Traits::length(s)); } + + size_type find(const CharT* s, size_type pos, size_type n) const + { + if (pos + n > size()) + return npos; + else { + pointer finish = this->m_start + this->m_length; + const const_iterator result = + std::search(detail::get_pointer(this->m_start + pos), + detail::get_pointer(finish), + s, s + n, Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + size_type find(CharT c, size_type pos = 0) const + { + if (pos >= size()) + return npos; + else { + pointer finish = this->m_start + this->m_length; + const const_iterator result = + std::find_if(this->m_start + pos, finish, + std::bind2nd(Eq_traits(), c)); + return result != finish ? result - begin() : npos; + } + } + + public: // rfind. + + size_type rfind(const basic_string& s, size_type pos = npos) const + { return rfind(s.c_str(), pos, s.size()); } + + size_type rfind(const CharT* s, size_type pos = npos) const + { return rfind(s, pos, Traits::length(s)); } + + size_type rfind(const CharT* s, size_type pos, size_type n) const + { + const std::size_t len = size(); + + if (n > len) + return npos; + else if (n == 0) + return std::min(len, pos); + else { + const const_iterator last = begin() + std::min(len - n, pos) + n; + const const_iterator result = find_end(begin(), last, + s, s + n, + Eq_traits()); + return result != last ? result - begin() : npos; + } + } + + size_type rfind(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + std::min(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::bind2nd(Eq_traits(), c)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + public: // find_first_of + + size_type find_first_of(const basic_string& s, size_type pos = 0) const + { return find_first_of(s.c_str(), pos, s.size()); } + + size_type find_first_of(const CharT* s, size_type pos = 0) const + { return find_first_of(s, pos, Traits::length(s)); } + + size_type find_first_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos >= size()) + return npos; + else { + pointer finish = this->m_start + this->m_length; + const_iterator result = std::find_first_of(this->m_start + pos, finish, + s, s + n, + Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + size_type find_first_of(CharT c, size_type pos = 0) const + { return find(c, pos); } + + public: // find_last_of + + size_type find_last_of(const basic_string& s, + size_type pos = npos) const + { return find_last_of(s.c_str(), pos, s.size()); } + + size_type find_last_of(const CharT* s, size_type pos = npos) const + { return find_last_of(s, pos, Traits::length(s)); } + + size_type find_last_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = this->m_start + std::min(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_first_of(const_reverse_iterator(last), rend(), + s, s + n, + Eq_traits()); + return rresult != rend() ? (rresult.base() - 1) - this->m_start : npos; + } + } + + size_type find_last_of(CharT c, size_type pos = npos) const + { return rfind(c, pos); } + + public: // find_first_not_of + + size_type find_first_not_of(const basic_string& s, + size_type pos = 0) const + { return find_first_not_of(s.c_str(), pos, s.size()); } + + size_type find_first_not_of(const CharT* s, size_type pos = 0) const + { return find_first_not_of(s, pos, Traits::length(s)); } + + size_type find_first_not_of(const CharT* s, size_type pos, + size_type n) const + { + if (pos > size()) + return npos; + else { + pointer finish = this->m_start + this->m_length; + const_iterator result = std::find_if(this->m_start + pos, finish, + Not_within_traits(s, s + n)); + return result != finish ? result - this->m_start : npos; + } + } + + size_type find_first_not_of(CharT c, size_type pos = 0) const + { + if (pos > size()) + return npos; + else { + pointer finish = this->m_start + this->m_length; + const_iterator result + = std::find_if(this->m_start + pos, finish, + std::not1(std::bind2nd(Eq_traits(), c))); + return result != finish ? result - begin() : npos; + } + } + + public: // find_last_not_of + + size_type find_last_not_of(const basic_string& s, + size_type pos = npos) const + { return find_last_not_of(s.c_str(), pos, s.size()); } + + size_type find_last_not_of(const CharT* s, size_type pos = npos) const + { return find_last_not_of(s, pos, Traits::length(s)); } + + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + std::min(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + Not_within_traits(s, s + n)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + size_type find_last_not_of(CharT c, size_type pos = npos) const + { + const size_type len = size(); + + if (len < 1) + return npos; + else { + const const_iterator last = begin() + std::min(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::not1(std::bind2nd(Eq_traits(), c))); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + public: // Substring. + + basic_string substr(size_type pos = 0, size_type n = npos) const + { + if (pos > size()) + this->throw_out_of_range(); + return basic_string(this->m_start + pos, + this->m_start + pos + std::min(n, size() - pos), this->get_alloc()); + } + + public: // Compare + + int compare(const basic_string& s) const + { return this->s_compare(this->m_start, this->m_start + this->m_length, s.m_start, s.m_start + s.m_length); } + + int compare(size_type pos1, size_type n1, const basic_string& s) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s.m_start, s.m_start + s.m_length); + } + + int compare(size_type pos1, size_type n1, + const basic_string& s, + size_type pos2, size_type n2) const { + if (pos1 > size() || pos2 > s.size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s.m_start + pos2, + s.m_start + pos2 + std::min(n2, size() - pos2)); + } + + int compare(const CharT* s) const + { return this->s_compare(this->m_start, this->m_start + this->m_length, s, s + Traits::length(s)); } + + int compare(size_type pos1, size_type n1, const CharT* s) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s, s + Traits::length(s)); + } + + int compare(size_type pos1, size_type n1, const CharT* s, + size_type n2) const + { + if (pos1 > size()) + this->throw_out_of_range(); + return this->s_compare(this->m_start + pos1, + this->m_start + pos1 + std::min(n1, size() - pos1), + s, s + n2); + } + +public: // Helper function for compare. + static int s_compare(const_pointer f1, const_pointer l1, + const_pointer f2, const_pointer l2) + { + const std::ptrdiff_t n1 = l1 - f1; + const std::ptrdiff_t n2 = l2 - f2; + const int cmp = Traits::compare(detail::get_pointer(f1), + detail::get_pointer(f2), + std::min(n1, n2)); + return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0)); + } +}; + +template +const typename basic_string::size_type +basic_string::npos + = (typename basic_string::size_type) -1; + +// ------------------------------------------------------------ +// Non-member functions. + +// Operator+ + +template +inline basic_string +operator+(const basic_string& x, + const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + y.size(), x.get_allocator()); + result.append(x); + result.append(y); + return result; +} + +template +inline basic_string +operator+(const CharT* s, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, n + y.size()); + result.append(s, s + n); + result.append(y); + return result; +} + +template +inline basic_string +operator+(CharT c, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, 1 + y.size()); + result.push_back(c); + result.append(y); + return result; +} + +template +inline basic_string +operator+(const basic_string& x, const CharT* s) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, x.size() + n, x.get_allocator()); + result.append(x); + result.append(s, s + n); + return result; +} + +template +inline basic_string +operator+(const basic_string& x, const CharT c) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + 1, x.get_allocator()); + result.append(x); + result.push_back(c); + return result; +} + +// Operator== and operator!= + +template +inline bool +operator==(const basic_string& x, + const basic_string& y) +{ + return x.size() == y.size() && + Traits::compare(x.data(), y.data(), x.size()) == 0; +} + +template +inline bool +operator==(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return n == y.size() && Traits::compare(s, y.data(), n) == 0; +} + +template +inline bool +operator==(const basic_string& x, const CharT* s) +{ + std::size_t n = Traits::length(s); + return x.size() == n && Traits::compare(x.data(), s, n) == 0; +} + +template +inline bool +operator!=(const basic_string& x, + const basic_string& y) + { return !(x == y); } + +template +inline bool +operator!=(const CharT* s, const basic_string& y) + { return !(s == y); } + +template +inline bool +operator!=(const basic_string& x, const CharT* s) + { return !(x == s); } + + +// Operator< (and also >, <=, and >=). + +template +inline bool +operator<(const basic_string& x, + const basic_string& y) +{ + return basic_string + ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return basic_string + ::s_compare(s, s + n, y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const basic_string& x, + const CharT* s) +{ + std::size_t n = Traits::length(s); + return basic_string + ::s_compare(x.begin(), x.end(), s, s + n) < 0; +} + +template +inline bool +operator>(const basic_string& x, + const basic_string& y) { + return y < x; +} + +template +inline bool +operator>(const CharT* s, const basic_string& y) { + return y < s; +} + +template +inline bool +operator>(const basic_string& x, const CharT* s) +{ + return s < x; +} + +template +inline bool +operator<=(const basic_string& x, + const basic_string& y) +{ + return !(y < x); +} + +template +inline bool +operator<=(const CharT* s, const basic_string& y) + { return !(y < s); } + +template +inline bool +operator<=(const basic_string& x, const CharT* s) + { return !(s < x); } + +template +inline bool +operator>=(const basic_string& x, + const basic_string& y) + { return !(x < y); } + +template +inline bool +operator>=(const CharT* s, const basic_string& y) + { return !(s < y); } + +template +inline bool +operator>=(const basic_string& x, const CharT* s) + { return !(x < s); } + +// Swap. + +template +inline void swap(basic_string& x, + basic_string& y) + { x.swap(y); } + +// I/O. + +template +inline bool +sgi_string_fill(std::basic_ostream& os, + std::basic_streambuf* buf, + std::size_t n) +{ + CharT f = os.fill(); + std::size_t i; + bool ok = true; + + for (i = 0; i < n; i++) + ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); + return ok; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const basic_string& s) +{ + typename std::basic_ostream::sentry sentry(os); + bool ok = false; + + if (sentry) { + ok = true; + std::size_t n = s.size(); + std::size_t pad_len = 0; + const bool left = (os.flags() & std::ios::left) != 0; + const std::size_t w = os.width(0); + std::basic_streambuf* buf = os.rdbuf(); + + if (w != 0 && n < w) + pad_len = w - n; + + if (!left) + ok = sgi_string_fill(os, buf, pad_len); + + ok = ok && + buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); + + if (left) + ok = ok && sgi_string_fill(os, buf, pad_len); + } + + if (!ok) + os.setstate(std::ios_base::failbit); + + return os; +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, + basic_string& s) +{ + typename std::basic_istream::sentry sentry(is); + + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + const std::ctype& ctype = std::use_facet >(is.getloc()); + + s.clear(); + std::size_t n = is.width(0); + if (n == 0) + n = static_cast(-1); + else + s.reserve(n); + + while (n-- > 0) { + typename Traits::int_type c1 = buf->sbumpc(); + + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + CharT c = Traits::to_char_type(c1); + + if (ctype.is(std::ctype::space, c)) { + if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) + is.setstate(std::ios_base::failbit); + break; + } + else + s.push_back(c); + } + } + + // If we have read no characters, then set failbit. + if (s.size() == 0) + is.setstate(std::ios_base::failbit); + } + else + is.setstate(std::ios_base::failbit); + + return is; +} + +template +std::basic_istream& +getline(std::istream& is, + basic_string& s, + CharT delim) +{ + std::size_t nread = 0; + typename std::basic_istream::sentry sentry(is, true); + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + s.clear(); + + int c1; + while (nread < s.max_size()) { + int c1 = buf->sbumpc(); + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + ++nread; + CharT c = Traits::to_char_type(c1); + if (!Traits::eq(c, delim)) + s.push_back(c); + else + break; // Character is extracted but not appended. + } + } + } + if (nread == 0 || nread >= s.max_size()) + is.setstate(std::ios_base::failbit); + + return is; +} + +template +inline std::basic_istream& +getline(std::basic_istream& is, + basic_string& s) +{ + return getline(is, s, '\n'); +} + +template +inline std::size_t hash_value(basic_string, A> const& v) +{ + return hash_range(v.begin(), v.end()); +} + +typedef basic_string, std::allocator > string; + +}} //namespace boost { namespace interprocess + +#include + +#endif // BOOST_INTERPROCESS_STRING_HPP diff --git a/include/boost/interprocess/containers/tree.hpp b/include/boost/interprocess/containers/tree.hpp new file mode 100644 index 0000000..5b8f06b --- /dev/null +++ b/include/boost/interprocess/containers/tree.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//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 +struct rb_tree_node + : rb_tree_node_base::type> +{ + typedef rb_tree_node_base::type> base_t; + typedef typename boost::detail::allocator:: + rebind_to >::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(upclass_pointer); + } + + const value_type &value() const { return m_value; } + value_type &value() { return m_value; } + private: + value_type m_value; +}; + +template +class rb_tree_alloc_base + //Inherit from node allocator +: public boost::detail::allocator:: + rebind_to >::type, + //Inherit from node_ptr allocator + public boost::detail::allocator:: + rebind_to >::type::value_type::basic_node_pointer>::type, + //Inherit from value_ptr allocator + public boost::detail::allocator::rebind_to::type +{ + + public: + typedef typename boost::detail::allocator:: + rebind_to >::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::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::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 NodeDeallocator; + typedef detail::scoped_destructor 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_ptrnode_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 + left_destroy(pleft, *this); + + basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t()); + scoped_ptr + right_destroy(pright, *this); + + basic_node_ptr_allocator_t::construct(pparent, basic_node_ptr_t()); + scoped_ptr + 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(*this); + node_allocator_t& other_alloc = static_cast(x); + if (this_alloc != other_alloc){ + detail::do_swap(static_cast(*this), + static_cast(x)); + detail::do_swap(static_cast(*this), + static_cast(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_ptrnode_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 + left_destroy(pleft, *this); + + basic_node_ptr_allocator_t::construct(pright, basic_node_ptr_t()); + scoped_ptr + 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 rb_tree_alloc_base + //Inherit from node allocator + : public boost::detail::allocator:: + rebind_to >::type +{ + public: + typedef typename boost::detail::allocator:: + rebind_to >::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::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::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 NodeDeallocator; + typedef detail::scoped_destructor 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 + node_pointer allocate_and_construct_node(const Convertible &x) + { + node_pointer p = node_allocator_t::allocate(1); + scoped_ptrnode_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(*this); + node_allocator_t& other_alloc = static_cast(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::value){ + basic_node_ptr_allocator_t node_ptr_allocator(*this); + scoped_ptrnode_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 + left_destroy(pleft, node_ptr_allocator); + + node_ptr_allocator.construct(pright, basic_node_ptr_t()); + scoped_ptr + 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::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 rb_tree + : protected rb_tree_alloc_base::value> +{ + private: + typedef rb_tree_alloc_base::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 rb_tree_algo_t; + typedef rb_tree_func 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 const_iterator; + typedef rb_tree_iterator iterator; + typedef boost::reverse_iterator reverse_iterator; + typedef boost::reverse_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 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(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(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 + 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 + 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 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 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(lower), iterator(upper)); + } + + std::pair 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(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(m_data); } + + Compare & get_compare() + { return static_cast(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 +inline bool +operator==(const rb_tree& x, + const rb_tree& y) +{ + return x.size() == y.size() && + std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const rb_tree& x, + const rb_tree& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); +} + +template +inline bool +operator!=(const rb_tree& x, + const rb_tree& y) { + return !(x == y); +} + +template +inline bool +operator>(const rb_tree& x, + const rb_tree& y) { + return y < x; +} + +template +inline bool +operator<=(const rb_tree& x, + const rb_tree& y) { + return !(y < x); +} + +template +inline bool +operator>=(const rb_tree& x, + const rb_tree& y) { + return !(x < y); +} + + +template +inline void +swap(rb_tree& x, + rb_tree& y) +{ + x.swap(y); +} + +} //namespace detail { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_TREE_HPP + diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp new file mode 100644 index 0000000..8171a3d --- /dev/null +++ b/include/boost/interprocess/containers/vector.hpp @@ -0,0 +1,1582 @@ +/* + * + * 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_INTERPROCESS_VECTOR_HPP +#define BOOST_INTERPROCESS_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { + +namespace interprocess { + +namespace detail { + +/*!This struct deallocates and allocated memory */ +template +struct vector_alloc_holder : public A +{ + typedef typename A::pointer pointer; + typedef typename A::size_type size_type; + + //Constructor, does not throw + vector_alloc_holder(const A &a) + : A(a), m_start(0), m_size(0), m_capacity(0) + {} + + //Destructor + ~vector_alloc_holder() + { this->priv_deallocate(); } + + typedef boost::integral_constant allocator_v1; + typedef boost::integral_constant allocator_v2; + typedef boost::integral_constant::value> alloc_version; + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + return allocation_command(command, limit_size, preferred_size, + received_size, reuse, alloc_version()); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + if(!(command & allocate_new)) + return std::pair(0, 0); + received_size = preferred_size; + return std::make_pair(A::allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v2) + { + return A::allocation_command(command, limit_size, preferred_size, + received_size, reuse); + } + + size_type next_capacity(size_type additional_objects) const + { return get_next_capacity(A::max_size(), this->m_capacity, additional_objects); } + + pointer m_start; + size_type m_size; + size_type m_capacity; + + private: + void priv_deallocate() + { + if(!m_start) return; + this->deallocate(m_start, m_capacity); + m_capacity = 0; + } +}; + +} //namespace detail { + + +//vector class +template +class vector : private detail::vector_alloc_holder +{ + typedef vector self_t; + typedef detail::vector_alloc_holder base_t; + typedef detail::scoped_array_deallocator 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 constant_iterator cvalue_iterator; + + public: + //Vector const_iterator + class const_iterator + : public boost::iterator + { + 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; + 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; + 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 + reverse_iterator; + typedef typename boost::reverse_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) + { this->assign(n, value); } + + //Copy constructor + vector(const vector& x) + : base_t(x.get_allocator()) + { *this = x; } + + //Construct from iterator range + template + vector(InIt first, InIt last, const allocator_type& a = allocator_type()) + : base_t(a) + { this->assign(first, last); } + + //Destructor + ~vector() + { this->priv_destroy_all(); } + + //Functions: begin, rbegin, end, rend + iterator begin() + { return iterator(this->m_start); } + + iterator end() + { return iterator(this->m_start + this->m_size); } + + const_iterator begin() const + { return const_iterator(this->m_start); } + + const_iterator end() const + { return const_iterator(this->m_start + this->m_size); } + + 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_start[this->m_size - 1]; } + + const_reference back() const + { return this->m_start[this->m_size - 1]; } + + //Functions: size, max_size, capacity, empty + size_type size() const + { return this->m_size; } + + size_type max_size() const + { return allocator_type::max_size(); } + + size_type capacity() const + { return this->m_capacity; } + + bool empty() const + { return !this->m_size; } + + //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 (this->capacity() < n){ + //Allocate new size, copy data and free old buffer + const size_type old_size = this->size(); + size_type new_cap; + pointer tmp = this->priv_reserve_and_copy + (n, new_cap, this->m_start, this->m_start + this->m_size); + this->priv_destroy_and_deallocate(); + this->m_start = tmp; + this->m_size = old_size; + this->m_capacity = new_cap; + } + } + + //Assignment + vector& operator=(const vector& x) + { + if (&x != this){ + this->assign(x.m_start, x.m_start + x.m_size); + } + return *this; + } + + void assign(size_type n, const value_type& val = T()) + { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } + + template + void assign(InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + void push_back(const T& x = T()) + { + if (this->m_size < this->m_capacity){ + //There is more memory, just construct a new object at the end + this->construct(this->m_start + this->m_size, x); + ++this->m_size; + } + + this->insert(this->end(), static_cast(1), x); + } + + void swap(vector& x) + { + allocator_type &this_al = *this, &other_al = x; + //Just swap internals + detail::do_swap(this->m_start, x.m_start); + detail::do_swap(this->m_size, x.m_size); + detail::do_swap(this->m_capacity, x.m_capacity); + + 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 + void insert(iterator pos, InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + void insert (iterator p, size_type n, const T& x) + { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + + void pop_back() + { + //Destroy last element + --this->m_size; + this->destroy(this->m_start + this->m_size); + } + + // 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) + { + size_type p_off = position.get_ptr() - this->m_start; + if (p_off + 1 != this->m_size){ + //If not the last element, copy left [position, end()) elements + copy_n(this->m_start + (p_off + 1), this->m_size - (p_off + 1), this->m_start + p_off); + } + --this->m_size; + //Destroy last element + this->destroy(this->m_start + this->m_size); + return iterator(position.get_ptr()); + } + + iterator erase(const_iterator first, const_iterator last) + { + //Overwrite [last, end()) elements to first + size_type f_off = first.get_ptr() - this->m_start; + size_type l_off = last.get_ptr() - this->m_start; + size_type n = l_off - f_off; + size_type rem = this->m_size - l_off; + size_type to_destroy = this->m_size - (f_off + rem); + size_type destroy_off = f_off + rem; + + //Overwrite [last, end()) elements to first + copy_n(last.get_ptr(), rem, first.get_ptr()); + //Destroy remaining objects + this->priv_destroy_n(this->m_start + destroy_off, to_destroy); + this->m_size -= n; + return iterator(first.get_ptr()); + } + + void resize(size_type new_size, const T& x = T()) + { + pointer finish = this->m_start + this->m_size; + if (new_size < size()){ + //Destroy last elements + this->erase(iterator(this->m_start + new_size), this->end()); + } + else{ + //Insert new elements at the end + this->insert(iterator(finish), new_size - this->size(), x); + } + } + + void clear() + { this->priv_destroy_all(); } + + private: + + void priv_destroy_all() + { + if(!this->m_start) + return; + + pointer start = this->m_start; + for(; this->m_size--; ++start) + this->destroy(start); + + this->m_size = 0; + } + + template + void priv_range_insert(const pointer &pos, FwdIt first, + FwdIt last, std::forward_iterator_tag) + { + if (first != last){ + size_type n = std::distance(first, last); + //Check if we have enough memory or try to expand current memory + size_type remaining = this->m_capacity - this->m_size; + bool same_buffer_start; + std::pair ret; + size_type new_cap; + + //Check if we already have room + if (n < remaining){ + same_buffer_start = true; + } + else{ + //There is not enough memory, allocate a new + //buffer or expand the old one. + new_cap = this->next_capacity(n); + ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->m_size + n, new_cap, new_cap, this->m_start); + + //Check for forward expansion + same_buffer_start = ret.second && this->m_start == ret.first; + if(same_buffer_start){ + this->m_capacity = new_cap; + } + } + + //If we had room or we have expanded forward + if (same_buffer_start){ + this->priv_range_insert_expand_forward + (pos, first, last, n); + } + //Backwards (and possibly forward) expansion + else if(ret.second){ + this->priv_range_insert_expand_backwards + (ret.first, new_cap, pos, first, last, n); + } + //New buffer + else{ + this->priv_range_insert_new_allocation + (ret.first, new_cap, pos, first, last); + } + } + } + + template + void priv_range_insert_expand_forward + (const pointer &pos, FwdIt first, FwdIt last, size_type n) + { + //There is enough memory + pointer old_finish = this->m_start + this->m_size; + const size_type elems_after = old_finish - pos; + + if (elems_after > n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + n_uninitialized_copy(old_finish - n, old_finish, + old_finish, static_cast(*this)); + this->m_size += n; + //Copy previous to last objects to the initialized end + std::copy_backward(pos, old_finish - n, old_finish); + //Insert new objects in the pos + copy_n(first, n, pos); + } + else { + //The new elements don't fit in the [pos, end()) range. Copy + //to the beginning of the unallocated zone the last new elements. + FwdIt mid = first; + std::advance(mid, elems_after); + n_uninitialized_copy(mid, last, old_finish, static_cast(*this)); + this->m_size += n - elems_after; + //Copy old [pos, end()) elements to the uninitialized memory + n_uninitialized_copy(pos, old_finish, + this->m_start + this->m_size, static_cast(*this)); + this->m_size += elems_after; + //Copy first new elements in pos + std::copy(first, mid, pos); + } + } + + template + void priv_range_insert_new_allocation + (pointer new_start, size_type new_cap, const pointer &pos, FwdIt first, FwdIt last) + { + //Anti-exception rollback + scoped_ptr scoped_alloc(new_start, dealloc_t(*this, new_cap)); + pointer new_finish = new_start; + BOOST_TRY{ + //Initialize with [begin(), pos) old buffer + //the start of the new buffer + new_finish += n_uninitialized_copy + (this->m_start, pos, new_start, static_cast(*this)); + //Initialize new objects, starting from previous point + new_finish += n_uninitialized_copy + (first, last, new_finish, static_cast(*this)); + //Initialize from the rest of the old buffer, + //starting from previous point + new_finish += n_uninitialized_copy + (pos, this->m_start + this->m_size, new_finish, static_cast(*this)); + } + BOOST_CATCH(...){ + this->priv_destroy_n(new_start, new_finish - new_start); + 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_size = new_finish - new_start; + this->m_capacity = new_cap; + } + + template + void priv_range_insert_expand_backwards + (pointer new_start, size_type new_capacity, + const pointer &pos, FwdIt first, FwdIt last, size_type n) + { + typedef detail::scoped_destructor_n + ValueArrayDestructor; + + //Backup old data + pointer old_start = this->m_start; + pointer old_finish = this->m_start + this->m_size; + size_type old_size = this->m_size; + + //We can have 8 possibilities: + const size_type elemsbefore = (size_type)(pos - this->m_start); + const size_type s_before = (size_type)(old_start - new_start); + + //Update the vector buffer information to a safe state + this->m_start = new_start; + this->m_capacity = new_capacity; + this->m_size = 0; + + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + scoped_ptr + old_values_destroyer + (old_start, ValueArrayDestructor(static_cast(*this),old_size)); + + //Check if s_before is so big that even copying the old data + new data + //there is a gap between the new data and the old data + if(s_before >= (old_size + n)){ + //Old situation: + // _________________________________________________________ + //| raw_mem | old_begin | old_end | + //| __________________________________|___________|_________| + // + //New situation: + // _________________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|________________________| + // + //Copy first old values before pos, after that the + //new objects + uninitialized_copy_copy + (old_start, pos, first, last, new_start, static_cast(*this)); + scoped_ptr + new_values_destroyer(new_start + ,ValueArrayDestructor(static_cast(*this) + ,elemsbefore)); + //Now initialize the rest of memory with the last old values + uninitialized_copy(pos, old_finish + ,new_start + elemsbefore + n, static_cast(*this)); + //All new elements correctly constructed, avoid new element destruction + new_values_destroyer.release(); + //Old values destroyed automatically with "old_values_destroyer" + //when "old_values_destroyer" goes out of scope. + this->m_size = old_size + n; + } + //Check if s_before is so big that divides old_end + else if(difference_type(s_before) >= difference_type(elemsbefore + n)){ + //Old situation: + // __________________________________________________ + //| raw_mem | old_begin | old_end | + //| ___________________________|___________|_________| + // + //New situation: + // __________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|_________________| + // + //Copy first old values before pos, after that the + //new objects + uninitialized_copy_copy + (old_start, pos, first, last, new_start, static_cast(*this)); + scoped_ptr + new_values_destroyer(new_start + ,ValueArrayDestructor(static_cast(*this) + ,elemsbefore)); + size_type raw_gap = s_before - (elemsbefore + n); + //Now initialize the rest of s_before memory with the + //first of elements after new values + uninitialized_copy(pos, pos + raw_gap + ,new_start + elemsbefore + n, static_cast(*this)); + //All new elements correctly constructed, avoid new element destruction + new_values_destroyer.release(); + //All new elements correctly constructed, avoid old element destruction + old_values_destroyer.release(); + //Update size since we have a contiguous buffer + this->m_size = old_size + s_before; + //Now copy remaining last objects in the old buffer begin + pointer to_destroy = std::copy(pos + raw_gap, old_finish, old_start); + //Now destroy redundant elements + size_type n_destroy = old_finish - to_destroy; + this->priv_destroy_n(to_destroy, n_destroy); + this->m_size -= n_destroy; + } + else{ + //Check if we have to do the insertion in two phases + //since maybe s_before is not enough and + //the buffer was expanded both sides + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin + old_end | raw_mem | + //|_________|_____________________|_________________| + // + //New situation with do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|___________________________________|_____________| + // + //New without do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|____________________________|____________________| + // + bool do_after = n > s_before; + FwdIt before_end = first; + //If we have to expand both sides, + //we will play if the first new values so + //calculate the upper bound of new values + if(do_after){ + std::advance(before_end, s_before); + } + + //Now we can have two situations: the raw_mem of the + //beginning divides the old_begin, or the new elements: + if (s_before <= elemsbefore) { + //The raw memory divides the old_begin group: + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_________|___________|_________|_________________| + // + //New situation with do_after(1): + //This is not definitive situation, the second phase + //will include + // _________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_________|_________|_________________| + // + //New situation without do_after: + // _________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|_____________________| + // + //Copy the first part of old_begin to raw_mem + pointer start_n = old_start + difference_type(s_before); + uninitialized_copy(old_start, start_n, new_start, static_cast(*this)); + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + this->m_size = old_size + s_before; + //Now copy the second part of old_begin overwriting himself + pointer next = std::copy(start_n, pos, old_start); + if(do_after){ + //Now copy the new_beg elements + std::copy(first, before_end, next); + } + else{ + //Now copy the all the new elements + pointer move_start = std::copy(first, last, next); + //Now displace old_end elements + pointer move_end = std::copy(pos, old_finish, move_start); + //Destroy remaining moved elements from old_end + difference_type n_destroy = s_before - n; + this->priv_destroy_n(move_end, n_destroy); + this->m_size -= n_destroy; + } + } + else { + //The raw memory divides the new elements + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_______________|___________|_________|_________________| + // + //New situation with do_after(): + // ____________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_______________|_________|______________| + // + //New situation without do_after: + // ______________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|__________________________| + // + //First copy whole old_begin and part of new to raw_mem + FwdIt mid = first; + size_type n_new_init = difference_type(s_before) - elemsbefore; + std::advance(mid, n_new_init); + uninitialized_copy_copy + (old_start, pos, first, mid, new_start, static_cast(*this)); + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + this->m_size = old_size + s_before; + + if(do_after){ + //Copy new_beg part +// std::copy(mid, before_end, old_start); + std::copy(mid, before_end, old_start); + } + else{ + //Copy all new elements + pointer move_start = std::copy(mid, last, old_start); + //Displace old_end + pointer move_end = std::copy(pos, old_finish, move_start); + //Destroy remaining moved elements from old_end + difference_type n_destroy = s_before - n; + this->priv_destroy_n(move_end, n_destroy); + this->m_size -= n_destroy; + } + } + + //This is only executed if two phase construction is needed + //This can be executed without exception handling since we + //have to just copy and append in raw memory and + //old_values_destroyer has been released in phase 1. + if(do_after){ + //The raw memory divides the new elements + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //New situation with do_after(2): + // ______________________________________________________ + //| old_begin + new | old_end |raw | + //|_______________________________________|_________|____| + // + const size_type n_after = n - s_before; + const difference_type elemsafter = old_size - elemsbefore; + + //The new_end part is [first + (n - n_after), last) + std::advance(first, n - n_after); + + //We can have two situations: + if (elemsafter > difference_type(n_after)){ + //The raw_mem from end will divide displaced old_end + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //First copy the part of old_end raw_mem + pointer finish_n = old_finish - difference_type(n_after); + uninitialized_copy(finish_n, old_finish + ,old_finish, static_cast(*this)); + this->m_size += n_after; + //Displace the rest of old_end to the new position + std::copy_backward(pos, finish_n, old_finish); + //Now overwrite with new_end + std::copy(first, last, pos); + } + else { + //The raw_mem from end will divide new_end part + // + //Old situation: + // _____________________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|_____________________| + // + //New situation with do_after(2): + // _____________________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_______________|________|_________| + // + FwdIt mid = first; + std::advance(mid, elemsafter); + //First initialize data in raw memory + uninitialized_copy_copy + (mid, last, pos, old_finish, + old_finish, static_cast(*this)); + this->m_size += n_after; + //Now copy the part of new_end over constructed elements + std::copy(first, mid, pos); + } + } + } +/* + const difference_type elemsbefore = pos - this->m_start; + + typedef detail::scoped_destructor_n + ValueArrayDestructor; + + pointer old_start = this->m_start; + pointer old_finish = this->m_start + this->m_size; + size_type old_size = this->m_size; + //Update the vector buffer information + this->m_start = new_start; + this->m_capacity = new_capacity; + + //If anything goes wrong, this object will destroy + //all old objects + scoped_ptr + old_values_destroyer(old_start + ,ValueArrayDestructor(static_cast(*this) + ,old_size)); + //If something goes wrong size will be 0 + this->m_size = 0; + + //This is the number of objects expanded backwards + size_type s_before = (size_type)(old_start - this->m_start); + + //Check if s_before is so big that even copying the old data + new data + //there is a gap between the new data and the old data + if(s_before >= (old_size + n)){ + //Old situation: + // _________________________________________________________ + //| raw_mem | old_begin | old_end | + //| __________________________________|___________|_________| + // + //New situation: + // _________________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|________________________| + // + //Copy first old values before pos, after that the + //new objects + this->priv_uninitialized_copy_copy + (old_start, pos, first, last, new_start, static_cast(*this)); + scoped_ptr + new_values_destroyer(new_start + ,ValueArrayDestructor(static_cast(*this) + ,elemsbefore)); + //Now initialize the rest of memory with the last old values + uninitialized_copy(pos, old_finish + ,new_start + elemsbefore + n, static_cast(*this)); + //All new elements correctly constructed, avoid new element destruction + new_values_destroyer.release(); + //Old values destroyed automatically with "old_values_destroyer" + //when "old_values_destroyer" goes out of scope. + this->m_size = old_size + n; + } + //Check if s_before is so big that divides old_end + else if(difference_type(s_before) >= difference_type(elemsbefore + n)){ + //Old situation: + // __________________________________________________ + //| raw_mem | old_begin | old_end | + //| ___________________________|___________|_________| + // + //New situation: + // __________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|__________|_________|_________________| + // + //Copy first old values before pos, after that the + //new objects + this->priv_uninitialized_copy_copy + (old_start, pos, first, last, new_start, static_cast(*this)); + scoped_ptr + new_values_destroyer(new_start + ,ValueArrayDestructor(static_cast(*this) + ,elemsbefore)); + size_type raw_gap = s_before - (elemsbefore + n); + //Now initialize the rest of s_before memory with the + //first of elements after new values + uninitialized_copy(pos, pos + raw_gap + ,new_start + elemsbefore + n, static_cast(*this)); + //All new elements correctly constructed, avoid new element destruction + new_values_destroyer.release(); + //All new elements correctly constructed, avoid old element destruction + old_values_destroyer.release(); + //Update size since we have a contiguous buffer + this->m_size = old_size + s_before; + //Now copy remaining last objects in the old buffer begin + pointer to_destroy = std::copy(pos + raw_gap, old_finish, old_start); + //Now destroy redundant elements + size_type n_destroy = old_finish - to_destroy; + this->priv_destroy_n(to_destroy, n_destroy); + this->m_size -= n_destroy; + } + else{ + //Check if we have to do the insertion in two phases + //since maybe s_before is not enough and + //the buffer was expanded both sides + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin + old_end | raw_mem | + //|_________|_____________________|_________________| + // + //New situation with do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|___________________________________|_____________| + // + //New without do_after: + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | + //|____________________________|____________________| + // + bool do_after = n > s_before; + FwdIt before_end = first; + //If we have to expand both sides, + //we will play if the first new values so + //calculate the upper bound of new values + if(do_after){ + std::advance(before_end, s_before); + } + + //Now we can have two situations: the raw_mem of the + //beginning divides the old_begin, or the new elements: + if (difference_type(s_before) <= elemsbefore) { + //The raw memory divides the old_begin group: + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_________|___________|_________|_________________| + // + //New situation with do_after(1): + //This is not definitive situation, the second phase + //will include + // _________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_________|_________|_________________| + // + //New situation without do_after: + // _________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|_____________________| + // + //Copy the first part of old_begin to raw_mem + pointer start_n = old_start + difference_type(s_before); + uninitialized_copy(old_start, start_n, new_start, static_cast(*this)); + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + this->m_size = old_size + s_before; + //Now copy the second part of old_begin overwriting himself + pointer next = std::copy(start_n, pos, old_start); + if(do_after){ + //Now copy the new_beg elements + std::copy(first, before_end, next); + } + else{ + //Now copy the all the new elements + pointer move_start = std::copy(first, last, next); + //Now displace old_end elements + pointer move_end = std::copy(pos, old_finish, move_start); + //Destroy remaining moved elements from old_end + difference_type n_destroy = s_before - n; + this->priv_destroy_n(move_end, n_destroy); + this->m_size -= n_destroy; + } + } + else { + //The raw memory divides the new elements + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + //Old situation: + // _______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|_______________|___________|_________|_________________| + // + //New situation with do_after(): + // ____________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | + //|___________|_______________|_________|______________| + // + //New situation without do_after: + // ______________________________________________________ + //| old_begin | new | old_end | raw_mem | + //|___________|_____|_________|__________________________| + // + //First copy whole old_begin and part of new to raw_mem + FwdIt mid = first; + size_type n_new_init = difference_type(s_before) - elemsbefore; + std::advance(mid, n_new_init); + uninitialized_copy_n_copy_n + (old_start, elemsbefore, first, mid, new_start, static_cast(*this)); + //The buffer is all constructed until old_end, + //release destroyer and update size + old_values_destroyer.release(); + this->m_size = old_size + s_before; + + if(do_after){ + //Copy new_beg part +// std::copy(mid, before_end, old_start); + std::copy(mid, before_end, old_start); + } + else{ + //Copy all new elements + pointer move_start = std::copy(mid, last, old_start); + //Displace old_end + pointer move_end = std::copy(pos, old_finish, move_start); + //Destroy remaining moved elements from old_end + difference_type n_destroy = s_before - n; + this->priv_destroy_n(move_end, n_destroy); + this->m_size -= n_destroy; + } + } + + //This is only executed if two phase construction is needed + //This can be executed without exception handling since we + //have to just copy and append in raw memory and + //old_values_destroyer has been released in phase 1. + if(do_after){ + //The raw memory divides the new elements + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //New situation with do_after(2): + // ______________________________________________________ + //| old_begin + new | old_end |raw | + //|_______________________________________|_________|____| + // + const size_type n_after = n - s_before; + const difference_type elemsafter = old_size - elemsbefore; + + //The new_end part is [first + (n - n_after), last) + std::advance(first, n - n_after); + + //We can have two situations: + if (elemsafter > difference_type(n_after)){ + //The raw_mem from end will divide displaced old_end + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //First copy the part of old_end raw_mem + pointer finish_n = old_finish - difference_type(n_after); + uninitialized_copy(finish_n, old_finish + ,old_finish, static_cast(*this)); + this->m_size += n_after; + //Displace the rest of old_end to the new position + std::copy_backward(pos, finish_n, old_finish); + //Now overwrite with new_end + std::copy(first, last, pos); + } + else { + //The raw_mem from end will divide new_end part + // + //Old situation: + // _____________________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|_____________________| + // + //New situation with do_after(2): + // _____________________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_______________|________|_________| + // + FwdIt mid = first; + std::advance(mid, elemsafter); + //First initialize data in raw memory + this->priv_uninitialized_copy_copy + (mid, last, pos, old_finish, + old_finish, static_cast(*this)); + this->m_size += n_after; + //Now copy the part of new_end over constructed elements + std::copy(first, mid, pos); + } + } + }*/ + } + + template + 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 + 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 sequence, erase remaining + this->erase(cur, end()); + } + else{ + //There are more elements in the range, insert the remaining ones + this->insert(this->end(), first, last); + } + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, + std::forward_iterator_tag) + { + size_type n = std::distance(first, last); + //Check if we have enough memory or try to expand current memory + size_type remaining = this->m_capacity - this->m_size; + bool same_buffer_start; + std::pair ret; + size_type new_cap; + + if (n < remaining){ + same_buffer_start = true; + } + else{ + //There is not enough memory, allocate a new buffer + new_cap = this->next_capacity(n); + ret = this->allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->size() + n, new_cap, new_cap, this->m_start); + same_buffer_start = ret.second && this->m_start == ret.first; + if(same_buffer_start){ + this->m_capacity = new_cap; + } + } + + if(same_buffer_start){ + if (this->size() >= n){ + //There is memory, but there are more old elements than new ones + //Overwrite old elements with new ones + copy_n(first, n, this->m_start); + //Destroy remaining old elements + this->priv_destroy_n(this->m_start + n, this->m_size - n); + this->m_size = n; + } + 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, this->size()); + std::copy(first, mid, this->m_start); + //Initialize the remaining new elements in the uninitialized memory + n_uninitialized_copy(mid, last, this->m_start + this->m_size, static_cast(*this)); + this->m_size = n; + } + } + else if(!ret.second){ + scoped_ptr scoped_alloc(ret.first, dealloc_t(*this, new_cap)); + n_uninitialized_copy(first, last, ret.first, static_cast(*this)); + scoped_alloc.release(); + //Destroy and deallocate old buffer + this->priv_destroy_and_deallocate(); + this->m_start = ret.first; + this->m_size = n; + this->m_capacity = new_cap; + } + else{ + //Backwards expansion + //If anything goes wrong, this object will destroy + //all old objects + typedef detail::scoped_destructor_n + ValueArrayDestructor; + pointer old_start = this->m_start; + size_type old_size = this->m_size; + scoped_ptr + old_values_destroyer(old_start + ,ValueArrayDestructor(static_cast(*this) + ,old_size)); + //If something goes wrong size will be 0 + //but holding the whole buffer + this->m_size = 0; + this->m_start = ret.first; + this->m_capacity = new_cap; + + //Backup old buffer data + size_type old_offset = old_start - ret.first; + size_type first_count = min_value(n, old_offset); + FwdIt mid = n_uninitialized_copy_n + (first, first_count, ret.first, static_cast(*this)); + + if(old_offset > n){ + //All old elements will be destroyed by "old_values_destroyer" + this->m_size = n; + } + else{ + //We have constructed objects from the new begin until + //the old end so release the rollback destruction + old_values_destroyer.release(); + this->m_start = ret.first; + this->m_size = first_count + old_size; + //Now overwrite the old values + size_type second_count = min_value(old_size, n - first_count); + mid = copy_n(mid, second_count, old_start); + + //Check if we still have to append elements in the + //uninitialized end + if(second_count == old_size){ + n_uninitialized_copy_n(mid, n - first_count - second_count + , old_start + old_size, static_cast(*this)); + } + else{ + //We have to destroy some old values + this->priv_destroy_n + (old_start + second_count, old_size - second_count); + this->m_size = n; + } + this->m_size = n; + } + } +/* + size_type len = std::distance(first, last); + //Check if we have enough memory or try to expand current memory + if (this->m_capacity >= len || this->expand_by(len - this->m_capacity)){ + + } + else { + //There is no enough memory, allocate and copy new buffer + size_type new_cap; + pointer tmp = this->priv_allocate_and_copy(len, new_cap, first, last); + //Destroy and deallocate old buffer + this->priv_destroy_and_deallocate(); + this->m_start = tmp; + this->m_size = len; + this->m_capacity = new_cap; + }*/ + } + + template + void priv_assign_dispatch(Integer n, Integer val, boost::mpl::true_) + { this->assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InIt first, InIt last, + boost::mpl::false_) + { + //Dispatch depending on integer/iterator + typedef typename + std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_insert_dispatch( iterator pos, Integer n, + Integer val, boost::mpl::true_) + { this->insert(pos, (size_type)n, (T)val); } + + template + void priv_insert_dispatch(iterator pos, InIt first, + InIt last, boost::mpl::false_) + { + //Dispatch depending on integer/iterator + typedef typename + std::iterator_traits::iterator_category ItCat; + this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); + } + + void priv_destroy_n(pointer p, size_type n) + { for(; n--; ++p) this->destroy(p); } + + template + void priv_initialize_aux(Integer n, Integer value, boost::mpl::true_) + { + this->priv_range_initialize(cvalue_iterator(value, n), + cvalue_iterator(), + cvalue_iterator::iterator_category()); + } + + template + void priv_initialize_aux(InIt first, InIt last, + boost::mpl::false_) + { + //Dispatch depending on integer/iterator + typedef typename + std::iterator_traits::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_n(this->m_start, this->m_size); + this->deallocate(this->m_start, this->m_capacity); + } + } + + template + pointer priv_reserve_and_copy(size_type n, size_type &cap + ,FwdIt first, FwdIt last) + { + //Allocate n element buffer and initialize from range + pointer result = this->allocation_command(allocate_new, n, n, cap).first; + scoped_ptr scoped_alloc(result, dealloc_t(*this, cap)); + n_uninitialized_copy(first, last, result, static_cast(*this)); + scoped_alloc.release(); + return result; + } + +/* + template + pointer priv_allocate_and_copy(size_type n, size_type &cap + ,FwdIt first, FwdIt last) + { + //Allocate n element buffer and initialize from range + pointer result = this->allocation_command(allocate_new, n, n, cap).first; + scoped_ptr scoped_alloc(result, dealloc_t(*this, cap)); + n_uninitialized_copy(first, last, result, static_cast(*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 +inline bool +operator==(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() == y.size() && + std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator!=(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() != y.size() || + !std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const vector& x, const vector& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); +} + +template +inline void swap(vector& x, vector& y) +{ + x.swap(y); +} + + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_VECTOR_HPP + diff --git a/include/boost/interprocess/containers/vector_old.hpp b/include/boost/interprocess/containers/vector_old.hpp new file mode 100644 index 0000000..c18047f --- /dev/null +++ b/include/boost/interprocess/containers/vector_old.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { + +namespace interprocess { + +namespace detail { + +/*!This struct deallocates and allocated memory */ +template +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 vector : private detail::vector_alloc_holder +{ + typedef vector self_t; + typedef detail::vector_alloc_holder base_t; + typedef detail::scoped_array_deallocator 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 range_from_ref_it; + + public: + //Vector const_iterator + class const_iterator + : public boost::iterator + { + 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; + 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; + 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 + reverse_iterator; + typedef typename boost::reverse_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& 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 + vector(InIt first, InIt last, + const allocator_type& a = allocator_type()) + : base_t(a) + { + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ 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& operator=(const vector& 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 tmp(n, val, static_cast(*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 + void assign(InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ 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(1), x); + } + } + + void swap(vector& 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 + void insert(iterator pos, InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = boost::is_integral::value; + typedef boost::mpl::bool_ 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 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 + 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 + 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 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 + 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 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 + 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 + 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 + 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 + void priv_assign_dispatch(Integer n, Integer val, boost::mpl::true_) + { this->assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InIt first, InIt last, + boost::mpl::false_) + { + //Dispatch depending on integer/iterator + typedef typename + std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_insert_dispatch( iterator pos, Integer n, + Integer val, boost::mpl::true_) + { this->insert(pos, (size_type)n, (T)val); } + + template + void priv_insert_dispatch(iterator pos, InIt first, + InIt last, boost::mpl::false_) + { + //Dispatch depending on integer/iterator + typedef typename + std::iterator_traits::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 + 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 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 + void priv_initialize_aux(InIt first, InIt last, + boost::mpl::false_) + { + //Dispatch depending on integer/iterator + typedef typename + std::iterator_traits::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 + 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 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 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 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 +inline bool +operator==(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() == y.size() && + std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator!=(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() != y.size() || + !std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const vector& x, const vector& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), + y.begin(), y.end()); +} + +template +inline void swap(vector& x, vector& y) +{ + x.swap(y); +} + + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif // #ifndef BOOST_SHMEM_VECTOR_HPP + diff --git a/include/boost/interprocess/detail/Attic/creation_tags.hpp b/include/boost/interprocess/detail/Attic/creation_tags.hpp new file mode 100644 index 0000000..de0642e --- /dev/null +++ b/include/boost/interprocess/detail/Attic/creation_tags.hpp @@ -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 +#include + +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 + +#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP + diff --git a/include/boost/interprocess/detail/Attic/generic_cast.hpp b/include/boost/interprocess/detail/Attic/generic_cast.hpp new file mode 100644 index 0000000..3834fa3 --- /dev/null +++ b/include/boost/interprocess/detail/Attic/generic_cast.hpp @@ -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 +#include + +#include + +//Predeclaration of pointer casts +namespace boost +{ + template + T static_pointer_cast(const U &r); + template + T const_pointer_cast(const U &r); + template + T dynamic_pointer_cast(const U &r); + template + T reinterpret_pointer_cast(const U &r); +} //namespace boost + +namespace boost { namespace interprocess { namespace detail { + +template +inline T do_static_cast_impl(const U &r, const boost::false_type) +{ + return static_pointer_cast(r); +} + +template +inline T do_static_cast_impl(const U &r, const boost::true_type) +{ + return static_cast(r); +} + +template +inline T do_dynamic_cast_impl(const U &r, const boost::false_type) +{ + return dynamic_pointer_cast(r); +} + +template +inline T do_dynamic_cast_impl(const U &r, const boost::true_type) +{ + return dynamic_cast(r); +} + +template +inline T do_reinterpret_cast_impl(const U &r, const boost::false_type) +{ + return reinterpret_pointer_cast(r); +} + +template +inline T do_reinterpret_cast_impl(const U &r, const boost::true_type) +{ + return reinterpret_cast(r); +} + +template +inline T do_const_cast_impl(const U &r, const boost::false_type) +{ + return const_pointer_cast(r); +} + +template +inline T do_const_cast_impl(const U &r, const boost::true_type) +{ + return const_cast(r); +} + +} //namespace detail { + +template +inline T do_static_cast(const U &r) +{ + return detail::do_static_cast_impl(r, typename boost::is_pointer::type()); +} + +template +inline T do_dynamic_cast(const U &r) +{ + return detail::do_dynamic_cast_impl(r, typename boost::is_pointer::type()); +} + +template +inline T do_reinterpret_cast(const U &r) +{ + return detail::do_reinterpret_cast_impl(r, typename boost::is_pointer::type()); +} + +template +inline T do_const_cast(const U &r) +{ + return detail::do_const_cast_impl(r, typename boost::is_pointer::type()); +} + + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_GENERIC_CAST_HPP + diff --git a/include/boost/interprocess/detail/Attic/multi_segment_services.hpp b/include/boost/interprocess/detail/Attic/multi_segment_services.hpp new file mode 100644 index 0000000..99586de --- /dev/null +++ b/include/boost/interprocess/detail/Attic/multi_segment_services.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 +#include + + +/*!\file + Describes a named shared memory allocation user class. +*/ + +namespace boost { + +namespace interprocess { + +class multi_segment_services +{ + public: + virtual std::pair 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 + +#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP diff --git a/include/boost/interprocess/detail/cast_tags.hpp b/include/boost/interprocess/detail/cast_tags.hpp new file mode 100644 index 0000000..23ad9b4 --- /dev/null +++ b/include/boost/interprocess/detail/cast_tags.hpp @@ -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 +#include + +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 + +#endif //#ifndef BOOST_INTERPROCESS_CAST_TAGS_HPP + diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp new file mode 100644 index 0000000..da242a1 --- /dev/null +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -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 +#include + +#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 diff --git a/include/boost/interprocess/detail/config_end.hpp b/include/boost/interprocess/detail/config_end.hpp new file mode 100644 index 0000000..ef4761d --- /dev/null +++ b/include/boost/interprocess/detail/config_end.hpp @@ -0,0 +1,11 @@ +#include +#include + +#if defined _MSC_VER + #pragma warning (pop) +#endif + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# pragma warn .8026 +# pragma warn .8027 +#endif diff --git a/include/boost/interprocess/detail/creation_tags.hpp b/include/boost/interprocess/detail/creation_tags.hpp new file mode 100644 index 0000000..de0642e --- /dev/null +++ b/include/boost/interprocess/detail/creation_tags.hpp @@ -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 +#include + +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 + +#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP + diff --git a/include/boost/interprocess/detail/generic_cast.hpp b/include/boost/interprocess/detail/generic_cast.hpp new file mode 100644 index 0000000..3834fa3 --- /dev/null +++ b/include/boost/interprocess/detail/generic_cast.hpp @@ -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 +#include + +#include + +//Predeclaration of pointer casts +namespace boost +{ + template + T static_pointer_cast(const U &r); + template + T const_pointer_cast(const U &r); + template + T dynamic_pointer_cast(const U &r); + template + T reinterpret_pointer_cast(const U &r); +} //namespace boost + +namespace boost { namespace interprocess { namespace detail { + +template +inline T do_static_cast_impl(const U &r, const boost::false_type) +{ + return static_pointer_cast(r); +} + +template +inline T do_static_cast_impl(const U &r, const boost::true_type) +{ + return static_cast(r); +} + +template +inline T do_dynamic_cast_impl(const U &r, const boost::false_type) +{ + return dynamic_pointer_cast(r); +} + +template +inline T do_dynamic_cast_impl(const U &r, const boost::true_type) +{ + return dynamic_cast(r); +} + +template +inline T do_reinterpret_cast_impl(const U &r, const boost::false_type) +{ + return reinterpret_pointer_cast(r); +} + +template +inline T do_reinterpret_cast_impl(const U &r, const boost::true_type) +{ + return reinterpret_cast(r); +} + +template +inline T do_const_cast_impl(const U &r, const boost::false_type) +{ + return const_pointer_cast(r); +} + +template +inline T do_const_cast_impl(const U &r, const boost::true_type) +{ + return const_cast(r); +} + +} //namespace detail { + +template +inline T do_static_cast(const U &r) +{ + return detail::do_static_cast_impl(r, typename boost::is_pointer::type()); +} + +template +inline T do_dynamic_cast(const U &r) +{ + return detail::do_dynamic_cast_impl(r, typename boost::is_pointer::type()); +} + +template +inline T do_reinterpret_cast(const U &r) +{ + return detail::do_reinterpret_cast_impl(r, typename boost::is_pointer::type()); +} + +template +inline T do_const_cast(const U &r) +{ + return detail::do_const_cast_impl(r, typename boost::is_pointer::type()); +} + + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_GENERIC_CAST_HPP + diff --git a/include/boost/interprocess/detail/global_lock.hpp b/include/boost/interprocess/detail/global_lock.hpp new file mode 100644 index 0000000..8ede5a1 --- /dev/null +++ b/include/boost/interprocess/detail/global_lock.hpp @@ -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 +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else + +# ifdef BOOST_HAS_UNISTD_H +# include //O_CREAT, O_*... +# include //ftruncate, close +# include //sem_t* family, SEM_VALUE_MAX +# include //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 + +#endif //BOOST_INTERPROCESS_DETAIL_GLOBAL_LOCK_HPP diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp new file mode 100644 index 0000000..8926aa7 --- /dev/null +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// +#include +#include +#include +// +#include +#include +#include +#include + +/*!\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 IndexType + > +class basic_managed_memory_impl +{ + public: + typedef segment_manager + 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 + 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(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 + bool create_from_file (const CharT *filename, + MemCreatorFunc &memcreator) + { + std::basic_ifstream< CharT, std::char_traits > + 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 + 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(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 + std::pair find (char_ptr_holder_t name) + { return mp_header->find(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 + typename segment_manager::template construct_proxy::type + construct(char_ptr_holder_t name) + { return mp_header->construct(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 + typename segment_manager::template find_construct_proxy::type + find_or_construct(char_ptr_holder_t name) + { return mp_header->find_or_construct(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 + typename segment_manager::template construct_proxy::type + construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->construct(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 + typename segment_manager::template find_construct_proxy::type + find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->find_or_construct(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 + typename segment_manager::template construct_iter_proxy::type + construct_it(char_ptr_holder_t name) + { return mp_header->construct_it(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 + typename segment_manager::template find_construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name) + { return mp_header->find_or_construct_it(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 + typename segment_manager::template construct_iter_proxy::type + construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->construct_it(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 + typename segment_manager::template find_construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return mp_header->find_or_construct_it(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 + 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 + bool destroy(const CharType *name) + { return mp_header->destroy(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 + bool destroy(const detail::unique_instance_t *const ) + { return mp_header->destroy(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 + bool destroy_ptr(const T *ptr) + { return mp_header->destroy_ptr(ptr); } + + /*!Returns the name of an object created with construct/find_or_construct + functions. Does not throw*/ + template + 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 + 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 + bool save_to_file (const CharT *filename) + { + //Open output file + std::basic_ofstream< CharT, std::char_traits > + 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(addr); + } + + private: + segment_manager *mp_header; +}; + +} //namespace detail { + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP + diff --git a/include/boost/interprocess/detail/multi_segment_services.hpp b/include/boost/interprocess/detail/multi_segment_services.hpp new file mode 100644 index 0000000..99586de --- /dev/null +++ b/include/boost/interprocess/detail/multi_segment_services.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 +#include + + +/*!\file + Describes a named shared memory allocation user class. +*/ + +namespace boost { + +namespace interprocess { + +class multi_segment_services +{ + public: + virtual std::pair 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 + +#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp new file mode 100644 index 0000000..43a972a --- /dev/null +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 +struct Ctor0Arg +{ + typedef Ctor0Arg self_t; + typedef T target_t; + enum { is_trivial = boost::has_trivial_constructor::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_ Result; + Ctor0Arg::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 +// 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_ 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))) \ +/**/ + +#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\ + 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_ 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 ctor_obj; + return mp_alloc->template + generic_construct(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 \ + T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_AUX_PARAM_LIST, _)) const \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + \ + ctor_obj_t; \ + ctor_obj_t ctor_obj (BOOST_PP_ENUM_PARAMS(n, p)); \ + return mp_alloc->template generic_construct \ + (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 + // T *operator()(P1 &p1, P2 &p2) const + // { + // typedef Ctor2Arg + // + // ctor_obj_t; + // ctor_obj_t ctor_obj(p1, p2); + // + // return mp_alloc->template generic_construct + // (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 + +#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP diff --git a/include/boost/interprocess/detail/null_create_func.hpp b/include/boost/interprocess/detail/null_create_func.hpp new file mode 100644 index 0000000..51470e8 --- /dev/null +++ b/include/boost/interprocess/detail/null_create_func.hpp @@ -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 +#include + +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 + +#endif //BOOST_INTERPROCESS_DETAIL_NULL_CREATION_FUNCTOR_HPP diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp new file mode 100644 index 0000000..1011a94 --- /dev/null +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -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 +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include +# else +# error Unknown platform +# endif +#endif + +#include + +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 + +#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp new file mode 100644 index 0000000..b5bca5a --- /dev/null +++ b/include/boost/interprocess/detail/utilities.hpp @@ -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 +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace interprocess { + +template +class offset_ptr; + +namespace detail { + +/*!Overload for smart pointers to avoid ADL problems with get_pointer*/ +template +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 +inline T *get_pointer(T *ptr) +{ return ptr; } + +/*!To avoid ADL problems with swap*/ +template +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 +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 +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 +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 +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 +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 +struct select1st + : public std::unary_function +{ + 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 +struct identity + : public std::unary_function +{ + 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 +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*/ +template +struct pointer_to_other; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template class Sp> +struct pointer_to_other< Sp, U > +{ + typedef Sp type; +}; + +template +struct pointer_to_other< T*, U > +{ + typedef U* type; +}; + +//Anti-exception node eraser +template +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::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 +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 +struct is_node_index +{ + enum { value = false }; +}; + +/*!Trait class to detect if an smart pointer has + multi-segment addressing capabilities.*/ +template +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 deleter +{ + public: + typedef typename detail::pointer_to_other + ::type pointer; + + private: + typedef typename detail::pointer_to_other + ::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 constant_iterator + : public boost::iterator_facade + < constant_iterator + , T + , boost::random_access_traversal_tag + , const T & + , Difference> +{ + typedef boost::iterator_facade + < constant_iterator + , T + , boost::random_access_traversal_tag + , const T & + , Difference> super_t; + + typedef constant_iterator 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 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 +InIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) +{ + for (; length--; ++dest, ++first) + *dest = *first; + return first; +} + + +template inline +typename std::iterator_traits::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::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 inline +FwdIt + uninitialized_copy(InIt first, InIt last, + FwdIt dest, Alloc& al) +{ + //Save initial destination position + FwdIt dest_init = dest; + typename std::iterator_traits::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 inline +InIt n_uninitialized_copy_n + (InIt first, + typename std::iterator_traits::difference_type count, + FwdIt dest, Alloc& al) +{ + //Save initial destination position + FwdIt dest_init = dest; + typename std::iterator_traits::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 +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 +InpIt2 uninitialized_copy_n_copy_n + (InpIt1 first1, + typename std::iterator_traits::difference_type n1, + InpIt2 first2, + typename std::iterator_traits::difference_type n2, + FwdIt result, + Alloc &alloc) +{ + typename std::iterator_traits::difference_type c1 = n1+1; + typename std::iterator_traits::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:: + difference_type c = (n1 - c1) + (n2 - c2); + for (; c--; ++dest_init){ + alloc.destroy(dest_init); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return first2; +} + +template +T max_value(const T &a, const T &b) +{ return a > b ? a : b; } + +template +T min_value(const T &a, const T &b) +{ return a < b ? a : b; } + +template +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 + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP + diff --git a/include/boost/interprocess/detail/version_type.hpp b/include/boost/interprocess/detail/version_type.hpp new file mode 100644 index 0000000..b0bc90c --- /dev/null +++ b/include/boost/interprocess/detail/version_type.hpp @@ -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 + +namespace boost{ +namespace interprocess{ +namespace detail{ + +template +struct version_type + : public boost::integral_constant +{ + typedef T type; + + version_type(const version_type&); +}; + +template +struct version + : public boost::integral_constant +{}; + +} //namespace detail{ +} //namespace interprocess{ +} //namespace boost{ +*/ + + +#include +#include + +namespace boost{ +namespace interprocess{ +namespace detail{ + +//using namespace boost; + +template +struct version_type + : public boost::integral_constant +{ + typedef T type; + + version_type(const version_type&); +}; + +namespace impl{ + +template , typename T::version>::value> +struct extract_version +{ + static const unsigned value = 1; +}; + +template +struct extract_version +{ + static const unsigned value = T::version::value; +}; + +template +struct has_version +{ + private: + struct two {char _[2];}; + template static two test(...); + template static char test(typename U::version*); + public: + static const bool value = sizeof(test(0)) == 1; +}; + +template ::value> +struct version +{ + static const unsigned value = 1; +}; + +template +struct version +{ + static const unsigned value = extract_version::value; +}; + +} //namespace impl + +template +struct version + : public boost::integral_constant::value> +{ +}; + +} //namespace detail{ +} //namespace interprocess{ +} //namespace boost{ + + +/* +#include +#include + +struct A +{ + typedef boost::interprocess::detail::version_type version; +}; + +struct B +{ + struct version {static unsigned const value = 3;}; +}; + +int main() +{ + boost::interprocess::detail:: + std::cout << boost::interprocess::detail::version::value << '\n'; + std::cout << boost::interprocess::detail::version::value << '\n'; + std::cout << boost::interprocess::detail::version::value << '\n'; +} +*/ + +#endif //#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp new file mode 100644 index 0000000..23a30f4 --- /dev/null +++ b/include/boost/interprocess/detail/workaround.hpp @@ -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 + +#include +#include +#include +#include + +#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 +#else +# include +#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 +struct random_it +: public boost::iterator +{ + typedef const T* const_pointer; + typedef const T& const_reference; +}; + +template<> struct random_it +{ + 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 +{ + 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 +{ + 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 +{ + 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 + +#endif //#ifndef BOOST_INTERPROCESS_PTR_WRKRND_HPP diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp new file mode 100644 index 0000000..2f24d6b --- /dev/null +++ b/include/boost/interprocess/errors.hpp @@ -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 +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include //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(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 + +#endif // BOOST_INTERPROCESS_ERRORS_HPP diff --git a/include/boost/interprocess/exceptions.hpp b/include/boost/interprocess/exceptions.hpp new file mode 100644 index 0000000..2cf8f12 --- /dev/null +++ b/include/boost/interprocess/exceptions.hpp @@ -0,0 +1,142 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gazta�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 +#include +#include +#include +#include + +/*!\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 + +#endif // BOOST_INTERPROCESS_EXCEPTIONS_HPP diff --git a/include/boost/interprocess/fully_mapped_file.hpp b/include/boost/interprocess/fully_mapped_file.hpp new file mode 100644 index 0000000..57053e5 --- /dev/null +++ b/include/boost/interprocess/fully_mapped_file.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include //std::auto_ptr +#include //std::fstream +#include //std::string +#include //std::remove +//#include //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 + 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 + 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 + 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 + 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 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 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 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 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 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 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(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 + +#endif //BOOST_INTERPROCESS_FULLY_MAPPED_FILE_HPP diff --git a/include/boost/interprocess/indexes/flat_map_index.hpp b/include/boost/interprocess/indexes/flat_map_index.hpp new file mode 100644 index 0000000..43e776f --- /dev/null +++ b/include/boost/interprocess/indexes/flat_map_index.hpp @@ -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 +#include + +#include +#include +#include +#include + +/*!\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 +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_less; + typedef std::pair value_type; + typedef allocator allocator_type; + typedef flat_map 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 flat_map_index + //Derive class from map specialization + : public flat_map_index_aux::index_t +{ + typedef flat_map_index_aux 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 + +#endif //#ifndef BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP diff --git a/include/boost/interprocess/indexes/map_index.hpp b/include/boost/interprocess/indexes/map_index.hpp new file mode 100644 index 0000000..80878b4 --- /dev/null +++ b/include/boost/interprocess/indexes/map_index.hpp @@ -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 +#include + +#include +#include +#include +#include + +/*!\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 +struct map_index_aux +{ + typedef typename MapConfig::key_type key_type; + typedef typename MapConfig::mapped_type mapped_type; + typedef std::less key_less; + typedef std::pair value_type; + typedef private_node_allocator + allocator_type; + typedef boost::interprocess::map 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 map_index + //Derive class from map specialization + : public map_index_aux::index_t +{ + typedef map_index_aux 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 +struct is_node_index + > +{ + enum { value = true }; +}; + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MAP_INDEX_HPP diff --git a/include/boost/interprocess/indexes/null_index.hpp b/include/boost/interprocess/indexes/null_index.hpp new file mode 100644 index 0000000..9903ecf --- /dev/null +++ b/include/boost/interprocess/indexes/null_index.hpp @@ -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 +#include + +#include + +/*!\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 null_index +{ + typedef typename MapConfig::segment_manager segment_manager; + + public: + + /*!Dummy function*/ + null_index(segment_manager *segment_mngr_hdr){} + +}; + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_NULL_INDEX_HPP diff --git a/include/boost/interprocess/indexes/unordered_map_index.hpp b/include/boost/interprocess/indexes/unordered_map_index.hpp new file mode 100644 index 0000000..e95c4f8 --- /dev/null +++ b/include/boost/interprocess/indexes/unordered_map_index.hpp @@ -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 +#include + +#include +#include +#include +#include +#include + +/*!\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 +struct unordered_map_index_aux +{ + typedef typename MapConfig::key_type key_type; + typedef typename MapConfig::mapped_type mapped_type; + typedef std::equal_to key_equal; + typedef std::pair value_type; + typedef private_node_allocator + allocator_type; + struct hasher + : std::unary_function + { + 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 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 unordered_map_index + //Derive class from unordered_map specialization + : public unordered_map_index_aux::index_t +{ + typedef unordered_map_index_aux 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 +struct is_node_index + > +{ + enum { value = true }; +}; + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp new file mode 100644 index 0000000..a162218 --- /dev/null +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -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 +#include + +#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) +// old Dinkumware +# include +#else +# include +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +namespace std { + +template +class allocator; + +template +struct less; + +template +struct pair; + +template +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 scoped_lock; + +template +class sharable_lock; + +////////////////////////////////////////////////////////////////////////////// +// STL compatible allocators +////////////////////////////////////////////////////////////////////////////// + +template +class allocator; + +template +class node_allocator; + +template +class private_node_allocator; + +template +class cached_node_allocator; + +////////////////////////////////////////////////////////////////////////////// +// offset_ptr +////////////////////////////////////////////////////////////////////////////// + +template +class offset_ptr; + +////////////////////////////////////////////////////////////////////////////// +// intersegment_ptr +////////////////////////////////////////////////////////////////////////////// + +template +struct flat_map_intersegment; + +template */> +class intersegment_ptr; + +////////////////////////////////////////////////////////////////////////////// +// Memory allocation algorithms +////////////////////////////////////////////////////////////////////////////// + +//Single segment memory allocation algorithms +template > +class seq_fit; + +template > +class simple_seq_fit; + +//Single segment memory allocation algorithms +template > +class multi_seq_fit; + +template > +class multi_simple_seq_fit; + +////////////////////////////////////////////////////////////////////////////// +// Index Types +////////////////////////////////////////////////////////////////////////////// + +template class flat_map_index; +template class map_index; +template class null_index; + +////////////////////////////////////////////////////////////////////////////// +// Segment manager +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class segment_manager; + +////////////////////////////////////////////////////////////////////////////// +// External buffer front-ends +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class basic_managed_external_buffer; + +typedef basic_managed_external_buffer + + ,flat_map_index> +managed_external_buffer; + +typedef basic_managed_external_buffer + + ,flat_map_index> +wmanaged_external_buffer; + +////////////////////////////////////////////////////////////////////////////// +// Shared memory front-ends +////////////////////////////////////////////////////////////////////////////// + +template class IndexType> +class basic_managed_shared_memory; + +typedef basic_managed_shared_memory + + ,flat_map_index> +managed_shared_memory; + +typedef basic_managed_shared_memory + + ,flat_map_index> +wmanaged_shared_memory; + +////////////////////////////////////////////////////////////////////////////// +// Fixed address shared memory +////////////////////////////////////////////////////////////////////////////// + +typedef basic_managed_shared_memory + + ,flat_map_index> +fixed_managed_shared_memory; + +typedef basic_managed_shared_memory + + ,flat_map_index> +wfixed_managed_shared_memory; + +////////////////////////////////////////////////////////////////////////////// +// Heap memory front-ends +////////////////////////////////////////////////////////////////////////////// + +template + class IndexType> +class basic_managed_heap_memory; + +typedef basic_managed_heap_memory + + ,flat_map_index> +managed_heap_memory; + +typedef basic_managed_heap_memory + + ,flat_map_index> +wmanaged_heap_memory; + +////////////////////////////////////////////////////////////////////////////// +// Mapped file front-ends +////////////////////////////////////////////////////////////////////////////// + +template + class IndexType> +class basic_managed_mapped_file; + +typedef basic_managed_mapped_file + + ,flat_map_index> +managed_mapped_file; + +typedef basic_managed_mapped_file + + ,flat_map_index> +wmanaged_mapped_file; + +////////////////////////////////////////////////////////////////////////////// +// Exceptions +////////////////////////////////////////////////////////////////////////////// + +class interprocess_exception; +class lock_exception; +class bad_alloc; + +////////////////////////////////////////////////////////////////////////////// +// Bufferstream +////////////////////////////////////////////////////////////////////////////// + +//bufferstream +template > +class basic_bufferbuf; + +template > +class basic_ibufferstream; + +template > +class basic_obufferstream; + +template > +class basic_bufferstream; + +////////////////////////////////////////////////////////////////////////////// +// Vectorstream +////////////////////////////////////////////////////////////////////////////// + +template > +class basic_vectorbuf; + +template > +class basic_ivectorstream; + +template > +class basic_ovectorstream; + +template > +class basic_vectorstream; + +////////////////////////////////////////////////////////////////////////////// +// Smart pointers +////////////////////////////////////////////////////////////////////////////// + +template +class scoped_ptr; + +template +class intrusive_ptr; + +////////////////////////////////////////////////////////////////////////////// +// IPC +////////////////////////////////////////////////////////////////////////////// + +class message_queue; + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +//vector class +template > +class vector; + +//list class +template > +class list; + +//slist class +template > +class slist; + +//set class +template + ,class Alloc = std::allocator > +class set; + +//multiset class +template + ,class Alloc = std::allocator > +class multiset; + +//map class +template + ,class Alloc = std::allocator > > +class map; + +//multimap class +template + ,class Alloc = std::allocator > > +class multimap; + +//flat_set class +template + ,class Alloc = std::allocator > +class flat_set; + +//flat_multiset class +template + ,class Alloc = std::allocator > +class flat_multiset; + +//flat_map class +template + ,class Alloc = std::allocator > > +class flat_map; + +//flat_multimap class +template + ,class Alloc = std::allocator > > +class flat_multimap; + +//basic_string class +template + ,class Alloc = std::allocator > +class basic_string; + +//string class +typedef basic_string + + ,std::allocator > +string; + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP + diff --git a/include/boost/interprocess/intersegment_ptr.hpp b/include/boost/interprocess/intersegment_ptr.hpp new file mode 100644 index 0000000..a008c28 --- /dev/null +++ b/include/boost/interprocess/intersegment_ptr.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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 +struct flat_map_intersegment +{ + typedef flat_map_intersegment 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 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 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 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 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 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 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 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 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 insert_ret; + std::size_t group = 0; + + BOOST_TRY{ + //------------------------------------------------------------------ + boost::interprocess::scoped_lock 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 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_ret_t; + typedef std::pair 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 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 + 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 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 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 + > ptr_to_segment_t; + /*!Maps segment group/id with base addresses*/ + typedef boost::interprocess::flat_map + 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 + 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 +typename flat_map_intersegment::mappings_t + flat_map_intersegment::s_map; + +/*!Static constant that shows the number of bits to shift to obtain the + group part of segment_t type*/ +template +const std::size_t flat_map_intersegment::s_shift; + +/*!Static constant that shows the number of bits to shift to obtain the + group part of segment_t type*/ +template +const std::size_t flat_map_intersegment::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 intersegment_ptr : public flat_map_intersegment //: public PT +{ + typedef flat_map_intersegment PT; + typedef boost::interprocess::workaround::random_it random_it_t; +// typedef intersegment_ptr self_t; + typedef intersegment_ptr 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 + 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 + intersegment_ptr(const intersegment_ptr &ptr) + { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } + + /*!Emulates static_cast operator. Never throws. */ + template + intersegment_ptr(const intersegment_ptr &r, detail::static_cast_tag) + //{ base_t::set_from_pointer(static_cast(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(this); + std::ptrdiff_t difference = detail::char_ptr_cast(static_cast(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 + intersegment_ptr(const intersegment_ptr &r, detail::const_cast_tag) + { base_t::set_from_pointer(const_cast(r.get())); } + /* + { + //Make sure const conversion is correct + pointer p = const_cast((U*)0); (void)p; + base_t::set_from_other(r); + }*/ + + /*!Emulates dynamic_cast operator. Never throws.*/ + template + intersegment_ptr(const intersegment_ptr &r, detail::dynamic_cast_tag) + { base_t::set_from_pointer(dynamic_cast(r.get())); } + + /*!Emulates reinterpret_cast operator. Never throws.*/ + template + intersegment_ptr(const intersegment_ptr &r, detail::reinterpret_cast_tag) + { base_t::set_from_pointer(reinterpret_cast(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 + intersegment_ptr& operator= (const intersegment_ptr & 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 + bool _diff(const intersegment_ptr &other) const + { return base_t::less(other); } + + /*!Returns true if both point to the same object*/ + template + bool _equal(const intersegment_ptr &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 + bool _less(const intersegment_ptr &other) const + { return base_t::less(other); } +}; + +/*!Compares the equality of two intersegment_ptr-s. + Never throws.*/ +template inline +bool operator ==(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) == + typename intersegment_ptr::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 inline +bool operator <(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) < + typename intersegment_ptr::pointer(0); + (void)e; + return left._less(right); +} + +template inline +bool operator!= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 ==pt2); } + +/*!intersegment_ptr <= intersegment_ptr. Never throws.*/ +template inline +bool operator<= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 > pt2); } + +/*!intersegment_ptr > intersegment_ptr. Never throws.*/ +template inline +bool operator> (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return (pt2 < pt1); } + +/*!intersegment_ptr >= intersegment_ptr. Never throws.*/ +template inline +bool operator>= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 < pt2); } + +/*!operator<< */ +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, const intersegment_ptr & p) +{ return os << p.get(); } + +/*!operator>> */ +template inline +std::basic_istream & operator>> + (std::basic_istream & os, intersegment_ptr & p) +{ U * tmp; return os >> tmp; p = tmp; } + +/*!std::ptrdiff_t + intersegment_ptr. + The result is another pointer of the same segment */ +template inline +intersegment_ptr operator+ + (std::ptrdiff_t diff, const intersegment_ptr& right) +{ return right + diff; } + +/*!intersegment_ptr - intersegment_ptr. + This only works with two intersegment_ptr-s that point to the + same segment*/ +template inline +std::ptrdiff_t operator- (const intersegment_ptr &pt, + const intersegment_ptr &pt2) +{ return pt._diff(pt2); } + +/*! swap specialization */ +template inline +void swap (boost::interprocess::intersegment_ptr &pt, + boost::interprocess::intersegment_ptr &pt2) +{ pt.swap(pt2); } + +/*!get_pointer() enables boost::mem_fn to recognize intersegment_ptr. + Never throws.*/ +template inline +T * get_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } + +/*!Simulation of static_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr static_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::static_cast_tag()); } + +/*!Simulation of const_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr const_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::const_cast_tag()); } + +/*!Simulation of dynamic_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr dynamic_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::dynamic_cast_tag()); } + +/*!Simulation of reinterpret_cast between pointers. Never throws.*/ +template inline +boost::interprocess::intersegment_ptr reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::reinterpret_cast_tag()); } + +/*!Trait class to detect if an smart pointer has + multi-segment addressing capabilities.*/ +template +struct is_multisegment_ptr + > +{ + enum { value = true }; +}; + +} //namespace interprocess { + + +/*!has_trivial_constructor<> == true_type specialization for optimizations*/ +template +struct has_trivial_constructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +/*!has_trivial_destructor<> == true_type specialization for optimizations*/ +template +struct has_trivial_destructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERSEGMENT_PTR_HPP + diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp new file mode 100644 index 0000000..cf20737 --- /dev/null +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include //std::lower_bound +#include //std::size_t +#include //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 &msg1, + const offset_ptr &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 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_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(*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::value, + index_align = boost::alignment_of::value, + r_hdr_size = detail::ct_rounded_size::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::value, + index_align = boost::alignment_of::value, + r_hdr_size = detail::ct_rounded_size::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 + (detail::char_ptr_cast(this)+r_hdr_size); + + //Pointer to the first message header + msg_hdr_t *msg_hdr = reinterpret_cast + (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 + (detail::char_ptr_cast(msg_hdr)+r_max_msg_size); + } + } + + public: + //Pointer to the index + offset_ptr 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(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(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 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(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 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(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(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 + +#endif //#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP diff --git a/include/boost/interprocess/ipc/named_fifo.hpp b/include/boost/interprocess/ipc/named_fifo.hpp new file mode 100644 index 0000000..3e8230d --- /dev/null +++ b/include/boost/interprocess/ipc/named_fifo.hpp @@ -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 +#include + +//TO-DO + +#include + +#endif //#ifndef BOOST_NAMED_FIFO_HPP \ No newline at end of file diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp new file mode 100644 index 0000000..1690d89 --- /dev/null +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -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 +#include + +#include +#include //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*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_external_buffer + : public detail::basic_managed_memory_impl +{ + typedef detail::basic_managed_memory_impl + 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 + +#endif //BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP + diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp new file mode 100644 index 0000000..9d4d285 --- /dev/null +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -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 +#include +#include +#include +#include +#include + +/*!\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 &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 &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*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_heap_memory + : public detail::basic_managed_memory_impl +{ + private: + + typedef detail::basic_managed_memory_impl + 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 + 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 + bool create_from_file (const CharT *filename, const char *mem_name, + const void *addr = 0) + { + std::basic_ifstream< CharT, std::char_traits > + 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(&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().swap(m_heapmem); + } + + std::vector m_heapmem; +}; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP + diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp new file mode 100644 index 0000000..0d1d8ef --- /dev/null +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -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 +#include +#include +#include +#include +#include + +/*!\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*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_mapped_file + : public detail::basic_managed_memory_impl + +{ + private: + + typedef detail::basic_managed_memory_impl + 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(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(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 + +#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP + diff --git a/include/boost/interprocess/managed_multi_shared_memory.hpp b/include/boost/interprocess/managed_multi_shared_memory.hpp new file mode 100644 index 0000000..51d5d6a --- /dev/null +++ b/include/boost/interprocess/managed_multi_shared_memory.hpp @@ -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 +#include + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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*/ +template + < + class CharType, + class MemoryAlgorithm, + template class IndexType + > +class basic_managed_multi_shared_memory + : public detail::basic_managed_memory_impl + +{ + + typedef basic_managed_multi_shared_memory + 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 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 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 + 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 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(&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 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(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 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 + 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 + +#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp new file mode 100644 index 0000000..ec98fc1 --- /dev/null +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -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 +#include + +#include +#include +#include + +/*!\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*/ +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +class basic_managed_shared_memory + : public detail::basic_managed_memory_impl +{ + //////////////////////////////////////////////////////////////////////// + // + // 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 + 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 + 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 + +#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP + diff --git a/include/boost/interprocess/mapped_file.hpp b/include/boost/interprocess/mapped_file.hpp new file mode 100644 index 0000000..7f7728e --- /dev/null +++ b/include/boost/interprocess/mapped_file.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include //std::auto_ptr +#include //std::fstream +#include //std::string +#include //std::remove +#include + +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include //mmap, off64_t +# include +# include +# 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 + 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 + 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 + 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 + 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 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 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 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 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 + +#endif //BOOST_INTERPROCESS_MAPPED_FILE_HPP + diff --git a/include/boost/interprocess/mem_algo/Attic/multi_simple_seq_fit.hpp b/include/boost/interprocess/mem_algo/Attic/multi_simple_seq_fit.hpp new file mode 100644 index 0000000..5c84a32 --- /dev/null +++ b/include/boost/interprocess/mem_algo/Attic/multi_simple_seq_fit.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 +#include + +#include +#include +#include + +/*!\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 multi_simple_seq_fit + : public detail::simple_seq_fit_impl +{ + typedef detail::simple_seq_fit_impl 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 + +#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP + diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp new file mode 100644 index 0000000..fd1237c --- /dev/null +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*!\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 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::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 + (detail::char_ptr_cast(addr) - BlockCtrlBytes); + } + + void *get_addr() const + { + return reinterpret_cast + (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 + 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 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 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::pairpriv_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::value }; + enum { BlockCtrlBytes = detail::ct_rounded_size::value }; + enum { BlockCtrlSize = BlockCtrlBytes/Alignment }; + enum { MinBlockSize = BlockCtrlSize + Alignment }; +}; + +template +inline simple_seq_fit_impl:: + 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 + (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 +inline simple_seq_fit_impl::~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 +inline void simple_seq_fit_impl::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 + (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 +inline void simple_seq_fit_impl::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(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 +inline std::size_t simple_seq_fit_impl::get_size() const + { return m_header.m_size; } + +template +inline std::size_t simple_seq_fit_impl:: + 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 +inline bool simple_seq_fit_impl:: + all_memory_deallocated() +{ + //----------------------- + boost::interprocess::scoped_lock 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 +inline bool simple_seq_fit_impl:: + check_sanity() +{ + //----------------------- + boost::interprocess::scoped_lock 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 +inline void* simple_seq_fit_impl:: + allocate(std::size_t nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + std::size_t ignore; + return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; +} + +template +inline std::pair simple_seq_fit_impl:: + 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 guard(m_header); + //----------------------- + return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr); +} + +template +inline std::size_t simple_seq_fit_impl:: + 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 + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + return block->m_size*Alignment - BlockCtrlBytes; +} + +template +inline void* simple_seq_fit_impl:: + multi_allocate(std::size_t nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock 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 + (void_pointer::find_group_data(group)); + assert(p_services); + std::pair 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 +void* simple_seq_fit_impl:: + 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 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 + (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 +std::pair simple_seq_fit_impl:: + 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 ((success ? reuse_ptr : 0), true); + } + typedef std::pair 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 +inline typename simple_seq_fit_impl::block_ctrl * + simple_seq_fit_impl:: + priv_next_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + //Take the address where the next block should go + block_ctrl *next_block = reinterpret_cast + (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 +inline + std::pair::block_ctrl * + ,typename simple_seq_fit_impl::block_ctrl *> + simple_seq_fit_impl:: + priv_prev_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + typedef std::pair 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 +inline bool simple_seq_fit_impl:: + 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 + (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 +inline bool simple_seq_fit_impl:: + 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 + (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 + (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 inline +void* simple_seq_fit_impl::priv_check_and_allocate + (std::size_t nunits + ,typename simple_seq_fit_impl::block_ctrl* prev + ,typename simple_seq_fit_impl::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 + (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 +void simple_seq_fit_impl::deallocate(void* addr) +{ + if(!addr) return; + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return this->priv_deallocate(addr); +} + +template +void simple_seq_fit_impl::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 + (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 + +#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP + diff --git a/include/boost/interprocess/mem_algo/multi_simple_seq_fit.hpp b/include/boost/interprocess/mem_algo/multi_simple_seq_fit.hpp new file mode 100644 index 0000000..5c84a32 --- /dev/null +++ b/include/boost/interprocess/mem_algo/multi_simple_seq_fit.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 +#include + +#include +#include +#include + +/*!\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 multi_simple_seq_fit + : public detail::simple_seq_fit_impl +{ + typedef detail::simple_seq_fit_impl 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 + +#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP + diff --git a/include/boost/interprocess/mem_algo/simple_seq_fit.hpp b/include/boost/interprocess/mem_algo/simple_seq_fit.hpp new file mode 100644 index 0000000..72c8afd --- /dev/null +++ b/include/boost/interprocess/mem_algo/simple_seq_fit.hpp @@ -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 +#include + +#include +#include +#include + +/*!\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 simple_seq_fit + : public detail::simple_seq_fit_impl +{ + typedef detail::simple_seq_fit_impl 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 + +#endif //#ifndef BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP + diff --git a/include/boost/interprocess/memory_mapping.hpp b/include/boost/interprocess/memory_mapping.hpp new file mode 100644 index 0000000..33926ab --- /dev/null +++ b/include/boost/interprocess/memory_mapping.hpp @@ -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 +#include + +#include +#include +#include +#include + +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else +# ifdef BOOST_HAS_UNISTD_H +# include +# include //mmap, off64_t +# include +# include +# 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(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(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(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(m_base)+mapping_offset, + static_cast(numbytes)); +} + +inline void mapped_region::priv_close() +{ + if(m_base){ + this->flush(); + winapi::unmap_view_of_file(reinterpret_cast(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(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 + +#endif //BOOST_INTERPROCESS_MEMORY_MAPPING_HPP + diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp new file mode 100644 index 0000000..7cbdf04 --- /dev/null +++ b/include/boost/interprocess/offset_ptr.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include + +/*!\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 offset_ptr +{ + typedef boost::interprocess::workaround::random_it random_it_t; + typedef offset_ptr 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 + 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 + offset_ptr(const offset_ptr &ptr) + { pointer p(ptr.get()); (void)p; this->set_offset(ptr.get()); } + + /*!Emulates static_cast operator. Never throws. */ + template + offset_ptr(const offset_ptr & r, detail::static_cast_tag) + { this->set_offset(static_cast(r.get())); } + + /*!Emulates const_cast operator. Never throws.*/ + template + offset_ptr(const offset_ptr & r, detail::const_cast_tag) + { this->set_offset(const_cast(r.get())); } + + /*!Emulates dynamic_cast operator. Never throws.*/ + template + offset_ptr(const offset_ptr & r, detail::dynamic_cast_tag) + { this->set_offset(dynamic_cast(r.get())); } + + /*!Emulates reinterpret_cast operator. Never throws.*/ + template + offset_ptr(const offset_ptr & r, detail::reinterpret_cast_tag) + { this->set_offset(reinterpret_cast(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 + offset_ptr& operator= (const offset_ptr & 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 == offset_ptr. Never throws.*/ +template +inline bool operator== (const offset_ptr &pt1, + const offset_ptr &pt2) +{ return pt1.get() == pt2.get(); } + +/*!offset_ptr != offset_ptr. Never throws.*/ +template +inline bool operator!= (const offset_ptr &pt1, + const offset_ptr &pt2) +{ return pt1.get() != pt2.get(); } + +/*!offset_ptr < offset_ptr. Never throws.*/ +template +inline bool operator< (const offset_ptr &pt1, + const offset_ptr &pt2) +{ return pt1.get() < pt2.get(); } + +/*!offset_ptr <= offset_ptr. Never throws.*/ +template +inline bool operator<= (const offset_ptr &pt1, + const offset_ptr &pt2) +{ return pt1.get() <= pt2.get(); } + +/*!offset_ptr > offset_ptr. Never throws.*/ +template +inline bool operator> (const offset_ptr &pt1, + const offset_ptr &pt2) +{ return pt1.get() > pt2.get(); } + +/*!offset_ptr >= offset_ptr. Never throws.*/ +template +inline bool operator>= (const offset_ptr &pt1, + const offset_ptr &pt2) +{ return pt1.get() >= pt2.get(); } + +/*!operator<< */ +template +inline std::basic_ostream & operator<< + (std::basic_ostream & os, offset_ptr const & p) +{ return os << p.get(); } + +/*!operator>> */ +template +inline std::basic_istream & operator>> + (std::basic_istream & os, offset_ptr & p) +{ Y * tmp; return os >> tmp; p = tmp; } + +/*!std::ptrdiff_t + offset_ptr */ +template +inline offset_ptr operator+(std::ptrdiff_t diff, const offset_ptr& right) +{ return right + diff; } + +/*!offset_ptr - offset_ptr */ +template +inline std::ptrdiff_t operator- (const offset_ptr &pt, const offset_ptr &pt2) +{ return pt.get()- pt2.get(); } + +/*!swap specialization */ +template +inline void swap (boost::interprocess::offset_ptr &pt, + boost::interprocess::offset_ptr &pt2) +{ + typename offset_ptr::value_type *ptr = pt.get(); + pt = pt2; + pt2 = ptr; +} + +/*!get_pointer() enables boost::mem_fn to recognize offset_ptr. + Never throws.*/ +template +inline T * get_pointer(boost::interprocess::offset_ptr const & p) +{ return p.get(); } + +/*!Simulation of static_cast between pointers. Never throws.*/ +template +inline boost::interprocess::offset_ptr + static_pointer_cast(boost::interprocess::offset_ptr const & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::detail::static_cast_tag()); +} + +/*!Simulation of const_cast between pointers. Never throws.*/ +template +inline boost::interprocess::offset_ptr + const_pointer_cast(boost::interprocess::offset_ptr const & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::detail::const_cast_tag()); +} + +/*!Simulation of dynamic_cast between pointers. Never throws.*/ +template +inline boost::interprocess::offset_ptr + dynamic_pointer_cast(boost::interprocess::offset_ptr const & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::detail::dynamic_cast_tag()); +} + +/*!Simulation of reinterpret_cast between pointers. Never throws.*/ +template +inline boost::interprocess::offset_ptr + reinterpret_pointer_cast(boost::interprocess::offset_ptr const & r) +{ + return boost::interprocess::offset_ptr + (r, boost::interprocess::detail::reinterpret_cast_tag()); +} + +} //namespace interprocess { + +/*!has_trivial_constructor<> == true_type specialization for optimizations*/ +template +struct has_trivial_constructor + < boost::interprocess::offset_ptr > + : public true_type +{}; + +/*!has_trivial_destructor<> == true_type specialization for optimizations*/ +template +struct has_trivial_destructor + < boost::interprocess::offset_ptr > + : public true_type +{}; + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_OFFSET_PTR_HPP + diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp new file mode 100644 index 0000000..1db55e2 --- /dev/null +++ b/include/boost/interprocess/segment_manager.hpp @@ -0,0 +1,1117 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_OBJECT_ALGO_HPP +#define BOOST_INTERPROCESS_NAMED_OBJECT_ALGO_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +/*!\file + Describes the object placed in a memory segment that provides + named object allocation capabilities for single-segment and + multi-segment allocations. +*/ + +namespace boost{ namespace interprocess { + +/*!An integer that describes the type of the instance constructed in memory*/ +enum InstanceType { anonymous_type = 0, named_type = 1, unique_type = 2 }; + +namespace detail{ + +/*! + This struct indicates an anonymous object creation allocation +*/ +class anonymous_instance_t +{ + private: + anonymous_instance_t(){} +}; + +/*! + This struct indicates an unique type indexed instance allocation +*/ +class unique_instance_t +{ + private: + unique_instance_t(){} +}; + +} //namespace detail{ + +//These pointers are the ones the user will use to +//indicate previous allocation types +static const detail::anonymous_instance_t *anonymous_instance; +static const detail::unique_instance_t *unique_instance; + +}} //namespace boost{ namespace interprocess{ + +namespace boost { namespace interprocess { namespace detail { + +/*!The key of the the named allocation information index. Stores an offset pointer + to a null terminated string and the length of the string to speed up sorting*/ +template +struct index_key +{ + typedef typename detail:: + pointer_to_other::type const_char_ptr_t; + typedef CharT char_type; + + //Offset pointer to the object's name + const_char_ptr_t mp_str; + //Length of the name buffer (null NOT included) + std::size_t m_len; + + /*!Constructor of the key*/ + index_key (const char_type *name, std::size_t length) + : mp_str(name), m_len(length) {} + + /*!Less than function for index ordering*/ + bool operator < (const index_key & right) const + { + detail::get_pointer(mp_str); + return (m_len < right.m_len) || + (m_len == right.m_len && + std::char_traits::compare + (detail::get_pointer(mp_str), + detail::get_pointer(right.mp_str), m_len) < 0); + } + + /*!Equal to function for index ordering*/ + bool operator == (const index_key & right) const + { + return m_len == right.m_len && + std::char_traits::compare + (detail::get_pointer(mp_str), + detail::get_pointer(right.mp_str), m_len) == 0; + } +}; + +/*!The index_data stores a pointer to a buffer and the element count needed + to know how many destructors must be called when calling destroy*/ +template +struct index_data +{ + typedef VoidPointer void_ptr; + void_ptr m_ptr; + index_data(void *ptr) : m_ptr(ptr){} +}; + + +template +struct alloc_info_t +{ + public: + std::size_t m_sizeof_type; + std::size_t m_num; + std::size_t m_allocation_type; + + static std::size_t get_offset() + { return ct_rounded_size), sizeof(T)>::value; } + + static T *get_data_from_info(const void *info) + { + return reinterpret_cast + (detail::char_ptr_cast(info) + get_offset()); + } + + static alloc_info_t *get_info_from_data(const void *data) + { + return reinterpret_cast + (detail::char_ptr_cast(data) - get_offset()); + } + + inline T* get_data() const + { + return reinterpret_cast + (detail::char_ptr_cast(this) + get_offset()); + } +}; + +template +struct alloc_name_t +{ + It m_it; + CharType m_name; + + static std::size_t get_name_offset() + { + //gcc does not like 0 to be used to this + return char_ptr_cast(&((alloc_name_t*)sizeof(alloc_name_t))->m_name) - + char_ptr_cast(&((alloc_name_t*)sizeof(alloc_name_t))->m_it); + } + CharType *get_name() + { return &m_name; } + It &get_it() + { return m_it; } +}; + +template +struct alloc_name_t +{ + CharType m_name; + + static std::size_t get_name_offset() + { return 0; } + CharType *get_name() + { return &m_name; } + It &get_it() + { static It m_it; return m_it; } +}; + +template +struct get_construct_name; + +template +struct get_construct_name +{ + static const OutPtr *get(const OutPtr *name) + { return name; } +}; + +template +struct get_construct_name +{ + static const OutPtr *get(const anonymous_instance_t *name) + { return reinterpret_cast(0); } +}; + +template +struct get_construct_name +{ + static const OutPtr *get(const unique_instance_t *name) + { return reinterpret_cast(-1); } +}; + +} //namespace detail { + +/*! + This object is placed in the beginning of memory segment and + implements the allocation (named or anonymous) of portions + of the segment. This object contains two indexes that + maintain an association between a name and a portion of the segment. + + The first index contains the mappings for normal named objects using the + char type specified in the template parameter. + + The second index contains the association for unique instances. The key will + be the const char * returned from type_info.name() function for the unique + type to be constructed. +*/ +template class IndexType> +class segment_manager : private MemoryAlgorithm +{ + public: + typedef typename MemoryAlgorithm::void_pointer void_pointer; + + private: + template + struct index_config + { + typedef detail::index_key key_type; + typedef detail::index_data mapped_type; + typedef segment_manager + segment_manager; + }; + + template + struct index_traits + { + typedef typename segment_manager:: + template index_config index_config_t; + typedef IndexType index_type; + typedef typename index_type::iterator index_it; + typedef std::pair index_ib; + typedef typename index_type::key_type key_type; + typedef typename index_type::mapped_type mapped_type; + typedef typename index_type::value_type value_type; + }; + + typedef IndexType > named_index_t; + typedef IndexType > unique_index_t; + + struct raw_deleter_t + { + typedef void * pointer; + + raw_deleter_t(segment_manager &mngr) + : m_mngr(mngr){} + void operator()(pointer p) + { m_mngr.deallocate(p); } + private: + segment_manager &m_mngr; + }; + + public: + class char_ptr_holder_t + { + public: + char_ptr_holder_t(const CharType *name) + : m_name(detail::get_construct_name::get(name)){} + + char_ptr_holder_t(const detail::anonymous_instance_t *name) + : m_name(detail::get_construct_name::get(name)){} + + char_ptr_holder_t(const detail::unique_instance_t *name) + : m_name(detail::get_construct_name::get(name)){} + + operator const CharType *() + { return m_name; } + private: + const CharType *m_name; + }; + + typedef typename MemoryAlgorithm::mutex_family mutex_family; + + /*!Constructor proxy object definition helper class*/ + template + struct construct_proxy + { + typedef detail::named_proxy type; + }; + /*!Find or construct proxy object definition helper class*/ + template + struct find_construct_proxy + { + typedef detail::named_proxy type; + }; + + /*!Constructor proxy object definition helper class*/ + template + struct construct_iter_proxy + { + typedef detail::named_proxy type; + }; + /*!Find or construct proxy object definition helper class*/ + template + struct find_construct_iter_proxy + { + typedef detail::named_proxy type; + }; + + /*!Constructor. Can throw*/ + segment_manager(std::size_t size ) + : MemoryAlgorithm(size, get_reserved_bytes()), + m_header(get_this_pointer()) + { (void) anonymous_instance; (void) unique_instance; } + + /*!Returns the size of the memory segment*/ + std::size_t get_size() const + { return MemoryAlgorithm::get_size(); } + + /*!Obtains the minimum size needed by the segment manager*/ + static std::size_t get_min_size () + { return MemoryAlgorithm::get_min_size(sizeof(segment_manager)-sizeof(MemoryAlgorithm)); } + + /*!Tries to find a previous named allocation address. Returns a memory + buffer and the object count. */ + template + std::pair find (const CharType* name) + { + //The name can't be null, no anonymous object can be found by name + assert(name != 0); + if(name == reinterpret_cast(-1)){ + return priv_generic_find (typeid(T).name(), m_header.m_unique_index); + } + else{ + return priv_generic_find (name, m_header.m_named_index); + } + } + + template + std::pair find (const detail::unique_instance_t* name) + { return priv_generic_find (name, m_header.m_unique_index); } + + /*!Returns throwing "construct" proxy object*/ + template + typename construct_proxy::type + construct(char_ptr_holder_t name) + { return typename construct_proxy::type (name, this); } + + /*!Returns throwing "search or construct" proxy object*/ + template + typename find_construct_proxy::type find_or_construct(char_ptr_holder_t name) + { return typename find_construct_proxy::type(name, this); } + + /*!Returns no throwing "construct" proxy object*/ + template + typename construct_proxy::type + construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return typename construct_proxy::type (name, this); } + + /*!Returns no throwing "search or construct" proxy object*/ + template + typename find_construct_proxy::type + find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow) + { return typename find_construct_proxy::type (name, this); } + + /*!Returns throwing "construct from iterators" proxy object*/ + template + typename construct_iter_proxy::type + construct_it(char_ptr_holder_t name) + { return typename construct_iter_proxy::type (name, this); } + + /*!Returns throwing "search or construct from iterators" proxy object*/ + template + typename find_construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name) + { return typename find_construct_iter_proxy::type(name, this); } + + /*!Returns no throwing "construct from iterators" proxy object*/ + template + typename construct_iter_proxy::type + construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return typename construct_iter_proxy::type (name, this); } + + /*!Returns no throwing "search or construct from iterators" proxy object*/ + template + typename find_construct_iter_proxy::type + find_or_construct_it(char_ptr_holder_t name, std::nothrow_t nothrow) + { return typename find_construct_iter_proxy::type (name, this); } + + /*!Calls object function blocking recursive interprocess_mutex and guarantees that + no new named_alloc or destroy will be executed by any process while + executing the object function call*/ + template + void atomic_func(Func &f) + { boost::interprocess::scoped_lock guard(m_header); f(); } + + /*!Calls the destructor and makes an unique deallocate*/ + template + bool destroy(const detail::unique_instance_t *) + { + return this->priv_generic_named_destroy + (typeid(T).name(), m_header.m_unique_index); + } + + template + bool destroy(const CharType *name) + { + return this->priv_generic_named_destroy + (name, m_header.m_named_index); + } + + template + bool destroy_ptr(const T *ptr) + { + //Allow void pointer deletion instantiation to be able to + //construct void shared_ptrs + //If we call the destroy_ptr(const void *), the function will return 0 + typedef typename boost::mpl::if_c::value, + char, T>::type data_t; + return priv_destroy_ptr((const data_t*)ptr); + } + + /*!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc when + it can allocate*/ + void* allocate(std::size_t nbytes) + { + void * ret = this->allocate(nbytes, std::nothrow_t()); + if(!ret) + throw bad_alloc(); + return ret; + } + + /*!Allocates nbytes bytes. This function is only used in + single-segment management. Never throws*/ + void* allocate (std::size_t nbytes, std::nothrow_t) + { return MemoryAlgorithm::allocate(nbytes); } + + /*!It will try to allocate a buffer of preferred_size or more. + It it can't do that, it will try to allocate at least + min_size bytes. Throws boost::interprocess::bad_alloc when + it can't allocate*/ +/* + std::pair allocate_at_least + (std::size_t min_size, + std::size_t preferred_size, std::size_t &received_size, void *reuse = 0) + { + std::pair ret = this->allocate_at_least + (min_size, preferred_size, received_size, std::nothrow_t(), reuse); + if(!ret.first) + throw bad_alloc(); + return ret; + } +*/ + std::pair + allocation_command (allocation_type command, std::size_t limit_size, + std::size_t preferred_size,std::size_t &received_size, + void *reuse_ptr = 0) + { + std::pair ret = MemoryAlgorithm::allocation_command + ( command | nothrow_allocation, limit_size, preferred_size, received_size + , reuse_ptr); + if(!(command & nothrow_allocation) && !ret.first) + throw bad_alloc(); + return ret; + } +/* + std::pair + allocation_command (allocation_type command, std::size_t min_size, + std::size_t preferred_size,std::size_t &received_size, + std::nothrow_t, void *reuse_ptr = 0) + { + return MemoryAlgorithm::allocation_command + (command, min_size, preferred_size, received_size, reuse_ptr); + } +*/ + + /*!It will try to allocate a buffer of preferred_size or more. + It it can't do that, it will try to allocate at least + min_size bytes. Return 0 when it can't allocate*/ +/* + std::pair allocate_at_least(std::size_t min_size, std::size_t preferred_size, + std::size_t &received_size, std::nothrow_t, void *reuse = 0) + { return MemoryAlgorithm::allocate_at_least(min_size, preferred_size, received_size, reuse); } +*/ + /*!Returns true if the buffer pointed by ptr can be expanded + to preferred_size or more. If not it will try to expand it + at least min_size. Otherwise, returns false*/ +/* + bool expand(void *ptr, + std::size_t min_size, std::size_t preferred_size, + std::size_t &received_size) + { return MemoryAlgorithm::expand(ptr, min_size, preferred_size, received_size); } +*/ + /*!Returns true if the buffer pointed by ptr can be shrunk + to preferred_size. If not it will try to shrink it + at least between max_size and preferred_size. Otherwise, returns false*/ +/* + bool shrink(void *ptr, + std::size_t max_size, std::size_t preferred_size, + std::size_t &received_size) + { return MemoryAlgorithm::shrink(ptr, max_size, preferred_size, received_size); } +*/ + /*!Deallocates the bytes allocated with allocate/allocate_at_least() + pointed by addr*/ + void deallocate (void *addr) + { MemoryAlgorithm::deallocate(addr); } + + /*!Increases managed memory in extra_size bytes more. This only works + with single-segment management*/ + void grow(std::size_t extra_size) + { MemoryAlgorithm::grow(extra_size); } + + /*!Generic named/anonymous new function. Offers all the possibilities, + such as throwing, search before creating, and the constructor is + encapsulated in an object function.*/ + template + T * generic_construct(const CharType *name, + std::size_t num, + bool try2find, + bool dothrow, + CtorFunc &ctor) + { + typedef detail::alloc_info_t ctrl_data_t; + if(name == 0){ + return this->priv_generic_anonymous_construct(num, dothrow, ctor); + } + else if(name == reinterpret_cast(-1)){ + return this->priv_generic_named_construct + (unique_type, typeid(T).name(), num, try2find, dothrow, ctor, m_header.m_unique_index); + } + else{ + return this->priv_generic_named_construct + (named_type, name, num, try2find, dothrow, ctor, m_header.m_named_index); + } + } + + /*!Returns the name of an object created with construct/find_or_construct + functions. Does not throw*/ + template + const char *get_name(const T *ptr) + { + typedef typename index_traits::index_type index_t; + typedef typename index_traits::key_type key_type; + typedef typename index_traits::index_it index_it; + typedef detail::alloc_info_t ctrl_data_t; + const bool NodeIndex = is_node_index::value; //change this + typedef detail::alloc_name_t + alloc_name_t; + + ctrl_data_t * ctrl_data = ctrl_data_t::get_info_from_data(ptr); + + //Get total size of data port and total allocation size + std::size_t datasize = detail::get_rounded_size + (ctrl_data_t::get_offset() + sizeof(T)*ctrl_data->m_num, + boost::alignment_of::value); + alloc_name_t *alloc_name = reinterpret_cast + (char_ptr_cast(ctrl_data)+datasize); + return alloc_name->get_name(); + } + + /*!Returns is the the name of an object created with construct/find_or_construct + functions. Does not throw*/ + template + InstanceType get_type(const T *ptr) + { + typedef detail::alloc_info_t ctrl_data_t; + ctrl_data_t * ctrl_data = ctrl_data_t::get_info_from_data(ptr); + return static_cast(ctrl_data->m_allocation_type); + } + + /*!Preallocates needed index resources to optimize the + creation of "num" named objects in the fixed size memory segment. + Can throw boost::interprocess::bad_alloc if there is no enough memory.*/ + void reserve_named_objects(std::size_t num) + { + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + m_header.m_named_index.reserve(num); + } + + /*!Preallocates needed index resources to optimize the + creation of "num" unique objects in the fixed size memory segment. + Can throw boost::interprocess::bad_alloc if there is no enough memory.*/ + void reserve_unique_objects(std::size_t num) + { + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + m_header.m_unique_index.reserve(num); + } + + /*!Returns the result of "all_memory_deallocated()" function + of the used memory algorithm*/ + bool all_memory_deallocated() + { return MemoryAlgorithm::all_memory_deallocated(); } + + /*!Returns the result of "check_sanity()" function + of the used memory algorithm*/ + bool check_sanity() + { return MemoryAlgorithm::check_sanity(); } + + private: + + template + bool priv_destroy_ptr(const T *ptr) + { + typedef detail::alloc_info_t ctrl_data_t; + + ctrl_data_t * ctrl_data = ctrl_data_t::get_info_from_data(ptr); + + switch(ctrl_data->m_allocation_type){ + case anonymous_type: + return this->priv_generic_anonymous_destroy(ptr); + break; + + case named_type: + return this->priv_generic_named_destroy + (ctrl_data, m_header.m_named_index); + break; + + case unique_type: + return this->priv_generic_named_destroy + (ctrl_data, m_header.m_unique_index); + break; + + default: + //This type is unknown, bad pointer passed to this function! + assert(0); + return false; + break; + } + return false; + } + template + std::pair priv_generic_find + (const CharT* name, + typename index_traits::index_type &index) + { + typedef typename index_traits::key_type key_type; + typedef typename index_traits::index_it index_it; + typedef detail::alloc_info_t ctrl_data_t; + + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + //Find name in index + index_it it = index.find(key_type(name, std::char_traits::length(name))); + + //Initialize returned values + T *ret_ptr = 0; + std::size_t ret_num = 0; + + //If found, assign values + if(it != index.end()){ + ctrl_data_t *ctrl_data = reinterpret_cast + (detail::get_pointer(it->second.m_ptr)); + //Check if sizeof is correct! + if(sizeof(T) != ctrl_data->m_sizeof_type){ + //The template parameter T is not correct! + assert(0); + ret_ptr = 0; + ret_num = 0; + } + else{ + ret_ptr = ctrl_data->get_data(); + ret_num = ctrl_data->m_num; + } + } + return std::make_pair(ret_ptr, ret_num); + } + + /*!Calls the destructor and makes an anonymous deallocate*/ + template + bool priv_generic_anonymous_destroy(const void *object) + { + typedef detail::alloc_info_t ctrl_data_t; + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + if(!object) + return false; + + //Get control data from associated with this object + ctrl_data_t * ctrl_data = ctrl_data_t::get_info_from_data(object); + if(ctrl_data->m_allocation_type != anonymous_type){ + //This is not an anonymous object, the pointer is wrong! + assert(0); + return false; + } + + if(ctrl_data->m_sizeof_type != sizeof(T)){ + //Wrong template parameter T in deallocation + assert(0); + return false; + } + + //Call destructors + if(!boost::has_trivial_destructor::value){ + this->priv_array_destroy + (ctrl_data, ctrl_data_t::get_data_from_info(ctrl_data), ctrl_data->m_num); + } + + return true; + } + template + bool priv_generic_named_destroy(const CharT *name, + typename index_traits::index_type &index) + { + typedef typename index_traits::key_type key_type; + typedef typename index_traits::index_it index_it; + typedef detail::alloc_info_t ctrl_data_t; + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + //Try to find the name in the index + index_it it = index.find(key_type (name, + std::char_traits::length(name))); + + //If not found, return false + if(it == index.end()){ + //This name is not present in the index, wrong pointer or name! + assert(0); + return false; + } + return this->priv_generic_named_destroy_impl(it, index); + } + + template + bool priv_generic_named_destroy(detail::alloc_info_t *data, + typename index_traits::index_type &index) + { + typedef typename index_traits::index_type index_t; + typedef typename index_traits::key_type key_type; + typedef typename index_traits::index_it index_it; + typedef detail::alloc_info_t ctrl_data_t; + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + const bool NodeIndex = is_node_index::value; //change this + typedef detail::alloc_name_t alloc_name_t; + + //Get total size of data port and total allocation size + std::size_t datasize = detail::get_rounded_size + (ctrl_data_t::get_offset() + sizeof(T)*data->m_num, + boost::alignment_of::value); + alloc_name_t *alloc_name = reinterpret_cast + (char_ptr_cast(data)+datasize); + if(NodeIndex){ + //If we are using node indexes, the iterator to the index + //entry is stored there, so we can erase faster + return this->priv_generic_named_destroy_impl + (alloc_name->get_it(), index); + } + else{ + //If not using node indexes, we must use the name to find + return this->priv_generic_named_destroy + (alloc_name->get_name(), index); + } + } + + template + bool priv_generic_named_destroy(const typename index_traits::index_it &it, + typename index_traits::index_type &index) + { + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + return this->priv_generic_named_destroy_impl(it, index); + } + + template + bool priv_generic_named_destroy_impl(const typename index_traits::index_it &it, + typename index_traits::index_type &index) + { + typedef typename index_traits::index_type index_t; + typedef typename index_traits::key_type key_type; + typedef typename index_traits::index_it index_it; + typedef detail::alloc_info_t ctrl_data_t; + + //Get allocation parameters + void *memory = detail::get_pointer(it->second.m_ptr); + char *stored_name = detail::char_ptr_cast + (detail::get_pointer(it->first.mp_str)); + //Check if the distance between the name pointer and the memory pointer + //is correct (this can detect incorrect T type in destruction) + ctrl_data_t *ctrl_data = reinterpret_cast(memory); + std::size_t num = ctrl_data->m_num; + + //Check if the sizeof(T) is equal to the size of the created type + if(sizeof(T) != ctrl_data->m_sizeof_type){ + //Wrong template T parameter in deallocation! + assert(0); + return false; + } + + const bool NodeIndex = is_node_index::value; //change this + typedef detail::alloc_name_t alloc_name_t; + + //Get total size of data port and total allocation size + std::size_t datasize = detail::get_rounded_size + (ctrl_data_t::get_offset() + sizeof(T)*num, + boost::alignment_of::value); + + //Check if the distance between the name pointer and the memory pointer + //is correct (this can detect incorrect T type in destruction) + if(std::size_t(stored_name - detail::char_ptr_cast(memory)) != + (datasize + alloc_name_t::get_name_offset())){ + assert(0); + //Something ugly here, name pointer is not in the right position! + return false; + } + + //If this is a node index, destroy the iterator (usually iterators are + //POD , but you never know) + if(NodeIndex){ + alloc_name_t *alloc_name = reinterpret_cast + (detail::char_ptr_cast(memory)+datasize); + alloc_name->get_it().~index_it(); + } + //Erase node from index + index.erase(it); + + //Call destructors + if(!boost::has_trivial_destructor::value){ + priv_array_destroy(memory, ctrl_data_t::get_data_from_info(memory), num); + } + + return true; + } + + template + void priv_array_destroy(const void * memory, T *objects, std::size_t count) + { + //Build scoped ptr to avoid leaks with destructor exception + boost::interprocess::scoped_ptr mem((void*)memory, *this); + + //Call destructors in reverse order, if one throws catch it and + //continue destroying ignoring further exceptions. + if(!boost::has_nothrow_destructor::value){ + while(count--){ + objects[count].~T(); + } + } + else{ + BOOST_TRY { + while(count--){ + objects[count].~T(); + } + } + BOOST_CATCH(...){ + //Destroy the rest of objects ignoring exceptions + while(count--){ + BOOST_TRY { objects[count].~T(); } + //Ignore exceptions + BOOST_CATCH(...) { } + BOOST_CATCH_END + } + //throws first exception + BOOST_RETHROW + } + BOOST_CATCH_END + } + } + + template + void priv_array_construct(typename Ctor::target_t *ptr, + std::size_t num, Ctor &ctor) + { + typedef typename Ctor::target_t target_t; + //Try constructors + std::size_t counter = 0; + BOOST_TRY{ + for(; counter < num; ++counter, ++ctor){ + ctor(&ptr[counter]); + } + } + //If there is an exception call destructors and erase index node + BOOST_CATCH(...){ + if(!boost::has_trivial_destructor::value){ + for(; counter; --counter){ + BOOST_TRY { ptr[counter].~target_t(); } + //Ignore exceptions, we will throw the original + //exception to free acquired locks + BOOST_CATCH(...) {} + BOOST_CATCH_END + } + } + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + /*!Generic named new function for named functions*/ + template + T * priv_generic_named_construct(std::size_t type, + const CharT *name, + std::size_t num, + bool try2find, + bool dothrow, + CtorFunc &ctor, + typename index_traits::index_type &index) + { + typedef typename index_traits::index_type index_t; + typedef typename index_traits::key_type key_type; + typedef typename index_traits::mapped_type mapped_type; + typedef typename index_traits::value_type value_type; + typedef typename index_traits::index_it index_it; + typedef typename index_traits::index_type index_type; + typedef typename index_traits::index_ib index_ib; + typedef detail::alloc_info_t ctrl_data_t; + + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + //Insert the node. This can throw. + //First, we want to know if the key is already present before + //we allocate any memory, and if the key is not present, we + //want to allocate all memory in a single buffer that will + //contain the name and the user buffer. + // + //Since equal_range(key) + insert(hint, value) approach is + //quite inefficient in container implementations + //(they re-test if the position is correct), I've chosen + //to insert the node, do an ugly un-const cast and modify + //the key (which is a smart pointer) to an equivalent one + std::size_t namelen = std::char_traits::length(name); + index_ib insert_ret = index.insert(value_type(key_type (name, namelen), + mapped_type(0))); + index_it it = insert_ret.first; + + //If found and this is find or construct, return data + //else return null + if(!insert_ret.second){ + return try2find ? + ctrl_data_t::get_data_from_info + (detail::get_pointer(it->second.m_ptr)): + 0; + } + //Initialize the node value_eraser to erase inserted node + //if something goes wrong + detail::value_eraser value_eraser(index, insert_ret.first); + + const bool NodeIndex = is_node_index::value; //change this + typedef detail::alloc_name_t alloc_name_t; + + //Get total size of data port and total allocation size + std::size_t datasize = detail::get_rounded_size + (ctrl_data_t::get_offset() + sizeof(T)*num, + boost::alignment_of::value); + std::size_t allocsize = datasize + alloc_name_t::get_name_offset() + (namelen+1)*sizeof(CharT); + + //Allocates buffer for name + data, this can throw (it hurts) + void *buffer_ptr; + + //Check if there is enough memory + if(dothrow){ + buffer_ptr = this->allocate(allocsize); + } + else{ + buffer_ptr = this->allocate(allocsize, std::nothrow_t()); + if(!buffer_ptr) return 0; + } + + //Set pointer and control data + insert_ret.first->second.m_ptr = buffer_ptr; + ctrl_data_t *ctrl_data = static_cast(buffer_ptr); + ctrl_data->m_allocation_type = type; + ctrl_data->m_num = num; + ctrl_data->m_sizeof_type = sizeof(T); + alloc_name_t *alloc_name = reinterpret_cast + (char_ptr_cast(ctrl_data) + datasize); + + //Copy name to memory segment and insert data + CharT *name_ptr = alloc_name->get_name(); + std::char_traits::copy(name_ptr, name, namelen+1); + + //If this is a node container, store also the iterator + if(NodeIndex){ + new(&alloc_name->get_it()) index_it(insert_ret.first); + } + + //Do the ugly cast, please mama, forgive me! + //This new key points to an identical string, so it must have the + //same position than the overwritten key according to the predicate + const_cast(insert_ret.first->first).mp_str = name_ptr; + + //Avoid constructions if constructor is trivial + if(!CtorFunc::is_trivial){ + //Build scoped ptr to avoid leaks with constructor exception + boost::interprocess::scoped_ptr mem(buffer_ptr, *this); + + //Construct array, this can throw + this->priv_array_construct + (ctrl_data_t::get_data_from_info(buffer_ptr), num, ctor); + + //All constructors successful, we don't want to release memory + mem.release(); + } + //Release node value_eraser since construction was successful + value_eraser.release(); + return ctrl_data_t::get_data_from_info(buffer_ptr); + } + + /*!Generic anonymous "new" function.*/ + template + T * priv_generic_anonymous_construct(std::size_t num, + bool dothrow, + CtorFunc &ctor) + { + typedef detail::alloc_info_t ctrl_data_t; + //------------------------------- + boost::interprocess::scoped_lock guard(m_header); + //------------------------------- + std::size_t allocsize = ctrl_data_t::get_offset() + sizeof(T)*num; + + //Allocate memory + void *ptr_struct = this->allocate(allocsize, std::nothrow_t()); + + //Check if there is enough memory + if(!ptr_struct){ + if(dothrow){ + throw bad_alloc(); + } + else{ + return 0; + } + } + + //Build scoped ptr to avoid leaks with constructor exception + boost::interprocess::scoped_ptr mem(ptr_struct, *this); + T* ptr = ctrl_data_t::get_data_from_info(ptr_struct); + ctrl_data_t *ctrl_data = reinterpret_cast(ptr_struct); + + //Set control data + ctrl_data->m_num = num; + ctrl_data->m_allocation_type = anonymous_type; + ctrl_data->m_sizeof_type = sizeof(T); + + if(!CtorFunc::is_trivial){ + //Construct array, this can throw + priv_array_construct(ptr, num, ctor); + } + + //All constructors successful, we don't want erase memory + mem.release(); + return ptr; + } + + private: + + /*!Returns the this pointer*/ + segment_manager *get_this_pointer() + { return this; } + + std::size_t get_reserved_bytes() + { + //Get the number of bytes until the end of (*this) + //beginning in the end of the MemoryAlgorithm base. + return (detail::char_ptr_cast(this) + sizeof(*this)) - + (detail::char_ptr_cast(static_cast(this)) + + sizeof(MemoryAlgorithm)); + } + + typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_t rmutex; + + /*!This struct includes needed data and derives from + rmutex to allow EBO when using null interprocess_mutex*/ + struct header_t : public rmutex + { + named_index_t m_named_index; + unique_index_t m_unique_index; + + header_t(segment_manager *segment_mngr) + : m_named_index (segment_mngr), + m_unique_index(segment_mngr) + {} + } m_header; +}; + + +}} //namespace boost { namespace interprocess + +#include + +#endif //#ifndef BOOST_INTERPROCESS_NAMED_OBJECT_ALGO_HPP + diff --git a/include/boost/interprocess/shared_memory.hpp b/include/boost/interprocess/shared_memory.hpp new file mode 100644 index 0000000..6623f85 --- /dev/null +++ b/include/boost/interprocess/shared_memory.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else + +# ifdef BOOST_HAS_UNISTD_H +# include //O_CREAT, O_*... +# include //mmap +# include //ftruncate, close +# include //sem_t* family, SEM_VALUE_MAX +# include //std::string +# include //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 + 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 + 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 + 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 + 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 +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 +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 +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 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 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 + +#endif //BOOST_INTERPROCESS_MEMORY_HPP diff --git a/include/boost/interprocess/smart_ptr/detail/Attic/sp_counted_base_pt.hpp b/include/boost/interprocess/smart_ptr/detail/Attic/sp_counted_base_pt.hpp new file mode 100644 index 0000000..133d8ae --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/Attic/sp_counted_base_pt.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 +#include + +#include +#include + +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 + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/detail/Attic/sp_counted_base_w32.hpp b/include/boost/interprocess/smart_ptr/detail/Attic/sp_counted_base_w32.hpp new file mode 100644 index 0000000..edc1e97 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/Attic/sp_counted_base_w32.hpp @@ -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 +#include + +#include +#include + +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( use_count_ ); } +}; + +} // namespace detail + +} // namespace interprocess + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp b/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp new file mode 100644 index 0000000..a95cd2f --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp @@ -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 +#include + +#ifndef BOOST_NO_EXCEPTIONS +#include +#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 + +#endif // #ifndef BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp new file mode 100644 index 0000000..36a84ef --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include + +#include // std::less + +namespace boost { +namespace interprocess { +namespace detail{ + +template +class weak_count; + +template +class shared_count +{ + public: + typedef typename detail::pointer_to_other + ::type pointer; + + private: + typedef sp_counted_impl_pd counted_impl; + typedef typename detail::pointer_to_other + ::type counted_impl_ptr; + typedef typename detail::pointer_to_other + ::type counted_base_ptr; + typedef typename A::template rebind + ::other counted_impl_allocator; + typedef typename detail::pointer_to_other + ::type const_deleter_pointer; + typedef typename detail::pointer_to_other + ::type const_allocator_pointer; + + pointer m_px; + counted_impl_ptr m_pi; + + template + friend class weak_count; + + template + friend class shared_count; + + public: + + shared_count() + : m_px(0), m_pi(0) // nothrow + {} + + template + 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 > + 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 + explicit 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 + explicit shared_count(const pointer & ptr, shared_count 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 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 + explicit shared_count(weak_count 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 + 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; + } + + 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 + bool internal_equal (shared_count const & other) const + { return this->m_pi == other.m_pi; } + + template + bool internal_less (shared_count const & other) const + { return std::less()(this->m_pi, other.m_pi); } +}; + +template inline +bool operator==(shared_count const & a, shared_count const & b) +{ return a.internal_equal(b); } + +template inline +bool operator<(shared_count const & a, shared_count const & b) +{ return a.internal_less(b); } + + +template +class weak_count +{ + public: + typedef typename detail::pointer_to_other + ::type pointer; + + private: + typedef sp_counted_impl_pd counted_impl; + typedef typename detail::pointer_to_other + ::type counted_impl_ptr; + typedef typename detail::pointer_to_other + ::type counted_base_ptr; + + pointer m_px; + counted_impl_ptr m_pi; + + template + friend class weak_count; + + template + friend class shared_count; + + public: + + weak_count(): m_px(0), m_pi(0) // nothrow + {} + + template + explicit weak_count(shared_count 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 + 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(); } + + ~weak_count() // nothrow + { if(m_pi != 0) m_pi->weak_release(); } + + template + weak_count & operator= (shared_count 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 + 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 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 + bool internal_equal (weak_count const & other) const + { return this->m_pi == other.m_pi; } + + template + bool internal_less (weak_count const & other) const + { return std::less()(this->m_pi, other.m_pi); } +}; + +template inline +bool operator==(weak_count const & a, weak_count const & b) +{ return a.internal_equal(b); } + +template inline +bool operator<(weak_count const & a, weak_count const & b) +{ return a.internal_less(b); } + +} // namespace detail +} // namespace interprocess +} // namespace boost + + +#include + + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp new file mode 100644 index 0000000..14b30f2 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp @@ -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 +#include + +#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) + +# include + +#elif defined( BOOST_HAS_PTHREADS ) + +//Ordinary pthreads counted base is not enough +//we need process shared attributte. +# include + +#else + +// Use #define BOOST_DISABLE_THREADS to avoid the error +# error Unrecognized threading platform + +#endif + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED + diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_base_pt.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_base_pt.hpp new file mode 100644 index 0000000..133d8ae --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_base_pt.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 +#include + +#include +#include + +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 + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_PT_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_base_w32.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_base_w32.hpp new file mode 100644 index 0000000..edc1e97 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_base_w32.hpp @@ -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 +#include + +#include +#include + +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( use_count_ ); } +}; + +} // namespace detail + +} // namespace interprocess + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_W32_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp new file mode 100644 index 0000000..5c79e87 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -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 +#include + +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace detail { + +template +class sp_counted_impl_pd + : public sp_counted_base + , A::template rebind< sp_counted_impl_pd >::other + , D // copy constructor must not throw +{ + private: + typedef sp_counted_impl_pd this_type; + typedef typename A::template rebind + ::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 + ::type const_deleter_pointer; + + typedef typename detail::pointer_to_other + ::type const_allocator_pointer; + + typedef typename D::pointer pointer; + pointer m_ptr; + + public: + // pre: d(p) must not throw + template + 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(*this)); } + + const_allocator_pointer get_allocator() const + { return const_allocator_pointer(&static_cast(*this)); } + + void dispose() // nothrow + { static_cast(*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_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 + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp new file mode 100644 index 0000000..67be630 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp @@ -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 +#include + +#include +#include +#include + +namespace boost{ +namespace interprocess{ + +template +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 shared_from_this() + { + shared_ptr p(_internal_weak_this); + BOOST_ASSERT(detail::get_pointer(p.get()) == this); + return p; + } + + shared_ptr shared_from_this() const + { + shared_ptr p(_internal_weak_this); + BOOST_ASSERT(detail::get_pointer(p.get()) == this); + return p; + } + + typedef T element_type; + mutable weak_ptr _internal_weak_this; +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + diff --git a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp new file mode 100644 index 0000000..921192f --- /dev/null +++ b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp @@ -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 +#include + +#include +#include +#include + +#include // for std::less +#include // 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 defines a class with a T* member whereas + intrusive_ptr > defines a class with a offset_ptr 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 intrusive_ptr +{ + public: + /*!Provides the type of the internal stored pointer.*/ + typedef typename detail::pointer_to_other::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 intrusive_ptr + (intrusive_ptr 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 intrusive_ptr & operator= + (intrusive_ptr 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 inline +bool operator==(intrusive_ptr const & a, + intrusive_ptr const & b) +{ return a.get() == b.get(); } + +/*Returns a.get() != b.get(). Does not throw*/ +template inline +bool operator!=(intrusive_ptr const & a, + intrusive_ptr const & b) +{ return a.get() != b.get(); } + +/*Returns a.get() == b. Does not throw*/ +template inline +bool operator==(intrusive_ptr const & a, + const typename intrusive_ptr::pointer &b) +{ return a.get() == b; } + +/*Returns a.get() != b. Does not throw*/ +template inline +bool operator!=(intrusive_ptr const & a, + const typename intrusive_ptr::pointer &b) +{ return a.get() != b; } + +/*Returns a == b.get(). Does not throw*/ +template inline +bool operator==(const typename intrusive_ptr::pointer &a, + intrusive_ptr const & b) +{ return a == b.get(); } + +/*Returns a != b.get(). Does not throw*/ +template inline +bool operator!=(const typename intrusive_ptr::pointer &a, + intrusive_ptr const & b) +{ return a != b.get(); } + +/*Returns a.get() < b.get(). Does not throw*/ +template inline +bool operator<(intrusive_ptr const & a, + intrusive_ptr const & b) +{ + return std::less::pointer>() + (a.get(), b.get()); +} + +/*!Exchanges the contents of the two intrusive_ptrs. Does not throw*/ +template inline +void swap(intrusive_ptr & lhs, + intrusive_ptr & rhs) +{ lhs.swap(rhs); } + +// operator<< +template +inline std::basic_ostream & operator<< + (std::basic_ostream & os, intrusive_ptr const & p) +{ os << p.get(); return os; } + +/*Returns p.get(). Does not throw*/ +template +inline typename boost::interprocess::intrusive_ptr::pointer + get_pointer(intrusive_ptr p) +{ return p.get(); } + +/*Emulates static cast operator. Does not throw*/ +template +inline boost::interprocess::intrusive_ptr static_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_static_cast(p.get()); } + +/*Emulates const cast operator. Does not throw*/ +template +inline boost::interprocess::intrusive_ptr const_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_const_cast(p.get()); } + +/*Emulates dynamic cast operator. Does not throw*/ +template +inline boost::interprocess::intrusive_ptr dynamic_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_dynamic_cast(p.get()); } + +/*Emulates reinterpret cast operator. Does not throw*/ +template +inline boost::interprocess::intrusive_ptrreinterpret_pointer_cast + (boost::interprocess::intrusive_ptr const & p) +{ return do_reinterpret_cast(p.get()); } + +} // namespace interprocess + +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp new file mode 100644 index 0000000..a5c0e65 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp @@ -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 +#include +#include + +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, the internal pointer will be offset_ptr).*/ +template +class scoped_ptr // noncopyable + : private Deleter +{ + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + typedef scoped_ptr this_type; + typedef typename workaround::random_it::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 + ::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(*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(*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 inline +void swap(scoped_ptr & a, scoped_ptr & b) // never throws +{ a.swap(b); } + +/*!Returns a copy of the stored pointer*/ +template inline +typename scoped_ptr::pointer get_pointer(scoped_ptr const & p) +{ return p.get(); } + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp new file mode 100644 index 0000000..4d23c3f --- /dev/null +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for std::swap +#include // for std::less +#include // for std::bad_cast +#include // for std::basic_ostream + +namespace boost{ +namespace interprocess{ + +template class weak_ptr; +template class enable_shared_from_this; + +namespace detail{ + +template +inline void sp_enable_shared_from_this + (shared_count const & pn, + const typename pointer_to_other ::pointer, + enable_shared_from_this >::type &pe, + const typename shared_count::pointer &px) +{ + if(pe != 0) + pe->_internal_weak_this._internal_assign(pn); +} +/* +template +inline void sp_enable_shared_from_this(shared_count 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, the internal pointer will be offset_ptr).*/ +template +class shared_ptr +{ + private: + + typedef shared_ptr 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 + ::type pointer; + + typedef typename workaround::random_it::reference reference; + typedef typename workaround::random_it::const_reference const_reference; + typedef typename detail::pointer_to_other + ::type const_deleter_pointer; + typedef typename detail::pointer_to_other + ::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::type ParameterPointer; + BOOST_STATIC_ASSERT((boost::is_same::value)|| + (boost::is_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 + shared_ptr(shared_ptr 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 + explicit shared_ptr(weak_ptr const & r) + : m_pn(r.m_pn) // may throw + {} + + template + shared_ptr(shared_ptr const & r, detail::static_cast_tag) + : m_pn(do_static_cast::type>(r.m_pn.get_pointer()), + r.m_pn) + {} + + template + shared_ptr(shared_ptr const & r, detail::const_cast_tag) + : m_pn(do_const_cast::type>(r.m_pn.get_pointer()), + r.m_pn) + {} + + template + shared_ptr(shared_ptr const & r, detail::dynamic_cast_tag) + : m_pn(do_dynamic_cast::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(); + } + } + + /*!Equivalent to shared_ptr(r).swap(*this). Never throws*/ + template + shared_ptr & operator=(shared_ptr const & r) + { + m_pn = r.m_pn; // shared_count::op= doesn't throw + return *this; + } + + void reset() + { + this_type().swap(*this); + } + + template + 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::type ParameterPointer; + BOOST_STATIC_ASSERT((boost::is_same::value)|| + (boost::is_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 & other) // never throws + { m_pn.swap(other.m_pn); } + + template + bool _internal_less(shared_ptr 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 friend class shared_ptr; + template friend class weak_ptr; + + detail::shared_count m_pn; // reference counter +}; // shared_ptr + +template inline +bool operator==(shared_ptr const & a, shared_ptr const & b) +{ return a.get() == b.get(); } + +template inline +bool operator!=(shared_ptr const & a, shared_ptr const & b) +{ return a.get() != b.get(); } + +template inline +bool operator<(shared_ptr const & a, shared_ptr const & b) +{ return a._internal_less(b); } + +template inline +void swap(shared_ptr & a, shared_ptr & b) +{ a.swap(b); } + +template inline +shared_ptr static_pointer_cast(shared_ptr const & r) +{ return shared_ptr(r, detail::static_cast_tag()); } + +template inline +shared_ptr const_pointer_cast(shared_ptr const & r) +{ return shared_ptr(r, detail::const_cast_tag()); } + +template inline +shared_ptr dynamic_pointer_cast(shared_ptr const & r) +{ return shared_ptr(r, detail::dynamic_cast_tag()); } + +// get_pointer() enables boost::mem_fn to recognize shared_ptr +template inline +T * get_pointer(shared_ptr const & p) +{ return p.get(); } + +// operator<< +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, shared_ptr const & p) +{ os << p.get(); return os; } +/* +// get_deleter (experimental) +template +typename detail::pointer_to_other, D>::type + get_deleter(shared_ptr const & p) +{ return static_cast(p._internal_get_deleter(typeid(D))); } +*/ +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED diff --git a/include/boost/interprocess/smart_ptr/unique_ptr_emulation.hpp b/include/boost/interprocess/smart_ptr/unique_ptr_emulation.hpp new file mode 100644 index 0000000..3d11313 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/unique_ptr_emulation.hpp @@ -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 +#include +#include +#include +#include +#include + +namespace boost_ext{ + +namespace detail +{ + +struct two {char _[2];}; + +namespace pointer_type_imp +{ + +template static two test(...); +template static char test(typename U::pointer* = 0); + +} + +template +struct has_pointer_type +{ + static const bool value = sizeof(pointer_type_imp::test(0)) == 1; +}; + +namespace pointer_type_imp +{ + +template ::value> +struct pointer_type +{ + typedef typename D::pointer type; +}; + +template +struct pointer_type +{ + typedef T* type; +}; + +} + +template +struct pointer_type +{ + typedef typename pointer_type_imp::pointer_type::type>::type type; +}; + +} + +template +struct default_delete +{ + default_delete() {} + template default_delete(const default_delete&) {} + void operator() (T* ptr) const + { + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete ptr; + } +}; + +template +struct default_delete +{ + void operator() (T* ptr) const + { + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete [] ptr; + } +}; + +template +struct default_delete +{ + void operator() (T* ptr, std::size_t) const + { + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete [] ptr; + } +}; + +template class unique_ptr; + +namespace detail +{ + +template struct unique_ptr_error; + +template +struct unique_ptr_error > +{ + typedef unique_ptr type; +}; + +} // detail + +template > +class unique_ptr +{ + struct nat {int for_bool_;}; + typedef typename boost::add_reference::type deleter_reference; + typedef typename boost::add_reference::type deleter_const_reference; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::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, + typename boost::add_reference::type>::type d) + : ptr_(p, d) {} + unique_ptr(const unique_ptr& u) + : ptr_(const_cast(u).release(), u.get_deleter()) {} + + template + unique_ptr(const unique_ptr& u, + typename boost::enable_if_c< + boost::is_convertible::pointer, pointer>::value && + boost::is_convertible::value && + ( + !boost::is_reference::value || + boost::is_same::value + ) + , + nat + >::type = nat()) + : ptr_(const_cast&>(u).release(), u.get_deleter()) {} + + // destructor + ~unique_ptr() {reset();} + + // assignment + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + template + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast&>(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + unique_ptr& operator=(int nat::*) + { + reset(); + return *this; + } + + // observers + typename boost::add_reference::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 ptr_; + + unique_ptr(unique_ptr&); + template unique_ptr(unique_ptr&); + template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); + + + unique_ptr& operator=(unique_ptr&); + template unique_ptr& operator=(unique_ptr&); + template typename detail::unique_ptr_error::type operator=(U&); +}; + +template +class unique_ptr +{ + struct nat {int for_bool_;}; + typedef typename boost::add_reference::type deleter_reference; + typedef typename boost::add_reference::type deleter_const_reference; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::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, + typename boost::add_reference::type>::type d) + : ptr_(p, d) {} + unique_ptr(const unique_ptr& u) + : ptr_(const_cast(u).release(), u.get_deleter()) {} + + // destructor + ~unique_ptr() {reset();} + + // assignment + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + unique_ptr& operator=(int nat::*) + { + reset(); + return *this; + } + + // observers + typename boost::add_reference::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 ptr_; + + template unique_ptr(U p, E, + typename boost::enable_if >::type* = 0); + template explicit unique_ptr(U, + typename boost::enable_if >::type* = 0); + + unique_ptr(unique_ptr&); + template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); + + unique_ptr& operator=(unique_ptr&); + template typename detail::unique_ptr_error::type operator=(U&); +}; + +template +class unique_ptr +{ + struct nat {int for_bool_;}; + typedef typename boost::add_reference::type deleter_reference; + typedef typename boost::add_reference::type deleter_const_reference; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::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, + typename boost::add_reference::type>::type d) + : ptr_(p, d) {} + unique_ptr(const unique_ptr& u) + : ptr_(const_cast(u).release(), u.get_deleter()) {} + + // destructor + ~unique_ptr() {reset();} + + // assignment + unique_ptr& operator=(const unique_ptr& cu) + { + unique_ptr& u = const_cast(cu); + reset(u.release()); + ptr_.second() = u.get_deleter(); + return *this; + } + unique_ptr& operator=(int nat::*) + { + reset(); + return *this; + } + + // observers + typename boost::add_reference::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 ptr_; + + template unique_ptr(U p, E, + typename boost::enable_if >::type* = 0); + template explicit unique_ptr(U, + typename boost::enable_if >::type* = 0); + + unique_ptr(unique_ptr&); + template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); + + unique_ptr& operator=(unique_ptr&); + template typename detail::unique_ptr_error::type operator=(U&); +}; + +template +inline +void swap(unique_ptr& x, unique_ptr& y) {x.swap(y);} + +template +inline +bool +operator==(const unique_ptr& x, const unique_ptr& y) + {return x.get() == y.get();} + +template +inline +bool +operator!=(const unique_ptr& x, const unique_ptr& y) + {return x.get() != y.get();} + +template +inline +bool +operator <(const unique_ptr& x, const unique_ptr& y) + {return x.get() < y.get();} + +template +inline +bool +operator<=(const unique_ptr& x, const unique_ptr& y) + {return x.get() <= y.get();} + +template +inline +bool +operator >(const unique_ptr& x, const unique_ptr& y) + {return x.get() > y.get();} + +template +inline +bool +operator>=(const unique_ptr& x, const unique_ptr& y) + {return x.get() >= y.get();} + +template +inline +unique_ptr +move(unique_ptr& p) +{ + return unique_ptr(p.release(), p.get_deleter()); +} + +} //namespace boost_ext{ + +#ifdef _MSC_VER + #pragma warning (pop) +#endif diff --git a/include/boost/interprocess/smart_ptr/unique_ptr_reference.hpp b/include/boost/interprocess/smart_ptr/unique_ptr_reference.hpp new file mode 100644 index 0000000..10bba15 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/unique_ptr_reference.hpp @@ -0,0 +1,407 @@ +// I, Howard Hinnant, hereby place this code in the public domain. + +namespace std { namespace detail { + +template +struct select +{ + typedef Then type; +}; + +template +struct select +{ + typedef Else type; +}; + +template struct restrict_to {}; +template struct restrict_to {typedef T type;}; + +using boost::compressed_pair; + +struct two {char _[2];}; + +namespace pointer_type_imp +{ + +template static two test(...); +template static char test(typename U::pointer* = 0); + +} + +template +struct has_pointer_type +{ + static const bool value = sizeof(pointer_type_imp::test(0)) == 1; +}; + +namespace pointer_type_imp +{ + +template ::value> +struct pointer_type +{ + typedef typename D::pointer type; +}; + +template +struct pointer_type +{ + typedef T* type; +}; + +} + +template +struct pointer_type +{ + typedef typename pointer_type_imp::pointer_type::type>::type type; +}; + +} } + +namespace std +{ + +template +struct default_delete +{ + default_delete() {} + template default_delete(const default_delete&) {} + void operator() (T* ptr) const + { + static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type"); + delete ptr; + } +}; + +template +struct default_delete +{ + void operator() (T* ptr) const + { + static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type"); + delete [] ptr; + } +}; + +template +struct default_delete +{ + void operator() (T* ptr, std::size_t) const + { + static_assert(sizeof(T) > 0, "Can't delete pointer to incomplete type"); + delete [] ptr; + } +}; + +template > +class unique_ptr +{ + struct nat {int for_bool_;}; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::type pointer; + + // constructors + unique_ptr() : ptr_(pointer()) {} + explicit unique_ptr(pointer p) : ptr_(p) {} + unique_ptr(pointer p, typename detail::select< + tr1::is_reference::value, + D, + const D&>::type d) + : ptr_(p, d) {} + unique_ptr(pointer p, typename tr1::remove_reference::type&& d) + : ptr_(p, std::move(d)) + { + static_assert(!tr1::is_reference::value, "rvalue deleter bound to reference"); + } + unique_ptr(unique_ptr&& u) + : ptr_(u.release(), std::forward(u.get_deleter())) {} + template + unique_ptr(unique_ptr&& u, + typename detail::restrict_to< + tr1::is_convertible::pointer, pointer>::value && + tr1::is_convertible::value && + ( + !tr1::is_reference::value || + tr1::is_same::value + ) + , + nat + >::type = nat()) + : ptr_(u.release(), std::forward(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 + 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::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 ptr_; + + unique_ptr(const unique_ptr&); + template unique_ptr(const unique_ptr&); + unique_ptr& operator=(const unique_ptr&); + template unique_ptr& operator=(const unique_ptr&); +}; + +template +class unique_ptr +{ + struct nat {int for_bool_;}; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::type pointer; + + // constructors + unique_ptr() : ptr_(pointer()) {} + explicit unique_ptr(pointer p) : ptr_(p) {} + unique_ptr(pointer p, typename detail::select< + tr1::is_reference::value, + D, + const D&>::type d) + : ptr_(p, d) {} + unique_ptr(pointer p, typename tr1::remove_reference::type&& d) + : ptr_(p, std::move(d)) + { + static_assert(!tr1::is_reference::value, "rvalue deleter bound to reference"); + } + unique_ptr(unique_ptr&& u) + : ptr_(u.release(), std::forward(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::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 ptr_; + + template unique_ptr(U p, + typename detail::select< + tr1::is_reference::value, + D, + const D&>::type d, + typename detail::restrict_to::value>::type* = 0); + template unique_ptr(U p, typename tr1::remove_reference::type&& d, + typename detail::restrict_to::value>::type* = 0); + template explicit unique_ptr(U, + typename detail::restrict_to::value>::type* = 0); + unique_ptr(const unique_ptr&); + unique_ptr& operator=(const unique_ptr&); +}; + +template +class unique_ptr +{ + struct nat {int for_bool_;}; +public: + typedef T element_type; + typedef D deleter_type; + typedef typename detail::pointer_type::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::value, + D, + const D&>::type d) + : ptr_(p, d) {} + unique_ptr(pointer p, typename tr1::remove_reference::type&& d) + : ptr_(p, std::move(d)) + { + static_assert(!tr1::is_reference::value, "rvalue deleter bound to reference"); + } + unique_ptr(unique_ptr&& u) + : ptr_(u.release(), std::forward(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::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 ptr_; + + template unique_ptr(U p, + typename detail::select< + tr1::is_reference::value, + D, + const D&>::type d, + typename detail::restrict_to::value>::type* = 0); + template unique_ptr(U p, typename tr1::remove_reference::type&& d, + typename detail::restrict_to::value>::type* = 0); + template explicit unique_ptr(U, + typename detail::restrict_to::value>::type* = 0); + unique_ptr(const unique_ptr&); + unique_ptr& operator=(const unique_ptr&); +}; + +template +inline +void swap(unique_ptr& x, unique_ptr& y) {x.swap(y);} + +template +inline +void swap(unique_ptr&& x, unique_ptr& y) {x.swap(y);} + +template +inline +void swap(unique_ptr& x, unique_ptr&& y) {x.swap(y);} + +template +inline +bool +operator==(const unique_ptr& x, const unique_ptr& y) + {return x.get() == y.get();} + +template +inline +bool +operator!=(const unique_ptr& x, const unique_ptr& y) + {return x.get() != y.get();} + +template +inline +bool +operator <(const unique_ptr& x, const unique_ptr& y) + {return x.get() < y.get();} + +template +inline +bool +operator<=(const unique_ptr& x, const unique_ptr& y) + {return x.get() <= y.get();} + +template +inline +bool +operator >(const unique_ptr& x, const unique_ptr& y) + {return x.get() > y.get();} + +template +inline +bool +operator>=(const unique_ptr& x, const unique_ptr& y) + {return x.get() >= y.get();} + +} // std \ No newline at end of file diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp new file mode 100644 index 0000000..c50fe16 --- /dev/null +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -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 +#include + +#include + +namespace boost{ +namespace interprocess{ + +template +class weak_ptr +{ + private: + + // Borland 5.5.1 specific workarounds + typedef weak_ptr this_type; + typedef typename detail::pointer_to_other + ::type pointer; + typedef typename workaround::random_it::reference reference; + typedef typename workaround::random_it::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 + // weak_ptr(weak_ptr 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 + weak_ptr(weak_ptr 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 &ref = r.lock(); + m_pn.set_pointer(ref.get()); + } + + template + weak_ptr(shared_ptr const & r) + : m_pn(r.m_pn) // never throws + {} + + template + weak_ptr & operator=(weak_ptr const & r) // never throws + { + //Construct a temporary shared_ptr so that nobody + //can destroy the value while constructing this + const shared_ptr &ref = r.lock(); + m_pn = r.m_pn; + m_pn.set_pointer(ref.get()); + return *this; + } + + template + weak_ptr & operator=(shared_ptr const & r) // never throws + { m_pn = r.m_pn; return *this; } + + shared_ptr lock() const // never throws + { + // optimization: avoid throw overhead + if(expired()){ + return shared_ptr(); + } + BOOST_TRY{ + return shared_ptr(*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(); + } + 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 + bool _internal_less(weak_ptr const & rhs) const + { return m_pn < rhs.m_pn; } + + template + void _internal_assign(const detail::shared_count & pn2) + { m_pn = pn2; } + + private: + + template friend class shared_ptr; + template friend class weak_ptr; + + detail::weak_count m_pn; // reference counter +}; // weak_ptr + +template inline +bool operator<(weak_ptr const & a, weak_ptr const & b) +{ return a._internal_less(b); } + +template inline +void swap(weak_ptr & a, weak_ptr & b) +{ a.swap(b); } + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED diff --git a/include/boost/interprocess/streams/bufferstream.hpp b/include/boost/interprocess/streams/bufferstream.hpp new file mode 100644 index 0000000..90036a9 --- /dev/null +++ b/include/boost/interprocess/streams/bufferstream.hpp @@ -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 +#include + +#include +#include +#include +#include +#include // char traits +#include // ptrdiff_t +#include +#include + +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 basic_bufferbuf + : public std::basic_streambuf +{ + 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 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 buffer() const + { return std::pair(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(m_length); + break; + case std::ios_base::cur: + newoff = in ? static_cast(this->gptr() - this->eback()) + : static_cast(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 basic_ibufferstream +: public std::basic_istream +{ + public: // Typedefs + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream 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(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* rdbuf() const + { return const_cast*>(&m_buf); } + + /*!Returns the pointer and size of the internal buffer. + Does not throw.*/ + std::pair 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(buffer), length); } + + private: + basic_bufferbuf m_buf; +}; + +/*!A basic_ostream class that uses a fixed size character buffer + as its formatting buffer.*/ +template +class basic_obufferstream + : public std::basic_ostream +{ + public: + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_ostream 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* rdbuf() const + { return const_cast*>(&m_buf); } + + /*!Returns the pointer and size of the internal buffer. + Does not throw.*/ + std::pair 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 m_buf; +}; + + +/*!A basic_iostream class that uses a fixed size character buffer + as its formatting buffer.*/ +template +class basic_bufferstream +: public std::basic_iostream + +{ + public: // Typedefs + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream 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* rdbuf() const + { return const_cast*>(&m_buf); } + + /*!Returns the pointer and size of the internal buffer. + Does not throw.*/ + std::pair 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 m_buf; +}; + +//Some typedefs to simplify usage +typedef basic_bufferbuf bufferbuf; +typedef basic_bufferstream bufferstream; +typedef basic_ibufferstream ibufferstream; +typedef basic_obufferstream obufferstream; + +typedef basic_bufferbuf wbufferbuf; +typedef basic_bufferstream wbufferstream; +typedef basic_ibufferstream wibufferstream; +typedef basic_obufferstream wobufferstream; + + +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */ diff --git a/include/boost/interprocess/streams/stringstream.hpp b/include/boost/interprocess/streams/stringstream.hpp new file mode 100644 index 0000000..a82735a --- /dev/null +++ b/include/boost/interprocess/streams/stringstream.hpp @@ -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 +#include + +#include +#include +#include +#include +#include // char traits +#include // ptrdiff_t +#include +#include + +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 basic_stringbuf + : public std::basic_streambuf +{ + 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 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 + 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(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( + &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(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 + (&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 + (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(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(, 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(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(m_string.size()); + break; + case std::ios_base::cur: + newoff = in ? static_cast(this->gptr() - this->eback()) + : static_cast(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 basic_istringstream +: public std::basic_istream +{ + public: + typedef CharString string_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream 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 + 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* rdbuf() const + { return const_cast*>(&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 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 basic_ostringstream + : public std::basic_ostream +{ + public: + typedef CharString string_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_ostream 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 + 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* rdbuf() const + { return const_cast*>(&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 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 basic_stringstream +: public std::basic_iostream + +{ + public: + typedef CharString string_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream 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 + 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* rdbuf() const + { return const_cast*>(&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 m_buf; +}; + +//Some typedefs to simplify usage +/* +typedef basic_stringbuf > stringbuf; +typedef basic_stringstream > stringstream; +typedef basic_istringstream > istringstream; +typedef basic_ostringstream > ostringstream; + +typedef basic_stringbuf > wstringbuf; +typedef basic_stringstream > wstringstream; +typedef basic_istringstream > wistringstream; +typedef basic_ostringstream > wostringstream; +*/ +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_STRINGSTREAM_HPP */ diff --git a/include/boost/interprocess/streams/vectorstream.hpp b/include/boost/interprocess/streams/vectorstream.hpp new file mode 100644 index 0000000..dea12a2 --- /dev/null +++ b/include/boost/interprocess/streams/vectorstream.hpp @@ -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 +#include + +#include +#include +#include +#include +#include // char traits +#include // ptrdiff_t +#include +#include + +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 basic_vectorbuf + : public std::basic_streambuf +{ + 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 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 + 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(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(&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 + (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(this->gptr() - this->eback()) + : static_cast(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 basic_ivectorstream +: public std::basic_istream +{ + public: + typedef CharVector vector_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream 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 + 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* rdbuf() const + { return const_cast*>(&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 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 basic_ovectorstream + : public std::basic_ostream +{ + public: + typedef CharVector vector_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_ostream 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 + 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* rdbuf() const + { return const_cast*>(&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 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 basic_vectorstream +: public std::basic_iostream + +{ + public: + typedef CharVector vector_type; + typedef typename std::basic_ios + ::char_type char_type; + typedef typename std::basic_ios::int_type int_type; + typedef typename std::basic_ios::pos_type pos_type; + typedef typename std::basic_ios::off_type off_type; + typedef typename std::basic_ios::traits_type traits_type; + + private: + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream 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 + 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* rdbuf() const + { return const_cast*>(&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 m_buf; +}; + +//Some typedefs to simplify usage +/* +typedef basic_vectorbuf > vectorbuf; +typedef basic_vectorstream > vectorstream; +typedef basic_ivectorstream > ivectorstream; +typedef basic_ovectorstream > ovectorstream; + +typedef basic_vectorbuf > wvectorbuf; +typedef basic_vectorstream > wvectorstream; +typedef basic_ivectorstream > wivectorstream; +typedef basic_ovectorstream > wovectorstream; +*/ +}} //namespace boost { namespace interprocess { + +#include + +#endif /* BOOST_INTERPROCESS_VECTORSTREAM_HPP */ diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp new file mode 100644 index 0000000..7bd7b1e --- /dev/null +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -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 +#include +#include +#include +#include +#include +#include + +/*!\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 + +#endif //BOOST_INTERPROCESS_FILE_LOCK_HPP diff --git a/include/boost/interprocess/sync/interprocess_barrier.hpp b/include/boost/interprocess/sync/interprocess_barrier.hpp new file mode 100644 index 0000000..31a7454 --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_barrier.hpp @@ -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 +#include + +#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER +# include +# include +# include +#else //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER +# include +# include +# include +# include +#endif //#if defined BOOST_INTERPROCESS_USE_PTHREAD_BARRIER + +# include + +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(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 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 + +#endif diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp new file mode 100644 index 0000000..9c990ed --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -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 +#include + +//#include +//#include +#include +#include +#include +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else +# include +# include +#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 + void wait(L& lock) + { + if (!lock) + throw lock_exception(); + do_wait(*lock.interprocess_mutex()); + } + + /*!The same as: while (!pred()) wait(lock)*/ + template + 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 + 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 + 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 +#else +# include +#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +#include + +#endif // BOOST_INTERPROCESS_CONDITION_HPP diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp new file mode 100644 index 0000000..5784d23 --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -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 +#include + +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +# include +# include +#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 +#else +# include +#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +#include + +#endif //BOOST_INTERPROCESS_MUTEX_HPP diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp new file mode 100644 index 0000000..db9335c --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -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 +#include + +#include +#include +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +# include +# include +#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 +#else +# include +#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +#include + +#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp new file mode 100644 index 0000000..7cecbd6 --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -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 +#include +#include +#include +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +# include +# include +#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +#include //O_CREAT, O_*... +#include //close +#include //std::string +#include //sem_* family, SEM_VALUE_MAX +#include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#include //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 +#else +# include +#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +#include + +#endif //BOOST_INTERPROCESS_SEMAPHORE_HPP diff --git a/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp b/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp new file mode 100644 index 0000000..78e6c2f --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_sharable_mutex.hpp @@ -0,0 +1,1271 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SHARABLE_MUTEX_HPP +#define BOOST_INTERPROCESS_SHARABLE_MUTEX_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + +namespace interprocess { + +/*!An object of class shared_read_write_mutex is a read_write_mutex that + can be placed in shared memory so that it can be used to synchronize + threads of different processes.*/ +class interprocess_sharable_mutex +{ + public: + + enum sharable_mutex_policy + { +// system_default, //The default behavior of the system + sharable_priority, //Prefer readers; can starve writers + exclusive_priority, //Prefer writers; can starve readers + no_priority, + max_priority + // rw_alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers + // rw_alternating_single_read //Alternate readers and writers; before a writer, release only on queued reader + }; + + interprocess_sharable_mutex(sharable_mutex_policy policy = sharable_priority) + : m_policy (policy) + { this->priv_init(); } + + ~interprocess_sharable_mutex() + { this->priv_fini(); } + + void lock_sharable() + { this->priv_sharable_lock(false, 0); } + + bool try_lock_sharable() + { return this->priv_sharable_lock(true, 0); } + + bool timed_lock_sharable(const boost::posix_time::ptime &pt) + { return this->priv_sharable_lock(true, &pt); } + + void unlock_sharable() + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + { + se_priority_t *const m = this->priv_members(); + scoped_lock lock(m->mut); + --m->shared_active; + if(m->shared_active == 0 && m->exclusive_waiting > 0){ + m->exclusive_cond.notify_one(); + } + } + break; + case no_priority: + priv_alt_priority_unlock(); + break; + default: + assert(0); + } + } + + void lock() + { this->priv_lock(false, 0); } + + bool try_lock() + { return this->priv_lock(true, 0); } + + bool timed_lock(const boost::posix_time::ptime &pt) + { return this->priv_lock(true, &pt); } + + void unlock() + { + switch(m_policy){ + case sharable_priority: + { + se_priority_t *const m = this->priv_members(); + scoped_lock lock(m->mut); + m->exclusive_active = 0; + if(m->shared_waiting > 0){ + m->shared_cond.notify_all(); + } + else if (m->exclusive_waiting > 0){ + m->exclusive_cond.notify_one(); + } + } + break; + case exclusive_priority: + { + se_priority_t *const m = this->priv_members(); + scoped_lock lock(m->mut); + m->exclusive_active = 0; + if(m->exclusive_waiting > 0){ + m->exclusive_cond.notify_one(); + } + else if (m->shared_waiting > 0){ + m->shared_cond.notify_all(); + } + } + break; + case no_priority: + priv_alt_priority_unlock(); + break; + default: + assert(0); + } + } + + sharable_mutex_policy get_policy() const + { return m_policy; } + + private: + + //Anti-exception RAII + struct counter_decrementer + { + counter_decrementer(std::size_t &count) + : m_count(count){} + ~counter_decrementer() + { --m_count; } + std::size_t &m_count; + }; + + struct a_priority_wlock_rollback + { + a_priority_wlock_rollback(interprocess_sharable_mutex *lock) + : m_lock(lock){} + + ~a_priority_wlock_rollback() + { + if(m_lock){ + no_priority_t *const m = m_lock->priv_members(); + m->shared_count = -m->completed_shared_count; + m->completed_shared_count = 0; + } + } + + void release(){ m_lock = 0; } + + private: + interprocess_sharable_mutex *m_lock; + }; + + bool priv_sharable_lock(bool timed, const boost::posix_time::ptime *pt) + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + { + se_priority_t *const m = this->priv_members(); + scoped_lock lock(m->mut); + if(m->exclusive_active && !this->priv_se_priority_s_wait(lock, timed, pt)){ + return false; + } + ++m->shared_active; + } + break; + case exclusive_priority: + { + se_priority_t *const m = this->priv_members(); + scoped_lock lock(m->mut); + if((m->exclusive_active || m->exclusive_waiting > 0) && + !this->priv_se_priority_s_wait(lock, timed, pt)){ + return false; + } + ++m->shared_active; + } + break; + + case no_priority: + { + no_priority_t *const m = this->priv_members(); + scoped_lock lock(m->exclusive_mutex, dont_lock); + + if(!this->priv_locking(lock, timed, pt)){ + return false; + } + + if(++m->shared_count == INT_MAX){ + scoped_lock lock(m->shared_mutex, *pt); + if(!lock.locked()){ + ++m->completed_shared_count; + return false; + } + m->shared_count -= m->completed_shared_count; + m->completed_shared_count = 0; + } + return true; + } + break; + default: + assert(0); + return false; + } + return true; + } + + bool priv_lock(bool timed, const boost::posix_time::ptime *pt) + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + { + se_priority_t *const m = this->priv_members(); + scoped_lock lock(m->mut); + if((m->exclusive_active || m->shared_active > 0) && + !this->priv_se_priority_e_wait(lock, timed, pt)){ + return false; + } + m->exclusive_active = 1; + } + break; + + case no_priority: + { + no_priority_t *const m = this->priv_members(); + + //Initialize scoped locks + scoped_lock lock_exclusive(m->exclusive_mutex, dont_lock); + scoped_lock lock_shared (m->shared_mutex, dont_lock); + + if(!this->priv_locking(lock_exclusive, timed, pt))return false; + if(!this->priv_locking(lock_shared, timed, pt))return false; + + if(m->exclusive_count == 0){ + if(m->completed_shared_count > 0){ + m->shared_count -= m->completed_shared_count; + m->completed_shared_count = 0; + } + if(m->shared_count > 0){ + //This logic is for timed a infinite waits + m->completed_shared_count = -m->shared_count; + a_priority_wlock_rollback rollback(this); + + do{ + if(!this->priv_waiting + (lock_shared, m->shared_cond, timed, pt)){ + m->shared_count = 0; + return false; + } + }while (m->completed_shared_count < 0); + + m->shared_count = 0; + rollback.release(); + } + } + + ++m->exclusive_count; + //Let mutexes locked + lock_exclusive.release(); + lock_shared.release(); + } + default: + return false; + } + return true; + } + + bool priv_se_priority_s_wait(scoped_lock &lock, bool timed, const boost::posix_time::ptime *pt) + { + se_priority_t *const m = this->priv_members(); + //We should block + ++m->shared_waiting; + counter_decrementer decrementer(m->shared_waiting); + do{ + if(!this->priv_waiting(lock, m->shared_cond, timed, pt)) + return false; + }while(m->exclusive_active); + return true; + } + + bool priv_se_priority_e_wait(scoped_lock &lock, bool timed, const boost::posix_time::ptime *pt) + { + se_priority_t *const m = this->priv_members(); + //We should block + ++m->exclusive_waiting; + counter_decrementer decrementer(m->exclusive_waiting); + do{ + if(!this->priv_waiting(lock, m->exclusive_cond, timed, pt)){ + return false; + } + }while(m->exclusive_active || m->shared_active > 0); + return true; + } + + void priv_alt_priority_unlock() + { + no_priority_t *const m = this->priv_members(); + if (m->exclusive_count == 0){ + scoped_lock lock(m->shared_mutex); + if(++m->completed_shared_count == 0) { + m->shared_cond.notify_one(); + } + } + else{ + --m->exclusive_count; + m->shared_mutex.unlock(); + m->exclusive_mutex.unlock(); + } + } + + private: + + bool priv_locking(scoped_lock &lock, + bool timed, + const boost::posix_time::ptime *pt) + { + return timed ? (!pt ? lock.try_lock() : lock.timed_lock(*pt)) + : (lock.lock(), true); + } + + bool priv_waiting(scoped_lock &lock, + interprocess_condition &cond, + bool timed, + const boost::posix_time::ptime *pt) + { + return timed ? (!pt ? false : cond.timed_wait(lock, *pt)) + : (cond.wait(lock), true); + } + + struct se_priority_t + { + se_priority_t() + : mut(), shared_cond(), exclusive_cond() + , shared_active(0), shared_waiting(0) + , exclusive_active(0), exclusive_waiting(0) + {} + + interprocess_mutex mut; + interprocess_condition shared_cond; + interprocess_condition exclusive_cond; + std::size_t shared_active; + std::size_t shared_waiting; + std::size_t exclusive_active; + std::size_t exclusive_waiting; + }; + + struct no_priority_t + { + no_priority_t() + : exclusive_mutex(), shared_mutex(), shared_cond() + , completed_shared_count(0), shared_count(0), exclusive_count(0) + {} + + //shared by all methods + interprocess_mutex exclusive_mutex; + interprocess_mutex shared_mutex; + interprocess_condition shared_cond; + int completed_shared_count; + int shared_count; + int exclusive_count; + }; + + //Let's make a smart "union" type + typedef boost::mpl::vector types; + //Let's get the size of the "union" + typedef boost::mpl::max_element + + > >::type iter; + //This is the instance of the variant + typedef boost::aligned_storage + ::type::value>::type raw_data_t; + + template + const T * const priv_members() const + { return static_cast(static_cast(&m_raw)); } + + template + T * const priv_members() + { return static_cast(static_cast(&m_raw)); } + + void priv_init() + { + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + new (&m_raw)se_priority_t(); + break; + case no_priority: + new (&m_raw)no_priority_t(); + break; + default: + { throw interprocess_exception(error_info(bad_sharable_lock)); } + } + } + + void priv_fini() + { + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + this->priv_members()->~se_priority_t(); + break; + case no_priority: + this->priv_members()->~no_priority_t(); + break; + default: + //This sharable lock type is unknown + assert(0); + } + } + + const sharable_mutex_policy m_policy; + raw_data_t m_raw; +}; + +/* +class interprocess_sharable_mutex +{ + public: + + enum sharable_mutex_policy + { + sharable_priority, //Prefer readers; can starve writers + exclusive_priority, //Prefer writers; can starve readers + no_priority, + max_priority + // rw_alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers + // rw_alternating_single_read //Alternate readers and writers; before a writer, release only on queued reader + }; + + interprocess_sharable_mutex(sharable_mutex_policy policy = sharable_priority) + : m_policy (policy) + { this->init(); } + + ~interprocess_sharable_mutex() + { this->fini(); } + + void lock_sharable() + { this->do_sharable_lock(false, 0); } + + bool try_lock_sharable() + { return this->do_sharable_lock(true, 0); } + + bool timed_lock_sharable(const boost::posix_time::ptime &pt) + { return this->do_sharable_lock(true, &pt); } + + void unlock_sharable() + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + { + se_priority_t *const m = this->get_se_priority_t(); + scoped_lock lock(m->interprocess_mutex); + --m->shared_active; + if(m->shared_active == 0 && m->exclusive_waiting > 0){ + m->exclusive_cond.notify_one(); + } + } + break; + case no_priority: + do_alt_priority_unlock(); + break; + default: + assert(0); + } + } + + void lock() + { this->do_lock(false, 0); } + + bool try_lock() + { return this->do_lock(true, 0); } + + bool timed_lock(const boost::posix_time::ptime &pt) + { return this->do_lock(true, &pt); } + + void unlock() + { + switch(m_policy){ + case sharable_priority: + { + se_priority_t *const m = this->get_se_priority_t(); + scoped_lock lock(m->interprocess_mutex); + m->exclusive_active = 0; + if(m->shared_waiting > 0){ + m->shared_cond.notify_all(); + } + else if (m->exclusive_waiting > 0){ + m->exclusive_cond.notify_one(); + } + } + break; + case exclusive_priority: + { + se_priority_t *const m = this->get_se_priority_t(); + scoped_lock lock(m->interprocess_mutex); + m->exclusive_active = 0; + if(m->exclusive_waiting > 0){ + m->exclusive_cond.notify_one(); + } + else if (m->shared_waiting > 0){ + m->shared_cond.notify_all(); + } + } + break; + case no_priority: + do_alt_priority_unlock(); + break; + default: + assert(0); + } + } + + sharable_mutex_policy get_policy() const + { return m_policy; } + + private: + + //Anti-exception RAII + struct counter_decrementer + { + counter_decrementer(std::size_t &count) + : m_count(count){} + ~counter_decrementer() + { --m_count; } + std::size_t &m_count; + }; + + struct a_priority_wlock_rollback + { + a_priority_wlock_rollback(interprocess_sharable_mutex *lock) + : m_lock(lock){} + + ~a_priority_wlock_rollback() + { + if(m_lock){ + no_priority_t *const m = m_lock->get_members(); + m->shared_count = -m->completed_shared_count; + m->completed_shared_count = 0; + } + } + + void release(){ m_lock = 0; } + + private: + interprocess_sharable_mutex *m_lock; + }; + + bool do_sharable_lock(bool timed, const boost::posix_time::ptime *pt) + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + { + se_priority_t *const m = this->get_se_priority_t(); + scoped_lock lock(m->interprocess_mutex); + if(m->exclusive_active && !this->do_se_priority_s_wait(lock, timed, pt)){ + return false; + } + ++m->shared_active; + } + break; + case exclusive_priority: + { + se_priority_t *const m = this->get_se_priority_t(); + scoped_lock lock(m->interprocess_mutex); + if((m->exclusive_active || m->exclusive_waiting > 0) && + !this->do_se_priority_s_wait(lock, timed, pt)){ + return false; + } + ++m->shared_active; + } + break; + + case no_priority: + { + no_priority_t *const m = this->get_members(); + if(timed && !pt){ + scoped_lock lock(m->exclusive_mutex, try_to_lock); + if(!lock.locked()) return false; + + if(++m->shared_count == INT_MAX){ + //Is better to throw in this case? + //m->shared_mutex.do_lock(); + scoped_lock lock(m->shared_mutex); + m->shared_count -= m->completed_shared_count; + m->completed_shared_count = 0; + } + } + else if(timed){ + scoped_lock lock(m->exclusive_mutex, *pt); + if(!lock.locked()){ + return false; + } + if(++m->shared_count == INT_MAX){ + //Is better to throw in this case? + //m->shared_mutex.do_lock(); + scoped_lock lock(m->shared_mutex, *pt); + if(!lock.locked()){ + ++m->completed_shared_count; + return false; + } + m->shared_count -= m->completed_shared_count; + m->completed_shared_count = 0; + return true; + } + } + else{ + scoped_lock lock(m->exclusive_mutex); + if(++m->shared_count == INT_MAX){ + //Is better to throw in this case? + //m->shared_mutex.do_lock(); + scoped_lock lock(m->shared_mutex); + m->shared_count -= m->completed_shared_count; + m->completed_shared_count = 0; + return true; + } + } + } + break; + default: + assert(0); + return false; + } + return true; + } + + bool do_lock(bool timed, const boost::posix_time::ptime *pt) + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + { + se_priority_t *const m = this->get_se_priority_t(); + scoped_lock lock(m->interprocess_mutex); + if((m->exclusive_active || m->shared_active > 0) && + !this->do_se_priority_e_wait(lock, timed, pt)){ + return false; + } + m->exclusive_active = 1; + } + break; + + case no_priority: + { + no_priority_t *const m = this->get_members(); + //Initialize scoped locks + scoped_lock lock_exclusive(m->exclusive_mutex, dont_lock); + scoped_lock lock_shared (m->shared_mutex, dont_lock); + + //Do initialization depending on lock type + if(timed && !pt){ + if(!lock_exclusive.try_lock())return false; + if(!lock_shared.try_lock()) return false; + } + else if(timed){ + if(!lock_exclusive.timed_lock(*pt))return false; + if(!lock_shared.timed_lock(*pt)) return false; + } + else{ + lock_exclusive.lock(); + lock_shared.lock(); + } + + if(m->exclusive_count == 0){ + if(m->completed_shared_count > 0){ + m->shared_count -= m->completed_shared_count; + m->completed_shared_count = 0; + } + if(m->shared_count > 0){ + //This logic is for timed a infinite waits + m->completed_shared_count = -m->shared_count; + a_priority_wlock_rollback rollback(this); + + do{ + if(timed && !pt){ + m->shared_count = 0; + return false; + } + else if(timed){ + if(!m->shared_cond.timed_wait(lock_shared, *pt)){ + m->shared_count = 0; + return false; + } + } + else{ + m->shared_cond.wait(lock_shared); + } + }while (m->completed_shared_count < 0); + + m->shared_count = 0; + rollback.release(); + } + } + + ++m->exclusive_count; + //Let mutexes locked + lock_exclusive.release(); + lock_shared.release(); + return true; + } + break; + default: + assert(0); + return false; + } + return true; + } + + bool do_se_priority_s_wait(scoped_lock &lock, bool timed, const boost::posix_time::ptime *pt) + { + if(timed && !pt) return false; + se_priority_t *const m = this->get_se_priority_t(); + //We should block + ++m->shared_waiting; + counter_decrementer decrementer(m->shared_waiting); + do{ + if(timed){ + if(!m->shared_cond.timed_wait(lock, *pt)) + return false; + } + else{ + m->shared_cond.wait(lock); + } + }while(m->exclusive_active); + return true; + } + + bool do_se_priority_e_wait(scoped_lock &lock, bool timed, const boost::posix_time::ptime *pt) + { + if(timed && !pt) return false; + se_priority_t *const m = this->get_se_priority_t(); + //We should block + ++m->exclusive_waiting; + counter_decrementer decrementer(m->exclusive_waiting); + do{ + if(timed && !m->exclusive_cond.timed_wait(lock, *pt)){ + return false; + } + else{ + m->exclusive_cond.wait(lock); + } + }while(m->exclusive_active || m->shared_active > 0); + return true; + } + + void do_alt_priority_unlock() + { + no_priority_t *const m = this->get_members(); + if (m->exclusive_count == 0){ + scoped_lock lock(m->shared_mutex); + if(++m->completed_shared_count == 0) { + m->shared_cond.notify_one(); + } + } + else{ + --m->exclusive_count; + m->shared_mutex.unlock(); + m->exclusive_mutex.unlock(); + } + } + + private: + + struct se_priority_t + { + se_priority_t() + : shared_active(0), shared_waiting(0), + exclusive_waiting(0),exclusive_active(0) + {} + + interprocess_mutex interprocess_mutex; + interprocess_condition shared_cond; + interprocess_condition exclusive_cond; + std::size_t shared_active; + std::size_t shared_waiting; + std::size_t exclusive_active; + std::size_t exclusive_waiting; + }; + + struct no_priority_t + { + no_priority_t() + : completed_shared_count(0), shared_count(0), exclusive_count(0) + {} + + //shared by all methods + interprocess_mutex exclusive_mutex; + interprocess_mutex shared_mutex; + interprocess_condition shared_cond; + int completed_shared_count; + int shared_count; + int exclusive_count; + }; + + typedef boost::mpl::vector types; + typedef boost::mpl::max_element + + > >::type iter; + + typedef boost::aligned_storage + ::type::value>::type raw_data_t; + + const se_priority_t *get_se_priority_t() const + { return static_cast(static_cast(&m_raw)); } + + se_priority_t *get_se_priority_t() + { return static_cast(static_cast(&m_raw)); } + + const no_priority_t *get_members() const + { return static_cast(static_cast(&m_raw)); } + + no_priority_t *get_members() + { return static_cast(static_cast(&m_raw)); } + + void init() + { + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + new (&m_raw)se_priority_t(); + break; + case no_priority: + new (&m_raw)no_priority_t(); + break; + default: + { throw interprocess_exception(error_info(bad_sharable_lock)); } + } + } + + void fini() + { + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + this->get_se_priority_t()->~se_priority_t(); + break; + case no_priority: + this->get_members()->~no_priority_t(); + break; + default: + //This sharable lock type is unknown + assert(0); + } + } + + const sharable_mutex_policy m_policy; + raw_data_t m_raw; +}; +*/ +/* +class interprocess_sharable_mutex +{ + public: + + enum sharable_mutex_policy + { + sharable_priority, //Prefer readers; can starve writers + exclusive_priority, //Prefer writers; can starve readers + no_priority, + max_priority + // rw_alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers + // rw_alternating_single_read //Alternate readers and writers; before a writer, release only on queued reader + }; + + interprocess_sharable_mutex(sharable_mutex_policy policy = sharable_priority) + : m_policy (policy), + m_r_active_completed_shared_count(0), m_r_wait_shared_count(0), m_w_wait_exclusive_count(0), m_w_active(0), + m_completed_shared_count(0), m_shared_count(0), m_exclusive_count(0) + {} + + ~interprocess_sharable_mutex() + {} + + void lock_sharable() + { this->do_sharable_lock(false, 0); } + + bool try_lock_sharable() + { return this->do_sharable_lock(true, 0); } + + bool timed_lock_sharable(const boost::posix_time::ptime &pt) + { return this->do_sharable_lock(true, &pt); } + + void unlock_sharable() + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + { + scoped_lock lock(m_mutex_exclusive_mutex); + --m_r_active_completed_shared_count; + if(m_r_active_completed_shared_count == 0 && m_w_wait_exclusive_count > 0){ + exclusive_cond.notify_one(); + } + } + break; + case no_priority: + { + do_alt_priority_unlock(); + } + break; + default: + assert(0); + } + } + + void lock() + { this->do_lock(false, 0); } + + bool try_lock() + { return this->do_lock(true, 0); } + + bool timed_lock(const boost::posix_time::ptime &pt) + { return this->do_lock(true, &pt); } + + void unlock() + { + switch(m_policy){ + case sharable_priority: + { + scoped_lock lock(m_mutex_exclusive_mutex); + m_w_active = 0; + if(m_r_wait_shared_count > 0){ + m_reader_shared_cond.notify_all(); + } + else if (m_w_wait_exclusive_count > 0){ + exclusive_cond.notify_one(); + } + } + break; + case exclusive_priority: + { + scoped_lock lock(m_mutex_exclusive_mutex); + m_w_active = 0; + if(m_w_wait_exclusive_count > 0){ + exclusive_cond.notify_one(); + } + else if (m_r_wait_shared_count > 0){ + m_reader_shared_cond.notify_all(); + } + } + break; + case no_priority: + do_alt_priority_unlock(); + break; + default: + assert(0); + } + } + + sharable_mutex_policy get_policy() const + { return m_policy; } + + private: + + //Anti-exception RAII + struct counter_decrementer + { + counter_decrementer(std::size_t &count) + : m_count(count){} + ~counter_decrementer() + { --m_count; } + std::size_t &m_count; + }; + + struct a_priority_wlock_rollback + { + a_priority_wlock_rollback(interprocess_sharable_mutex *lock) + : m_lock(lock){} + + ~a_priority_wlock_rollback() + { + if(m_lock){ + m_lock->m_shared_count = -m_lock->m_completed_shared_count; + m_lock->m_completed_shared_count = 0; + } + } + + void release(){ m_lock = 0; } + + private: + interprocess_sharable_mutex *m_lock; + }; + + + bool do_sharable_lock(bool timed, const boost::posix_time::ptime *pt) + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + { + scoped_lock lock(m_mutex_exclusive_mutex); + if(m_w_active && !this->do_se_priority_s_wait(lock, timed, pt)){ + return false; + } + ++m_r_active_completed_shared_count; + } + break; + case exclusive_priority: + { + scoped_lock lock(m_mutex_exclusive_mutex); + if((m_w_active || m_w_wait_exclusive_count > 0) && + !this->do_se_priority_s_wait(lock, timed, pt)){ + return false; + } + ++m_r_active_completed_shared_count; + } + break; + + case no_priority: + { + if(timed && !pt){ + scoped_lock lock + (m_mutex_exclusive_mutex, try_to_lock); + if(!lock.locked()) return false; + + if(++m_shared_count == INT_MAX){ + //Is better to throw in this case? + //m_mutex_shared_completed.do_lock(); + scoped_lock lock(m_mutex_shared_completed); + m_shared_count -= m_completed_shared_count; + m_completed_shared_count = 0; + } + } + else if(timed){ + scoped_lock lock + (m_mutex_exclusive_mutex, *pt); + if(!lock.locked()) return false; + if(++m_shared_count == INT_MAX){ + //Is better to throw in this case? + //m_mutex_shared_completed.do_lock(); + scoped_lock lock + (m_mutex_shared_completed, *pt); + if(!lock.locked()){ + ++m_completed_shared_count; + return false; + } + m_shared_count -= m_completed_shared_count; + m_completed_shared_count = 0; + return true; + } + } + else{ + scoped_lock lock + (m_mutex_exclusive_mutex); + if(++m_shared_count == INT_MAX){ + //Is better to throw in this case? + //m_mutex_shared_completed.do_lock(); + scoped_lock lock + (m_mutex_shared_completed); + m_shared_count -= m_completed_shared_count; + m_completed_shared_count = 0; + return true; + } + } + } + break; + default: + assert(0); + return false; + } + return true; + } + + bool do_lock(bool timed, const boost::posix_time::ptime *pt) + { + assert(m_policy < max_priority); + switch(m_policy){ + case sharable_priority: + case exclusive_priority: + { + scoped_lock lock(m_mutex_exclusive_mutex); + if((m_w_active || m_r_active_completed_shared_count > 0) && + !this->do_se_priority_e_wait(lock, timed, pt)){ + return false; + } + m_w_active = 1; + } + break; + + case no_priority: + { + //Initialize scoped locks + scoped_lock lock_exclusive + (m_mutex_exclusive_mutex, dont_lock); + scoped_lock lock_shared + (m_mutex_shared_completed, dont_lock); + //Do initialization depending on lock type + if(timed && !pt){ + if(!lock_exclusive.try_lock())return false; + if(!lock_shared.try_lock()) return false; + } + else if(timed){ + if(!lock_exclusive.timed_lock(*pt))return false; + if(!lock_shared.timed_lock(*pt)) return false; + } + else{ + lock_exclusive.lock(); + lock_shared.lock(); + } + //Now do common logic + if(!do_alt_priority_e_wait(lock_shared, timed, pt)) + return false; + //We left the mutexes locked + lock_shared.release(); + lock_exclusive.release(); + return true; + } + break; + default: + assert(0); + return false; + } + return true; + } + + bool do_se_priority_s_wait(scoped_lock &lock, bool timed, const boost::posix_time::ptime *pt) + { + if(timed && !pt) return false; + //We should block + ++m_r_wait_shared_count; + counter_decrementer decrementer(m_r_wait_shared_count); + do{ + if(timed){ + if(!m_reader_shared_cond.timed_wait(lock, *pt)) + return false; + } + else{ + m_reader_shared_cond.wait(lock); + } + }while(m_w_active); + return true; + } + + bool do_se_priority_e_wait(scoped_lock &lock, bool timed, const boost::posix_time::ptime *pt) + { + if(timed && !pt) return false; + //We should block + ++m_w_wait_exclusive_count; + counter_decrementer decrementer(m_w_wait_exclusive_count); + do{ + if(timed && !exclusive_cond.timed_wait(lock, *pt)){ + return false; + } + else{ + exclusive_cond.wait(lock); + } + }while(m_w_active || m_r_active_completed_shared_count > 0); + return true; + } + + bool do_alt_priority_e_wait(scoped_lock &lock_shared, bool timed, const boost::posix_time::ptime *pt) + { + //This would be a try lock + if(timed && !pt) return false; + + if(m_exclusive_count == 0){ + if(m_completed_shared_count > 0){ + m_shared_count -= m_completed_shared_count; + m_completed_shared_count = 0; + } + if(m_shared_count > 0){ + //This logic is for timed a infinite waits + m_completed_shared_count = -m_shared_count; + a_priority_wlock_rollback rollback(this); + do{ + if(timed){ + if(!m_reader_shared_cond.timed_wait(lock_shared, *pt)){ + return false; + } + } + else{ + m_reader_shared_cond.wait(lock_shared); + } + }while (m_completed_shared_count < 0); + m_shared_count = 0; + rollback.release(); + } + } +// else{ +// //Is this case correct? +// lock_shared.release(); +// lock_exclusive.release(); +// return false; +// } + + ++m_exclusive_count; + return true; + } + + void do_alt_priority_unlock() + { + if (m_exclusive_count == 0){ + scoped_lock lock(m_mutex_exclusive_mutex); + if(++m_completed_shared_count == 0) { + m_reader_shared_cond.notify_one(); + } + } + else{ + --m_exclusive_count; + m_mutex_shared_completed.unlock(); + m_mutex_exclusive_mutex.unlock(); + } + } + + private: + + const sharable_mutex_policy m_policy; + //shared by all methods + interprocess_mutex m_mutex_exclusive_mutex; + interprocess_condition m_reader_shared_cond; + std::size_t m_r_active_completed_shared_count; + std::size_t m_r_wait_shared_count; + std::size_t m_w_wait_exclusive_count; + //Only for reader-writer + interprocess_condition exclusive_cond; + std::size_t m_w_active; + //Only for no_priority + interprocess_mutex m_mutex_shared_completed; + int m_completed_shared_count; + int m_shared_count; + int m_exclusive_count; +}; + +*/ + + +} // namespace interprocess + +} // namespace boost + +#include + +#endif + diff --git a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp new file mode 100644 index 0000000..a5bd48c --- /dev/null +++ b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -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 +#include +#include +#include +#include +#include +#include + + +/*!\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 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 + +#endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP diff --git a/include/boost/interprocess/sync/lock_options.hpp b/include/boost/interprocess/sync/lock_options.hpp new file mode 100644 index 0000000..880cca4 --- /dev/null +++ b/include/boost/interprocess/sync/lock_options.hpp @@ -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 +#include + +/*!\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 + +#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP diff --git a/include/boost/interprocess/sync/mutex_family.hpp b/include/boost/interprocess/sync/mutex_family.hpp new file mode 100644 index 0000000..6f2360f --- /dev/null +++ b/include/boost/interprocess/sync/mutex_family.hpp @@ -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 +#include + +#include +#include +#include + +/*!\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 + +#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP + + diff --git a/include/boost/interprocess/sync/named_mutex.hpp b/include/boost/interprocess/sync/named_mutex.hpp new file mode 100644 index 0000000..05918c2 --- /dev/null +++ b/include/boost/interprocess/sync/named_mutex.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +/*!\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(m_shmem.get_address())->lock(); } + +inline void named_mutex::unlock() +{ static_cast(m_shmem.get_address())->unlock(); } + +inline bool named_mutex::try_lock() +{ return static_cast(m_shmem.get_address())->try_lock(); } + +inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ return static_cast(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 + +#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP diff --git a/include/boost/interprocess/sync/named_recursive_mutex.hpp b/include/boost/interprocess/sync/named_recursive_mutex.hpp new file mode 100644 index 0000000..0ed685f --- /dev/null +++ b/include/boost/interprocess/sync/named_recursive_mutex.hpp @@ -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 +#include +#include +#include +#include +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +# include + +#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + +#include //close +#include //std::string +#include //pthread_* family +#include +# include +#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 + +#endif //BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP diff --git a/include/boost/interprocess/sync/named_semaphore.hpp b/include/boost/interprocess/sync/named_semaphore.hpp new file mode 100644 index 0000000..1b377c8 --- /dev/null +++ b/include/boost/interprocess/sync/named_semaphore.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + + +/*!\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(m_shmem.get_address())->post(); } + +inline void named_semaphore::wait() +{ static_cast(m_shmem.get_address())->wait(); } + +inline bool named_semaphore::try_wait() +{ return static_cast(m_shmem.get_address())->try_wait(); } + +inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ return static_cast(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 + +#endif //BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP diff --git a/include/boost/interprocess/sync/null_mutex.hpp b/include/boost/interprocess/sync/null_mutex.hpp new file mode 100644 index 0000000..fa7f52f --- /dev/null +++ b/include/boost/interprocess/sync/null_mutex.hpp @@ -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 +#include + + +/*!\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 + +#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP diff --git a/include/boost/interprocess/sync/posix/interprocess_condition.hpp b/include/boost/interprocess/sync/posix/interprocess_condition.hpp new file mode 100644 index 0000000..80b40a6 --- /dev/null +++ b/include/boost/interprocess/sync/posix/interprocess_condition.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 +#include + +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 diff --git a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp new file mode 100644 index 0000000..7a9ba3b --- /dev/null +++ b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp @@ -0,0 +1,261 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +////////////////////////////////////////////////////////////////////////////// + +#include +#include + + +namespace boost { + +namespace interprocess { +/* +inline interprocess_mutex::interprocess_mutex() +{ + detail::mutexattr_wrapper mut_attr; + detail::mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline interprocess_mutex::~interprocess_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + assert(res == 0);(void)res; +} + +inline void interprocess_mutex::lock() +{ + int res = pthread_mutex_lock(&m_mut); + if ( res == EDEADLK) + throw lock_exception(); + assert(res == 0); +} + +inline void interprocess_mutex::do_unlock() +{ + int res = pthread_mutex_unlock(&m_mut); + if (res == EPERM) + throw lock_exception(); + assert(res == 0); +} + +inline interprocess_mutex::interprocess_mutex() +{ + detail::mutexattr_wrapper mut_attr; + detail::mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline interprocess_mutex::~interprocess_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + assert(res == 0);(void)res; +} + +inline void interprocess_mutex::lock() +{ + if (pthread_mutex_lock(&m_mut) == EDEADLK) + throw lock_exception(); +} + +inline bool interprocess_mutex::try_lock() +{ + int res = 0; + res = pthread_mutex_trylock(&m_mut); + if (res == EDEADLK) throw lock_exception(); + assert(res == 0 || res == EBUSY); + return res == 0; +} + +inline void interprocess_mutex::do_unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); + if (res == EPERM) throw lock_exception(); + assert(res == 0); +} +*/ +//--- + +#ifdef _POSIX_TIMEOUTS + +inline interprocess_mutex::interprocess_mutex() +{ + detail::mutexattr_wrapper mut_attr; + detail::mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline interprocess_mutex::~interprocess_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + assert(res == 0);(void)res; +} + +inline void interprocess_mutex::lock() +{ + if (pthread_mutex_lock(&m_mut) != 0) + throw lock_exception(); +} + +inline bool interprocess_mutex::try_lock() +{ + int res = pthread_mutex_trylock(&m_mut); + if (res == EDEADLK) throw lock_exception(); + assert(res == 0 || res == EBUSY); + return res == 0; +} + +inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + timespec ts = detail::ptime_to_timespec(abs_time); + int res = pthread_mutex_timedlock(&m_mut, &ts); + if (res == EDEADLK || (res != 0 || res != ETIMEDOUT)) + throw lock_exception(); + return res == 0; +} + +inline void interprocess_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); +// if (res == EPERM) throw lock_exception(); + assert(res == 0); +} + +#else //#ifdef _POSIX_TIMEOUTS + +inline interprocess_mutex::interprocess_mutex() + : m_locked(false) +{ + //Mutex init + detail::mutexattr_wrapper mut_attr; + detail::mutex_initializer mut(m_mut, mut_attr); + + //Condition init + detail::condattr_wrapper cond_attr; + detail::condition_initializer cond(m_cond, cond_attr); + + mut.release(); + cond.release(); +} + +inline interprocess_mutex::~interprocess_mutex() +{ + assert(!m_locked); + int res = 0; + res = pthread_mutex_destroy(&m_mut); + assert(res == 0); + + res = pthread_cond_destroy(&m_cond); + assert(res == 0); +} + +inline void interprocess_mutex::lock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + while (m_locked){ + res = pthread_cond_wait(&m_cond, &m_mut); + assert(res == 0); + } + + assert(!m_locked); + m_locked = true; + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); +} + +inline bool interprocess_mutex::try_lock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + bool ret = false; + if (!m_locked) + { + m_locked = true; + ret = true; + } + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); + return ret; +} + +inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + timespec ts = detail::ptime_to_timespec(abs_time); + + while (m_locked) + { + res = pthread_cond_timedwait(&m_cond, &m_mut, &ts); + assert(res == 0 || res == ETIMEDOUT); + + if (res == ETIMEDOUT) + break; + } + + bool ret = false; + if (!m_locked) + { + m_locked = true; + ret = true; + } + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); + return ret; +} + +inline void interprocess_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + assert(m_locked); + m_locked = false; + + res = pthread_cond_signal(&m_cond); + assert(res == 0); + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); +} + +#endif //#ifdef _POSIX_TIMEOUTS + +} //namespace interprocess { + +} //namespace boost { diff --git a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp new file mode 100644 index 0000000..3f86fa8 --- /dev/null +++ b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp @@ -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. +// +////////////////////////////////////////////////////////////////////////////// +// +// 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. +////////////////////////////////////////////////////////////////////////////// + +#include +#include + +namespace boost { + +namespace interprocess { + +#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined _POSIX_TIMEOUTS +inline interprocess_recursive_mutex::interprocess_recursive_mutex() +{ + detail::mutexattr_wrapper mut_attr(true); + detail::mutex_initializer mut(m_mut, mut_attr); + mut.release(); +} + +inline interprocess_recursive_mutex::~interprocess_recursive_mutex() +{ + int res = pthread_mutex_destroy(&m_mut); + assert(res == 0);(void)res; +} + +inline void interprocess_recursive_mutex::lock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + if (res == EDEADLK) throw lock_exception(); + assert(res == 0); +} + +inline bool interprocess_recursive_mutex::try_lock() +{ + int res = 0; + res = pthread_mutex_trylock(&m_mut); + if (res == EDEADLK) throw lock_exception(); + assert(res == 0 || res == EBUSY); + return res == 0; +} + +inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + timespec ts = detail::ptime_to_timespec(abs_time); + int res = pthread_mutex_timedlock(&m_mut, &ts); + if (res == EDEADLK) throw lock_exception(); + assert(res == 0 || res == EBUSY); + return res == 0; +} + +inline void interprocess_recursive_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_unlock(&m_mut); + if (res == EPERM) throw lock_exception(); + assert(res == 0); +} + +#else //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined _POSIX_TIMEOUTS + +inline interprocess_recursive_mutex::interprocess_recursive_mutex() + : m_valid_id(false), m_count(0) +{ + //Mutex init + detail::mutexattr_wrapper mut_attr; + detail::mutex_initializer mut(m_mut, mut_attr); + + //Condition init + detail::condattr_wrapper cond_attr; + detail::condition_initializer cond(m_unlocked, cond_attr); + + mut.release(); + cond.release(); +} + +inline interprocess_recursive_mutex::~interprocess_recursive_mutex() +{ + int res = 0; + res = pthread_mutex_destroy(&m_mut); + assert(res == 0); + + res = pthread_cond_destroy(&m_unlocked); + assert(res == 0); +} + +inline void interprocess_recursive_mutex::lock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + pthread_t tid = pthread_self(); + if (m_valid_id && pthread_equal(m_thread_id, tid)){ + ++m_count; + } + else{ + while (m_valid_id) + { + res = pthread_cond_wait(&m_unlocked, &m_mut); + assert(res == 0); + } + + m_thread_id = tid; + m_valid_id = true; + m_count = 1; + } + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); +} + +inline bool interprocess_recursive_mutex::try_lock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + bool ret = false; + pthread_t tid = pthread_self(); + if (m_valid_id && pthread_equal(m_thread_id, tid)){ + ++m_count; + ret = true; + } + else if (!m_valid_id){ + m_thread_id = tid; + m_valid_id = true; + m_count = 1; + ret = true; + } + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); + return ret; +} + +inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + bool ret = false; + pthread_t tid = pthread_self(); + if (m_valid_id && pthread_equal(m_thread_id, tid)){ + ++m_count; + ret = true; + } + else{ + timespec ts = detail::ptime_to_timespec(abs_time); + + while (m_valid_id){ + res = pthread_cond_timedwait(&m_unlocked, &m_mut, &ts); + if (res == ETIMEDOUT) + break; + assert(res == 0); + } + + if (!m_valid_id){ + m_thread_id = tid; + m_valid_id = true; + m_count = 1; + ret = true; + } + } + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); + return ret; +} + +inline void interprocess_recursive_mutex::unlock() +{ + int res = 0; + res = pthread_mutex_lock(&m_mut); + assert(res == 0); + + pthread_t tid = pthread_self(); + if (m_valid_id && !pthread_equal(m_thread_id, tid)){ + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); + throw lock_exception(); + } + + if (--m_count == 0){ + assert(m_valid_id); + m_valid_id = false; + + res = pthread_cond_signal(&m_unlocked); + assert(res == 0); + } + + res = pthread_mutex_unlock(&m_mut); + assert(res == 0); +} + +#endif //_POSIX_VERSION >= 200112L + +} //namespace interprocess { + +} //namespace boost { diff --git a/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp b/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp new file mode 100644 index 0000000..abf74a1 --- /dev/null +++ b/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include + +namespace boost { + +namespace interprocess { + +inline interprocess_semaphore::~interprocess_semaphore() +{} + +inline interprocess_semaphore::interprocess_semaphore(int initialCount) + : m_sem(initialCount) +{} + +inline void interprocess_semaphore::post() +{ m_sem.post(); } + +inline void interprocess_semaphore::wait() +{ m_sem.wait(); } + +inline bool interprocess_semaphore::try_wait() +{ return m_sem.try_wait(); } + +inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ return m_sem.timed_wait(abs_time); } +/* +inline int interprocess_semaphore::get_count() const +{ return m_sem.get_count(); } +*/ +} //namespace interprocess { + +} //namespace boost { + diff --git a/include/boost/interprocess/sync/posix/pthread_helpers.hpp b/include/boost/interprocess/sync/posix/pthread_helpers.hpp new file mode 100644 index 0000000..7ac04d5 --- /dev/null +++ b/include/boost/interprocess/sync/posix/pthread_helpers.hpp @@ -0,0 +1,162 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PTHREAD_HELPERS_HPP +#define BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace detail{ + + /*!Makes pthread_mutexattr_t cleanup easy when using exceptions*/ + struct mutexattr_wrapper + { + /*!Constructor*/ + mutexattr_wrapper(bool recursive = false) + { + if(pthread_mutexattr_init(&m_attr)!=0 || + pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 || + (recursive && + pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 )) + throw boost::interprocess::interprocess_exception(); + } + + /*!Destructor*/ + ~mutexattr_wrapper() { pthread_mutexattr_destroy(&m_attr); } + + /*!This allows using mutexattr_wrapper as pthread_mutexattr_t*/ + operator pthread_mutexattr_t&() { return m_attr; } + + pthread_mutexattr_t m_attr; + }; + + /*!Makes pthread_condattr_t cleanup easy when using exceptions*/ + struct condattr_wrapper + { + /*!Constructor*/ + condattr_wrapper() + { + if(pthread_condattr_init(&m_attr)!=0 || + pthread_condattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0) + throw boost::interprocess::interprocess_exception(); + } + + /*!Destructor*/ + ~condattr_wrapper() { pthread_condattr_destroy(&m_attr); } + + /*!This allows using condattr_wrapper as pthread_condattr_t*/ + operator pthread_condattr_t&(){ return m_attr; } + + pthread_condattr_t m_attr; + }; + + /*!Makes pthread_barrierattr_t cleanup easy when using exceptions*/ + struct barrierattr_wrapper + { + /*!Constructor*/ + barrierattr_wrapper() + { + if(pthread_barrierattr_init(&m_attr)!=0 || + pthread_barrierattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0) + throw boost::interprocess::interprocess_exception(); + } + + /*!Destructor*/ + ~barrierattr_wrapper() { pthread_barrierattr_destroy(&m_attr); } + + /*!This allows using mutexattr_wrapper as pthread_barrierattr_t*/ + operator pthread_barrierattr_t&() { return m_attr; } + + pthread_barrierattr_t m_attr; + }; + + /*!Makes initialized pthread_mutex_t cleanup easy when using exceptions*/ + class mutex_initializer + { + public: + /*!Constructor. Takes interprocess_mutex attributes to initialize the interprocess_mutex*/ + mutex_initializer(pthread_mutex_t &mut, pthread_mutexattr_t &mut_attr) + : mp_mut(&mut) + { + if(pthread_mutex_init(mp_mut, &mut_attr) != 0) + throw boost::interprocess::interprocess_exception(); + } + + ~mutex_initializer() { if(mp_mut) pthread_mutex_destroy(mp_mut); } + + void release() {mp_mut = 0; } + + private: + pthread_mutex_t *mp_mut; + }; + + /*!Makes initialized pthread_cond_t cleanup easy when using exceptions*/ + class condition_initializer + { + public: + condition_initializer(pthread_cond_t &cond, pthread_condattr_t &cond_attr) + : mp_cond(&cond) + { + if(pthread_cond_init(mp_cond, &cond_attr)!= 0) + throw boost::interprocess::interprocess_exception(); + } + + ~condition_initializer() { if(mp_cond) pthread_cond_destroy(mp_cond); } + + void release() { mp_cond = 0; } + + private: + pthread_cond_t *mp_cond; + }; + + /*!Makes initialized pthread_barrier_t cleanup easy when using exceptions*/ + class barrier_initializer + { + public: + /*!Constructor. Takes barrier attributes to initialize the barrier*/ + barrier_initializer(pthread_barrier_t &mut, + pthread_barrierattr_t &mut_attr, + int count) + : mp_barrier(&mut) + { + if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0) + throw boost::interprocess::interprocess_exception(); + } + + ~barrier_initializer() { if(mp_barrier) pthread_barrier_destroy(mp_barrier); } + + void release() {mp_barrier = 0; } + + private: + pthread_barrier_t *mp_barrier; + }; + +}//namespace detail + +}//namespace interprocess + +}//namespace boost + +#include + +#endif //ifdef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP diff --git a/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp b/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp new file mode 100644 index 0000000..8c6317d --- /dev/null +++ b/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_PTIME_TO_TIMESPEC_HPP +#define BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP + +#include +#include +#include + +namespace boost { + +namespace interprocess { + +namespace detail { + +inline timespec ptime_to_timespec (const boost::posix_time::ptime &tm) +{ + const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); + boost::posix_time::time_duration duration (tm - epoch); + timespec ts; + ts.tv_sec = duration.seconds(); + ts.tv_nsec = duration.total_nanoseconds() % 1000000000; + return ts; +} + +} //namespace detail { + +} //namespace interprocess { + +} //namespace boost { + +#endif //ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp new file mode 100644 index 0000000..1a2fde9 --- /dev/null +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -0,0 +1,99 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_POSIX_SEMAPHORE_WRAPPER_HPP +#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP + +#include +#include +#include + +namespace boost { +namespace interprocess { +namespace detail { + +class semaphore_wrapper : private boost::noncopyable +{ + public: + semaphore_wrapper(int initialCount) + { + if(sem_init(&m_sem, 1, initialCount) != 0){ + throw interprocess_exception(system_error_code()); + } + } + + ~semaphore_wrapper() + { + if(sem_destroy(&m_sem) != 0){ + assert(0); + } + } + + void post() + { + if(sem_post(&m_sem) != 0){ + throw interprocess_exception(system_error_code()); + } + } + + void wait() + { + if(sem_wait(&m_sem) != 0){ + throw interprocess_exception(system_error_code()); + } + } + + bool try_wait() + { + int res = sem_trywait(&m_sem); + if(res == 0) + return true; + if(system_error_code() == EAGAIN){ + return false; + } + throw interprocess_exception(system_error_code()); + return false; + } + + bool timed_wait(const boost::posix_time::ptime &abs_time) + { + timespec tspec = detail::ptime_to_timespec(abs_time); + for (;;){ + int res = sem_timedwait(&m_sem, &tspec); + if(res == 0) + return true; + if (res > 0){ + //buggy glibc, copy the returned error code to errno + errno = res; + } + if(system_error_code() == ETIMEDOUT){ + return false; + } + throw interprocess_exception(system_error_code()); + } + return false; + } +/* + int get_count()const + { + int count; + sem_getvalue(&m_sem, &ret); + return count; + } +*/ + private: + sem_t m_sem; +}; + +} //namespace detail { +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp new file mode 100644 index 0000000..b73025f --- /dev/null +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -0,0 +1,125 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SCOPED_LOCK_HPP +#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +/*!\file + Describes the scoped_lock and scoped_try_lock classes needed to use shared + interprocess_mutex familiy synchronization objects +*/ + +namespace boost { +namespace interprocess { + +template +class scoped_lock +{ + private: + typedef scoped_lock this_type; + scoped_lock(scoped_lock const&); + scoped_lock& operator= (scoped_lock const&); + typedef bool this_type::*unspecified_bool_type; + + public: + typedef Mutex mutex_type; + + explicit scoped_lock(mutex_type& m) + : mp_mutex(&m), m_locked(false) + { mp_mutex->lock(); m_locked = true; } + + scoped_lock(mutex_type& m, detail::dont_lock_t) + : mp_mutex(&m), m_locked(false) + {} + + scoped_lock(mutex_type& m, detail::try_to_lock_t) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->try_lock(); } + + scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->timed_lock(abs_time); } + + ~scoped_lock() + { + try{ if(m_locked && mp_mutex) mp_mutex->unlock(); } + catch(...){} + } + + void lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + mp_mutex->lock(); + m_locked = true; + } + + bool try_lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock(); + return m_locked; + } + + bool timed_lock(const boost::posix_time::ptime& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->timed_lock(abs_time); + return m_locked; + } + + void unlock() + { + if(!mp_mutex || !m_locked) + throw lock_exception(); + mp_mutex->unlock(); + m_locked = false; + } + + bool locked() const + { return m_locked; } + + operator unspecified_bool_type() const + { return m_locked? &this_type::m_locked : 0; } + + mutex_type* interprocess_mutex() const + { return mp_mutex; } + + mutex_type* release() + { + mutex_type *mut = mp_mutex; + mp_mutex = 0; + return mut; + } + + private: + mutex_type *mp_mutex; + bool m_locked; +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp new file mode 100644 index 0000000..f349ea5 --- /dev/null +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -0,0 +1,133 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_SHARABLE_LOCK_HPP +#define BOOST_INTERPROCESS_SHARABLE_LOCK_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +/*!\file + Describes the scoped_lock and scoped_try_lock classes needed to use shared + interprocess_mutex familiy synchronization objects +*/ + +namespace boost { +namespace interprocess { + +template +class scoped_lock; + +template +class sharable_lock +{ + public: + typedef SharableMutex mutex_type; + + private: + typedef sharable_lock this_type; + sharable_lock(sharable_lock const&); + explicit sharable_lock(scoped_lock const&); + typedef bool this_type::*unspecified_bool_type; + sharable_lock& operator=(sharable_lock const&); + sharable_lock& operator=(scoped_lock const&); + + public: + explicit sharable_lock(mutex_type& m) + : mp_mutex(&m), m_locked(false) + { mp_mutex->lock_sharable(); m_locked = true; } + + sharable_lock(mutex_type& m, detail::dont_lock_t) + : mp_mutex(&m), m_locked(false) + {} + + sharable_lock(mutex_type& m, detail::try_to_lock_t) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->try_lock_sharable(); } + + sharable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time) + : mp_mutex(&m), m_locked(false) + { m_locked = mp_mutex->timed_lock_sharable(abs_time); } + + ~sharable_lock() + { + try{ + if(m_locked && mp_mutex) mp_mutex->unlock_sharable(); + } + catch(...){} + } + + void lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + mp_mutex->lock_sharable(); + m_locked = true; + } + + bool try_lock() + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->try_lock_sharable(); + return m_locked; + } + + bool timed_lock(const boost::posix_time::ptime& abs_time) + { + if(!mp_mutex || m_locked) + throw lock_exception(); + m_locked = mp_mutex->timed_lock_sharable(abs_time); + return m_locked; + } + + void unlock() + { + if(!mp_mutex || !m_locked) + throw lock_exception(); + mp_mutex->unlock_sharable(); + m_locked = false; + } + + bool locked() const + { return m_locked; } + + operator unspecified_bool_type() const + { return m_locked? &this_type::m_locked : 0; } + + mutex_type* interprocess_mutex() const + { return mp_mutex; } + + mutex_type* release() + { + mutex_type *mut = mp_mutex; + mp_mutex = 0; + return mut; + } + + private: + mutex_type *mp_mutex; // exposition only + bool m_locked; // exposition only +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_SHARABLE_LOCK_HPP diff --git a/include/boost/interprocess/sync/win32/interprocess_condition.hpp b/include/boost/interprocess/sync/win32/interprocess_condition.hpp new file mode 100644 index 0000000..7e0eded --- /dev/null +++ b/include/boost/interprocess/sync/win32/interprocess_condition.hpp @@ -0,0 +1,186 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +namespace boost { + +namespace interprocess { + + +inline interprocess_condition::interprocess_condition() +{ + m_command = SLEEP; + m_num_waiters = 0; +} + +inline interprocess_condition::~interprocess_condition() +{} + + +inline void interprocess_condition::notify_one() +{ + notify(NOTIFY_ONE); +} + +inline void interprocess_condition::notify_all() +{ + notify(NOTIFY_ALL); +} + +inline void interprocess_condition::notify(long command) +{ + //This interprocess_mutex guarantees that no other thread can enter to the + //do_timed_wait method logic, so that thread count will be + //constant until the function writes a NOTIFY_ALL command. + //It also guarantees that no other notification can be signaled + //on this interprocess_condition before this one ends + using namespace boost::detail; + m_enter_mut.lock(); + + //Return if there are no waiters + if(!winapi::exchange_and_add(&m_num_waiters, 0)) { + m_enter_mut.unlock(); + return; + } + + //Notify that all threads should execute wait logic + BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_command, command, SLEEP); + //The enter interprocess_mutex will rest locked until the last waiting thread unlocks it +} + +inline void interprocess_condition::do_wait(interprocess_mutex &mut) +{ + do_timed_wait(false, boost::posix_time::ptime(), mut); +} + +inline bool interprocess_condition::do_timed_wait + (const boost::posix_time::ptime &abs_time, interprocess_mutex &mut) +{ + return do_timed_wait(true, abs_time, mut); +} + +inline bool interprocess_condition::do_timed_wait(bool tout_enabled, + const boost::posix_time::ptime &abs_time, + interprocess_mutex &mut) +{ + using namespace boost::detail; + boost::posix_time::ptime now = + boost::posix_time::microsec_clock::universal_time(); + + if(tout_enabled){ + if(now >= abs_time) return false; + } + + //The enter interprocess_mutex guarantees that while executing a notification, + //no other thread can execute the do_timed_wait method. + { + //--------------------------------------------------------------- + boost::interprocess::scoped_lock lock(m_enter_mut); + //--------------------------------------------------------------- + //We increment the waiting thread count protected so that it will be + //always constant when another thread enters the notification logic. + //The increment marks this thread as "waiting on interprocess_condition" + BOOST_INTERLOCKED_INCREMENT((long*)&m_num_waiters); + + //We unlock the external interprocess_mutex atomically with the increment + mut.unlock(); + } + + //By default, we suppose that no timeout has happened + bool timed_out = false, unlock_enter_mut= false; + + //Loop until a notification indicates that the thread should + //exit or timeout occurs + while(1){ + //The thread sleeps/spins until a interprocess_condition commands a notification + //Notification occurred, we will lock the checking interprocess_mutex so that + while(winapi::exchange_and_add(&m_command, 0) == SLEEP){ + winapi::sched_yield(); + + //Check for timeout + if(tout_enabled){ + now = boost::posix_time::microsec_clock::universal_time(); + + if(now >= abs_time){ + //If we can lock the interprocess_mutex it means that no notification + //is being executed in this interprocess_condition variable + timed_out = m_enter_mut.try_lock(); + + //If locking fails, indicates that another thread is executing + //notification, so we play the notification game + if(!timed_out){ + //There is an ongoing notification, we will try again later + continue; + } + //No notification in execution, since enter interprocess_mutex is locked. + //We will execute time-out logic, so we will decrement count, + //release the enter interprocess_mutex and return false. + break; + } + } + } + + //If a timeout occurred, the interprocess_mutex will not execute checking logic + if(tout_enabled && timed_out){ + //Decrement wait count + BOOST_INTERLOCKED_DECREMENT((long*)&m_num_waiters); + unlock_enter_mut = true; + break; + } + else{ + //Notification occurred, we will lock the checking interprocess_mutex so that + //if a notify_one notification occurs, only one thread can exit + //--------------------------------------------------------------- + boost::interprocess::scoped_lock lock(m_check_mut); + //--------------------------------------------------------------- + long result = BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_command, SLEEP, NOTIFY_ONE); + if(result == SLEEP){ + //Other thread has been notified and since it was a NOTIFY one + //command, this thread must sleep again + continue; + } + else if(result == NOTIFY_ONE){ + //If it was a NOTIFY_ONE command, only this thread should + //exit. This thread has atomically marked command as sleep before + //so no other thread will exit. + //Decrement wait count. + unlock_enter_mut = true; + BOOST_INTERLOCKED_DECREMENT((long*)&m_num_waiters); + break; + } + else{ + //If it is a NOTIFY_ALL command, all threads should return + //from do_timed_wait function. Decrement wait count. + unlock_enter_mut = BOOST_INTERLOCKED_DECREMENT((long*)&m_num_waiters) == 0; + //Check if this is the last thread of notify_all waiters + //Only the last thread will release the interprocess_mutex + if(unlock_enter_mut){ + BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_command, SLEEP, NOTIFY_ALL); + } + break; + } + } + } + + //Unlock the enter interprocess_mutex if it is a single notification, if this is + //the last notified thread in a notify_all or a timeout has occurred + if(unlock_enter_mut){ + m_enter_mut.unlock(); + } + + //Lock external again before returning from the method + mut.lock(); + return !timed_out; +} + +} //namespace interprocess + +} // namespace boost diff --git a/include/boost/interprocess/sync/win32/interprocess_mutex.hpp b/include/boost/interprocess/sync/win32/interprocess_mutex.hpp new file mode 100644 index 0000000..69efa0b --- /dev/null +++ b/include/boost/interprocess/sync/win32/interprocess_mutex.hpp @@ -0,0 +1,120 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +////////////////////////////////////////////////////////////////////////////// + +#include + +namespace boost { + +namespace interprocess { + +inline static void do_lock_func(volatile long &m_s) +{ + using namespace boost::detail; + do{ + long prev_s = BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_s, 0, 1); + + if (m_s == 0 && prev_s == 1){ + break; + } + // relinquish current timeslice + winapi::sched_yield(); + }while (true); +} + +inline static bool do_trylock_func(volatile long &m_s) +{ + using namespace boost::detail; + long prev_s = BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_s, 0, 1); + + if (m_s == 0 && prev_s == 1){ + return true; + } + return false; +} + +inline static bool do_timedlock_func(volatile long &m_s, 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{ + long prev_s = BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_s, 0, 1); + + if (m_s == 0 && prev_s == 1){ + break; + } + now = boost::posix_time::microsec_clock::universal_time(); + + if(now >= abs_time){ + return false; + } + // relinquish current time slice + winapi::sched_yield(); + }while (true); + + return true; +} + +inline static void do_unlock_func(volatile long &m_s) +{ + using namespace boost::detail; + BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)&m_s, 1, 0); +} + +inline interprocess_mutex::interprocess_mutex() + : m_s(1) +{} + +inline interprocess_mutex::~interprocess_mutex() +{} + +inline void interprocess_mutex::lock(void) +{ + do_lock_func(m_s); +} + +inline bool interprocess_mutex::try_lock(void) +{ + return do_trylock_func(m_s); +} + +inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + return do_timedlock_func(m_s, abs_time); +} + +inline void interprocess_mutex::unlock(void) +{ + do_unlock_func(m_s); +} + +} //namespace interprocess { + +} //namespace boost { diff --git a/include/boost/interprocess/sync/win32/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/win32/interprocess_recursive_mutex.hpp new file mode 100644 index 0000000..3519154 --- /dev/null +++ b/include/boost/interprocess/sync/win32/interprocess_recursive_mutex.hpp @@ -0,0 +1,96 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +////////////////////////////////////////////////////////////////////////////// + +#include + +namespace boost { + +namespace interprocess { + +inline interprocess_recursive_mutex::interprocess_recursive_mutex() + : m_nLockCount(0), m_nOwner(0xffffffff){} + +inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} + +inline void interprocess_recursive_mutex::lock() +{ + unsigned long pNumber = winapi::current_thread_id(); + if(pNumber == m_nOwner){ + ++m_nLockCount; + } + else{ + m_shared_timed_mutex.lock(); + m_nOwner = pNumber; + ++m_nLockCount; + } +} + +inline bool interprocess_recursive_mutex::try_lock() +{ + unsigned long pNumber = winapi::current_thread_id(); + if(pNumber == m_nOwner) { // we own it + ++m_nLockCount; + return true; + } + if(m_shared_timed_mutex.try_lock()){ + m_nOwner = pNumber; + ++m_nLockCount; + return true; + } + return false; +} + +inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) +{ + unsigned long pNumber = winapi::current_thread_id(); + if(pNumber == m_nOwner) { // we own it + ++m_nLockCount; + return true; + } + if(m_shared_timed_mutex.timed_lock(abs_time)){ + m_nOwner = pNumber; + ++m_nLockCount; + return true; + } + return false; +} + +inline void interprocess_recursive_mutex::unlock() +{ + unsigned long pNumber = winapi::current_thread_id(); + assert(pNumber == m_nOwner); + --m_nLockCount; + if(!m_nLockCount){ + m_nOwner = m_nLockCount; + --m_nOwner; + m_shared_timed_mutex.unlock(); + } +} + +} //namespace interprocess { + +} //namespace boost { + diff --git a/include/boost/interprocess/sync/win32/interprocess_semaphore.hpp b/include/boost/interprocess/sync/win32/interprocess_semaphore.hpp new file mode 100644 index 0000000..705a3e0 --- /dev/null +++ b/include/boost/interprocess/sync/win32/interprocess_semaphore.hpp @@ -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. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +namespace boost { +namespace interprocess { + +inline interprocess_semaphore::~interprocess_semaphore() +{} + +inline interprocess_semaphore::interprocess_semaphore(int initialCount) + : m_mut(), m_cond(), m_count(initialCount) +{} + +inline void interprocess_semaphore::post() +{ + scoped_lock lock(m_mut); + if(m_count == 0){ + m_cond.notify_one(); + } + ++m_count; +} + +inline void interprocess_semaphore::wait() +{ + scoped_lock lock(m_mut); + while(m_count == 0){ + m_cond.wait(lock); + } + --m_count; +} + +inline bool interprocess_semaphore::try_wait() +{ + scoped_lock lock(m_mut); + if(m_count == 0){ + return false; + } + --m_count; + return true; +} + +inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) +{ + scoped_lock lock(m_mut); + while(m_count == 0){ + if(!m_cond.timed_wait(lock, abs_time)) + return false; + } + --m_count; + return true; +} +/* +inline int interprocess_semaphore::get_count() const +{ + scoped_lock lock(m_mut); + return count; +}*/ + +} //namespace interprocess { +} //namespace boost { diff --git a/include/boost/interprocess/sync/win32/win32_sync_primitives.hpp b/include/boost/interprocess/sync/win32/win32_sync_primitives.hpp new file mode 100644 index 0000000..0a195d4 --- /dev/null +++ b/include/boost/interprocess/sync/win32/win32_sync_primitives.hpp @@ -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_WIN32_SYNC_PRIMITIVES_HPP +#define BOOST_INTERPROCESS_WIN32_SYNC_PRIMITIVES_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +# include +# include +# include +#else +# error "This file can only be included in Windows OS" +#endif + +//The structures used in Interprocess with the +//same binary interface as windows ones +namespace boost { +namespace interprocess { +namespace winapi { + +//Some used constants +static const unsigned long infinite_time = 0xFFFFFFFF; +static const unsigned long error_already_exists = 183L; +static const unsigned long error_file_not_found = 2u; + +static const unsigned long semaphore_all_access = (0x000F0000L)|(0x00100000L)|0x3; +static const unsigned long mutex_all_access = (0x000F0000L)|(0x00100000L)|0x0001; + +static const unsigned long page_readonly = 0x02; +static const unsigned long page_readwrite = 0x04; + +static const unsigned long file_map_read = 0x0004; +static const unsigned long file_map_write = 0x0002; +static const unsigned long file_map_all_access = (0x000F0000L) | (0x0001) | + file_map_write | file_map_read | + (0x0008)| (0x0010); + +static const unsigned long file_share_read = 0x00000001; +static const unsigned long file_share_write = 0x00000002; + +static const unsigned long generic_read = 0x80000000L; +static const unsigned long generic_write = 0x40000000L; + +static const unsigned long wait_object_0 = 0; +static const unsigned long wait_abandoned = 0x00000080L; +static const unsigned long wait_timeout = 258L; +static const unsigned long wait_failed = (unsigned long)0xFFFFFFFF; + +static const unsigned long format_message_allocate_buffer + = (unsigned long)0x00000100; +static const unsigned long format_message_ignore_inserts + = (unsigned long)0x00000200; +static const unsigned long format_message_from_string + = (unsigned long)0x00000400; +static const unsigned long format_message_from_hmodule + = (unsigned long)0x00000800; +static const unsigned long format_message_from_system + = (unsigned long)0x00001000; +static const unsigned long format_message_argument_array + = (unsigned long)0x00002000; +static const unsigned long format_message_max_width_mask + = (unsigned long)0x000000FF; +static const unsigned long lang_neutral = (unsigned long)0x00; +static const unsigned long sublang_default = (unsigned long)0x01; +static const unsigned long invalid_file_size = (unsigned long)0xFFFFFFFF; +static void * const invalid_handle_value = (void*)(long*)-1; +static const unsigned long create_new = 1; +static const unsigned long create_always = 2; +static const unsigned long open_existing = 3; +static const unsigned long open_always = 4; +static const unsigned long truncate_existing = 5; + +static const unsigned long file_attribute_temporary = 0x00000100; + +static const unsigned long file_begin = 0; +static const unsigned long file_current = 1; +static const unsigned long file_end = 2; + +static const unsigned long lockfile_fail_immediately = 1; +static const unsigned long lockfile_exclusive_lock = 2; +static const unsigned long error_lock_violation = 33; + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + +#if !defined( BOOST_USE_WINDOWS_H ) + +namespace boost { +namespace interprocess { +namespace winapi { + +struct interprocess_overlapped +{ + unsigned long *internal; + unsigned long *internal_high; + union { + struct { + unsigned long offset; + unsigned long offset_high; + }; + void *pointer; + }; + + void *h_event; +}; + +struct interprocess_filetime +{ + unsigned long dwLowDateTime; + unsigned long dwHighDateTime; +}; + +struct interprocess_security_attributes +{ + unsigned long nLength; + void *lpSecurityDescriptor; + int bInheritHandle; +}; + +struct system_info { + union { + unsigned long dwOemId; // Obsolete field...do not use + struct { + unsigned short wProcessorArchitecture; + unsigned short wReserved; + }; + }; + unsigned long dwPageSize; + void * lpMinimumApplicationAddress; + void * lpMaximumApplicationAddress; + unsigned long * dwActiveProcessorMask; + unsigned long dwNumberOfProcessors; + unsigned long dwProcessorType; + unsigned long dwAllocationGranularity; + unsigned short wProcessorLevel; + unsigned short wProcessorRevision; +}; + +//Some windows API declarations +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); +extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); +extern "C" __declspec(dllimport) unsigned long __stdcall GetLastError(); +extern "C" __declspec(dllimport) int __stdcall CloseHandle(void*); +extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(interprocess_filetime*); +extern "C" __declspec(dllimport) void * __stdcall CreateMutexA(interprocess_security_attributes*, int, const char *); +extern "C" __declspec(dllimport) void * __stdcall OpenMutexA(unsigned long, int, const char *); +extern "C" __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void *, unsigned long); +extern "C" __declspec(dllimport) int __stdcall ReleaseMutex(void *); +extern "C" __declspec(dllimport) int __stdcall UnmapViewOfFile(void *); +extern "C" __declspec(dllimport) void * __stdcall CreateSemaphoreA(interprocess_security_attributes*, long, long, const char *); +extern "C" __declspec(dllimport) int __stdcall ReleaseSemaphore(void *, long, long *); +extern "C" __declspec(dllimport) void * __stdcall OpenSemaphoreA(unsigned long, int, const char *); +extern "C" __declspec(dllimport) void * __stdcall CreateFileMappingA (void *, interprocess_security_attributes*, unsigned long, unsigned long, unsigned long, const char *); +extern "C" __declspec(dllimport) void * __stdcall MapViewOfFileEx (void *, unsigned long, unsigned long, unsigned long, size_t, void*); +extern "C" __declspec(dllimport) void * __stdcall OpenFileMappingA (unsigned long, int, const char *); +extern "C" __declspec(dllimport) void * __stdcall CreateFileA (const char *, unsigned long, unsigned long, struct _SECURITY_ATTRIBUTES*, unsigned long, unsigned long, void *); +extern "C" __declspec(dllimport) int __stdcall DeleteFileA (const char *); +extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *); +extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, size_t); +extern "C" __declspec(dllimport) int __stdcall GetFileSizeEx (void *, __int64 *size); +extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA + (unsigned long dwFlags, const void *lpSource, unsigned long dwMessageId, + unsigned long dwLanguageId, char *lpBuffer, unsigned long nSize, + va_list *Arguments); +extern "C" __declspec(dllimport) void *__stdcall LocalFree (void *); +extern "C" __declspec(dllimport) int __stdcall CreateDirectoryA(const char *, interprocess_security_attributes*); +extern "C" __declspec(dllimport) int __stdcall GetTempPathA(unsigned long length, char *buffer); +extern "C" __declspec(dllimport) int __stdcall CreateDirectory(const char *, interprocess_security_attributes*); +extern "C" __declspec(dllimport) int __stdcall SetFileValidData(void *, __int64 size); +extern "C" __declspec(dllimport) int __stdcall SetEndOfFile(void *); +extern "C" __declspec(dllimport) int __stdcall SetFilePointerEx(void *, __int64 distance, __int64 *new_file_pointer, unsigned long move_method); +extern "C" __declspec(dllimport) int __stdcall LockFile (void *hnd, unsigned long offset_low, unsigned long offset_high, unsigned long size_low, unsigned long size_high); +extern "C" __declspec(dllimport) int __stdcall UnlockFile(void *hnd, unsigned long offset_low, unsigned long offset_high, unsigned long size_low, unsigned long size_high); +extern "C" __declspec(dllimport) int __stdcall LockFileEx(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped* overlapped); +extern "C" __declspec(dllimport) long __stdcall InterlockedIncrement( long volatile * ); +extern "C" __declspec(dllimport) long __stdcall InterlockedDecrement( long volatile * ); +extern "C" __declspec(dllimport) long __stdcall InterlockedCompareExchange( long volatile *, long, long ); +extern "C" __declspec(dllimport) long __stdcall InterlockedExchangeAdd(long volatile *, long); + +} //namespace winapi { +} //namespace interprocess { +} //namespace boost { + +#else +# include +#endif //#if !defined( BOOST_USE_WINDOWS_H ) + +namespace boost { +namespace interprocess { +namespace winapi { + +static inline unsigned long format_message + (unsigned long dwFlags, const void *lpSource, + unsigned long dwMessageId, unsigned long dwLanguageId, + char *lpBuffer, unsigned long nSize, va_list *Arguments) +{ + return FormatMessageA + (dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); +} + +//And now, wrapper functions +static inline void * local_free(void *hmem) +{ return LocalFree(hmem); } + +static inline unsigned long make_lang_id(unsigned long p, unsigned long s) +{ return ((((unsigned short)(s)) << 10) | (unsigned short)(p)); } + +static inline void sched_yield() +{ Sleep(1); } + +static inline unsigned long current_thread_id() +{ return GetCurrentThreadId(); } + +static inline unsigned int close_handle(void* handle) +{ return CloseHandle(handle); } + +static inline unsigned long get_last_error() +{ return GetLastError(); } + +static inline void get_system_time_as_file_time(interprocess_filetime *filetime) +{ GetSystemTimeAsFileTime(filetime); } + +static inline void *create_mutex(const char *name) +{ return CreateMutexA(0, 0, name); } + +static inline void *open_mutex(const char *name) +{ return OpenMutexA(mutex_all_access, 0, name); } + +static inline unsigned long wait_for_single_object(void *handle, unsigned long time) +{ return WaitForSingleObject(handle, time); } + +static inline int release_mutex(void *handle) +{ return ReleaseMutex(handle); } + +static inline int unmap_view_of_file(void *address) +{ return UnmapViewOfFile(address); } + +static inline void *create_semaphore(long initialCount, const char *name) +{ return CreateSemaphoreA(0, initialCount, (long)(((unsigned long)(-1))>>1), name); } + +static inline int release_semaphore(void *handle, long release_count, long *prev_count) +{ return ReleaseSemaphore(handle, release_count, prev_count); } + +static inline void *open_semaphore(const char *name) +{ return OpenSemaphoreA(semaphore_all_access, 1, name); } + +static inline void * create_file_mapping (void * handle, unsigned long access, unsigned long high_size, unsigned long low_size, const char * name) +{ return CreateFileMappingA (handle, 0, access, high_size, low_size, name); } + +static inline void * open_file_mapping (unsigned long access, const char *name) +{ return OpenFileMappingA (access, 0, name); } + +static inline void *map_view_of_file_ex(void *handle, unsigned long file_access, unsigned long highoffset, unsigned long lowoffset, std::size_t numbytes, void *base_addr) +{ return MapViewOfFileEx(handle, file_access, highoffset, lowoffset, numbytes, base_addr); } + +static inline void *create_file(const char *name, unsigned long access, unsigned long creation_flags, unsigned long attributes = 0) +{ return CreateFileA(name, access, file_share_read | file_share_write, 0, creation_flags, attributes, 0); } + +static inline bool delete_file(const char *name) +{ return 0 != DeleteFileA(name); } + +static inline void get_system_info(system_info *info) +{ GetSystemInfo(info); } + +static inline int flush_view_of_file(void *base_addr, std::size_t numbytes) +{ return FlushViewOfFile(base_addr, numbytes); } + +static inline bool get_file_size(void *handle, __int64 &size) +{ + return 0 != GetFileSizeEx(handle, &size); +} + +static inline bool create_directory(const char *name, interprocess_security_attributes* security) +{ + return 0 != CreateDirectoryA(name, security); +} + +static inline unsigned long get_temp_path(unsigned long length, char *buffer) +{ + return GetTempPathA(length, buffer); +} + +static inline int set_end_of_file(void *handle) +{ + return 0 != SetEndOfFile(handle); +} + +static inline bool set_file_pointer_ex(void *handle, __int64 distance, __int64 *new_file_pointer, unsigned long move_method) +{ + return 0 != SetFilePointerEx(handle, distance, new_file_pointer, move_method); +} + +static inline bool lock_file_ex(void *hnd, unsigned long flags, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped *overlapped) +{ + return 0 != LockFileEx(hnd, flags, reserved, size_low, size_high, overlapped); +} + +static inline bool unlock_file_ex(void *hnd, unsigned long reserved, unsigned long size_low, unsigned long size_high, interprocess_overlapped *overlapped) +{ + return 0 != UnlockFileEx(hnd, reserved, size_low, size_high, overlapped); +} + +static inline long interlocked_increment(long volatile *addr) +{ return InterlockedIncrement(addr); } + +static inline long interlocked_decrement(long volatile *addr) +{ return InterlockedDecrement(addr); } + +static inline long interlocked_compare_exchange(long volatile *addr, long val1, long val2) +{ return InterlockedCompareExchange(addr, val1, val2); } + +static inline long exchange_and_add(long volatile* addend, long value) +{ return InterlockedExchangeAdd((long*)addend, value); } + +} //namespace winapi +} //namespace interprocess +} //namespace boost + +#include + +#endif //#ifdef BOOST_INTERPROCESS_WIN32_SYNC_PRIMITIVES_HPP