|
Boost-Commit : |
From: igaztanaga_at_[hidden]
Date: 2008-05-23 19:17:57
Author: igaztanaga
Date: 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
New Revision: 45704
URL: http://svn.boost.org/trac/boost/changeset/45704
Log:
#1912: some copy edits on boost.intrusive
#1932: move semantics for shared objects
#1635: Incomplete include guard in boost/intrusive
Added:
trunk/boost/interprocess/detail/managed_multi_shared_memory.hpp (contents, props changed)
trunk/boost/interprocess/detail/managed_open_or_create_impl.hpp (contents, props changed)
trunk/boost/interprocess/detail/math_functions.hpp (contents, props changed)
trunk/boost/interprocess/detail/multi_segment_services.hpp (contents, props changed)
trunk/boost/interprocess/detail/segment_manager_helper.hpp (contents, props changed)
trunk/boost/interprocess/detail/utilities.hpp (contents, props changed)
Added: trunk/boost/interprocess/detail/managed_multi_shared_memory.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/interprocess/detail/managed_multi_shared_memory.hpp 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
@@ -0,0 +1,389 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+#define BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/detail/multi_segment_services.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/containers/list.hpp>//list
+#include <boost/interprocess/mapped_region.hpp> //mapped_region
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp> //managed_open_or_create_impl
+#include <new>
+#include <boost/interprocess/containers/string.hpp>
+#include <boost/interprocess/streams/vectorstream.hpp>
+#include <memory>
+
+//!\file
+//!Describes a named shared memory object allocation user class.
+
+namespace boost {
+
+namespace interprocess {
+
+//!A basic shared memory named object creation class. Initializes the
+//!shared memory segment. Inherits all basic functionality from
+//!basic_managed_memory_impl<CharType, MemoryAlgorithm, IndexType>
+template
+ <
+ class CharType,
+ class MemoryAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_multi_shared_memory
+ : public detail::basic_managed_memory_impl
+ <CharType, MemoryAlgorithm, IndexType>
+{
+
+ typedef basic_managed_multi_shared_memory
+ <CharType, MemoryAlgorithm, IndexType> self_t;
+ typedef typename MemoryAlgorithm::void_pointer void_pointer;
+ typedef typename detail::
+ managed_open_or_create_impl<shared_memory_object> managed_impl;
+ typedef typename void_pointer::segment_group_id segment_group_id;
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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 multi_segment_services
+ {
+ public:
+ typedef std::pair<void *, std::size_t> result_type;
+ typedef basic_managed_multi_shared_memory frontend_t;
+ typedef typename
+ basic_managed_multi_shared_memory::void_pointer void_pointer;
+ typedef typename void_pointer::segment_group_id segment_group_id;
+ group_services(frontend_t *const frontend)
+ : mp_frontend(frontend), m_group(0), m_min_segment_size(0){}
+
+ virtual std::pair<void *, std::size_t> create_new_segment(std::size_t alloc_size)
+ {
+ //We should allocate an extra byte so that the
+ //[base_addr + alloc_size] byte belongs to this segment
+ alloc_size += 1;
+
+ //If requested size is less than minimum, update that
+ alloc_size = (m_min_segment_size > alloc_size) ?
+ m_min_segment_size : alloc_size;
+ if(mp_frontend->priv_new_segment(create_open_func::DoCreate,
+ alloc_size, 0)){
+ shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin();
+ return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1);
+ }
+ return result_type(0, 0);
+ }
+
+ virtual bool update_segments ()
+ { return true; }
+
+ virtual ~group_services(){}
+
+ void set_group(segment_group_id group)
+ { m_group = group; }
+
+ segment_group_id 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;
+ segment_group_id 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()(void *addr, std::size_t size, bool created) const
+ {
+ if(((m_type == DoOpen) && created) ||
+ ((m_type == DoCreate) && !created))
+ return false;
+ segment_group_id 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
+ void_pointer::insert_mapping
+ ( group
+ , (char*)addr - managed_impl::ManagedOpenOrCreateUserOffset
+ , size + managed_impl::ManagedOpenOrCreateUserOffset);
+ //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_last_mapping(group);
+ assert(ret);(void)ret;
+ }
+ return false;
+ }
+ self_t * const mp_frontend;
+ type_t m_type;
+ std::size_t m_segment_number;
+ };
+
+ //!Functor to execute atomically when closing a shared memory segment.
+ struct close_func
+ {
+ typedef typename
+ basic_managed_multi_shared_memory::void_pointer void_pointer;
+
+ close_func(self_t * const frontend)
+ : mp_frontend(frontend){}
+
+ void operator()(const mapped_region ®ion, bool last) const
+ {
+ if(last) mp_frontend->destroy_impl();
+ else mp_frontend->close_impl();
+ }
+ self_t * const mp_frontend;
+ };
+
+ typedef detail::basic_managed_memory_impl
+ <CharType, MemoryAlgorithm, IndexType> base_t;
+
+ //Friend declarations
+ friend struct basic_managed_multi_shared_memory::create_open_func;
+ friend struct basic_managed_multi_shared_memory::close_func;
+ friend class basic_managed_multi_shared_memory::group_services;
+
+ typedef list<managed_impl> shmem_list_t;
+
+ basic_managed_multi_shared_memory *get_this_pointer()
+ { return this; }
+
+ public:
+
+ basic_managed_multi_shared_memory(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(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(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;
+ typename void_pointer::segment_group_id group = 0;
+ BOOST_TRY{
+ m_root_name = name;
+ //Insert multi segment services and get a group identifier
+ group = void_pointer::new_segment_group(&m_group_services);
+ size = void_pointer::round_size(size);
+ m_group_services.set_group(group);
+ m_group_services.set_min_segment_size(size);
+
+ if(group){
+ if(this->priv_new_segment(type, size, 0)){
+ return true;
+ }
+ }
+ }
+ BOOST_CATCH(const std::bad_alloc&){
+ }
+ BOOST_CATCH_END
+ if(group){
+ void_pointer::delete_group(group);
+ }
+ return false;
+ }
+
+ bool priv_new_segment(typename create_open_func::type_t type,
+ std::size_t size,
+ const void *addr)
+ {
+ BOOST_TRY{
+ //Get the number of groups of this multi_segment group
+ std::size_t segment_id = m_shmem_list.size();
+ //Format the name of the shared memory: append segment number.
+ boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
+ //Pre-reserve string size
+ std::size_t str_size = m_root_name.length()+10;
+ if(formatter.vector().size() < str_size){
+ //This can throw.
+ formatter.reserve(str_size);
+ }
+ //Format segment's name
+ formatter << m_root_name
+ << static_cast<unsigned int>(segment_id) << std::ends;
+ //This functor will be executed when constructing
+ create_open_func func(this, type, segment_id);
+ const char *name = formatter.vector().c_str();
+ //This can throw.
+ managed_impl mshm;
+
+ switch(type){
+ case create_open_func::DoCreate:
+ {
+ managed_impl shm(create_only, name, size, read_write, addr, func);
+ mshm = move(shm);
+ }
+ break;
+
+ case create_open_func::DoOpen:
+ {
+ managed_impl shm(open_only, name,read_write, addr, func);
+ mshm = move(shm);
+ }
+ break;
+
+ case create_open_func::DoOpenOrCreate:
+ {
+ managed_impl shm(open_or_create, name, size, read_write, addr, func);
+ mshm = move(shm);
+ }
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ //This can throw.
+ m_shmem_list.push_back(move(mshm));
+ 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
+ segment_group_id 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);
+ m_shmem_list.clear();
+ }
+ }
+
+ private:
+ shmem_list_t m_shmem_list;
+ group_services m_group_services;
+ std::string m_root_name;
+};
+
+typedef basic_managed_multi_shared_memory
+ < char
+ , rbtree_best_fit<mutex_family, intersegment_ptr<void> >
+ , iset_index>
+ managed_multi_shared_memory;
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+
Added: trunk/boost/interprocess/detail/managed_open_or_create_impl.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/interprocess/detail/managed_open_or_create_impl.hpp 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
@@ -0,0 +1,453 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// 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_OPEN_OR_CREATE_IMPL
+#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
+
+#include <boost/interprocess/detail/os_thread_functions.hpp>
+#include <boost/interprocess/detail/os_file_functions.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/interprocess/detail/interprocess_tester.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/move.hpp>
+#include <boost/cstdint.hpp>
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail{ class interprocess_tester; }
+/// @endcond
+
+namespace detail {
+
+template<class DeviceAbstraction, bool FileBased = true>
+class managed_open_or_create_impl
+{
+ //Non-copyable
+ managed_open_or_create_impl(const managed_open_or_create_impl &);
+ managed_open_or_create_impl &operator=(const managed_open_or_create_impl &);
+
+ enum
+ {
+ UninitializedSegment,
+ InitializingSegment,
+ InitializedSegment,
+ CorruptedSegment
+ };
+
+ public:
+
+ static const std::size_t
+ ManagedOpenOrCreateUserOffset =
+ detail::ct_rounded_size
+ < sizeof(boost::uint32_t)
+ , detail::alignment_of<detail::max_align>::value>::value;
+
+ managed_open_or_create_impl()
+ {}
+
+ managed_open_or_create_impl(create_only_t,
+ const char *name,
+ std::size_t size,
+ mode_t mode = read_write,
+ const void *addr = 0)
+ {
+ m_name = name;
+ priv_open_or_create
+ ( detail::DoCreate
+ , size
+ , mode
+ , addr
+ , null_mapped_region_function());
+ }
+
+ managed_open_or_create_impl(open_only_t,
+ const char *name,
+ mode_t mode = read_write,
+ const void *addr = 0)
+ {
+ m_name = name;
+ priv_open_or_create
+ ( detail::DoOpen
+ , 0
+ , mode
+ , addr
+ , null_mapped_region_function());
+ }
+
+
+ managed_open_or_create_impl(open_or_create_t,
+ const char *name,
+ std::size_t size,
+ mode_t mode = read_write,
+ const void *addr = 0)
+ {
+ m_name = name;
+ priv_open_or_create
+ ( detail::DoOpenOrCreate
+ , size
+ , mode
+ , addr
+ , null_mapped_region_function());
+ }
+
+ template <class ConstructFunc>
+ managed_open_or_create_impl(create_only_t,
+ const char *name,
+ std::size_t size,
+ mode_t mode,
+ const void *addr,
+ const ConstructFunc &construct_func)
+ {
+ m_name = name;
+ priv_open_or_create
+ (detail::DoCreate
+ , size
+ , mode
+ , addr
+ , construct_func);
+ }
+
+ template <class ConstructFunc>
+ managed_open_or_create_impl(open_only_t,
+ const char *name,
+ mode_t mode,
+ const void *addr,
+ const ConstructFunc &construct_func)
+ {
+ m_name = name;
+ priv_open_or_create
+ ( detail::DoOpen
+ , 0
+ , mode
+ , addr
+ , construct_func);
+ }
+
+ template <class ConstructFunc>
+ managed_open_or_create_impl(open_or_create_t,
+ const char *name,
+ std::size_t size,
+ mode_t mode,
+ const void *addr,
+ const ConstructFunc &construct_func)
+ {
+ m_name = name;
+ priv_open_or_create
+ ( detail::DoOpenOrCreate
+ , size
+ , mode
+ , addr
+ , construct_func);
+ }
+
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ managed_open_or_create_impl(detail::moved_object<managed_open_or_create_impl> moved)
+ { this->swap(moved.get()); }
+ #else
+ managed_open_or_create_impl(managed_open_or_create_impl &&moved)
+ { this->swap(moved); }
+ #endif
+
+ //!Move assignment. If *this owns a memory mapped region, it will be
+ //!destroyed and it will take ownership of "other"'s memory mapped region.
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ managed_open_or_create_impl &operator=(detail::moved_object<managed_open_or_create_impl> moved)
+ {
+ managed_open_or_create_impl tmp(moved);
+ this->swap(tmp);
+ return *this;
+ }
+
+ #else
+ managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved)
+ {
+ managed_open_or_create_impl tmp(move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+ #endif
+
+ ~managed_open_or_create_impl()
+ {}
+
+ std::size_t get_user_size() const
+ { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
+
+ void *get_user_address() const
+ { return (char*)m_mapped_region.get_address() + ManagedOpenOrCreateUserOffset; }
+
+ std::size_t get_real_size() const
+ { return m_mapped_region.get_size(); }
+
+ void *get_real_address() const
+ { return (char*)m_mapped_region.get_address(); }
+
+ void swap(managed_open_or_create_impl &other)
+ {
+ this->m_name.swap(other.m_name);
+ this->m_mapped_region.swap(other.m_mapped_region);
+ }
+
+ const char *get_name() const
+ { return m_name.c_str(); }
+
+ bool flush()
+ { return m_mapped_region.flush(); }
+
+ private:
+
+ //These are templatized to allow explicit instantiations
+ template<bool dummy>
+ static void write_whole_device(DeviceAbstraction &, std::size_t, detail::false_)
+ {} //Empty
+
+ template<bool dummy>
+ static void write_whole_device(DeviceAbstraction &dev, std::size_t size, detail::true_)
+ {
+ file_handle_t hnd = detail::file_handle_from_mapping_handle(dev.get_mapping_handle());
+
+ if(size <= ManagedOpenOrCreateUserOffset){
+ throw interprocess_exception(error_info(system_error_code()));
+ }
+
+ size -= ManagedOpenOrCreateUserOffset;
+
+ if(!detail::set_file_pointer(hnd, ManagedOpenOrCreateUserOffset, file_begin)){
+ throw interprocess_exception(error_info(system_error_code()));
+ }
+
+ //We will write zeros in the file
+ for(std::size_t remaining = size, write_size = 0
+ ;remaining > 0
+ ;remaining -= write_size){
+ const std::size_t DataSize = 512;
+ static char data [DataSize];
+ write_size = DataSize < remaining ? DataSize : remaining;
+ if(!detail::write_file(hnd, data, write_size)){
+ error_info err = system_error_code();
+ throw interprocess_exception(err);
+ }
+ }
+ }
+
+ //These are templatized to allow explicit instantiations
+ template<bool dummy>
+ static void truncate_device(DeviceAbstraction &, std::size_t, detail::false_)
+ {} //Empty
+
+ template<bool dummy>
+ static void truncate_device(DeviceAbstraction &dev, std::size_t size, detail::true_)
+ { dev.truncate(size); }
+
+ //These are templatized to allow explicit instantiations
+ template<bool dummy>
+ static void create_device(DeviceAbstraction &dev, const char *name, std::size_t size, detail::false_)
+ {
+ DeviceAbstraction tmp(create_only, name, read_write, size);
+ tmp.swap(dev);
+ }
+
+ template<bool dummy>
+ static void create_device(DeviceAbstraction &dev, const char *name, std::size_t, detail::true_)
+ {
+ DeviceAbstraction tmp(create_only, name, read_write);
+ tmp.swap(dev);
+ }
+
+ template <class ConstructFunc> inline
+ void priv_open_or_create
+ (detail::create_enum_t type, std::size_t size,
+ mode_t mode, const void *addr,
+ ConstructFunc construct_func)
+ {
+ typedef detail::bool_<FileBased> file_like_t;
+ (void)mode;
+ error_info err;
+ bool created = false;
+ bool ronly = false;
+ bool cow = false;
+ DeviceAbstraction dev;
+
+ if(type != detail::DoOpen && size < ManagedOpenOrCreateUserOffset){
+ throw interprocess_exception(error_info(size_error));
+ }
+
+ if(type == detail::DoOpen && mode == read_write){
+ DeviceAbstraction tmp(open_only, m_name.c_str(), read_write);
+ tmp.swap(dev);
+ created = false;
+ }
+ else if(type == detail::DoOpen && mode == read_only){
+ DeviceAbstraction tmp(open_only, m_name.c_str(), read_only);
+ tmp.swap(dev);
+ created = false;
+ ronly = true;
+ }
+ else if(type == detail::DoOpen && mode == copy_on_write){
+ DeviceAbstraction tmp(open_only, m_name.c_str(), read_only);
+ tmp.swap(dev);
+ created = false;
+ cow = true;
+ }
+ else if(type == detail::DoCreate){
+ create_device<FileBased>(dev, m_name.c_str(), size, file_like_t());
+ created = true;
+ }
+ else if(type == detail::DoOpenOrCreate){
+ //This loop is very ugly, but brute force is sometimes better
+ //than diplomacy. If someone knows how to open or create a
+ //file and know if we have really created it or just open it
+ //drop me a e-mail!
+ bool completed = false;
+ while(!completed){
+ try{
+ create_device<FileBased>(dev, m_name.c_str(), size, file_like_t());
+ created = true;
+ completed = true;
+ }
+ catch(interprocess_exception &ex){
+ if(ex.get_error_code() != already_exists_error){
+ throw;
+ }
+ else{
+ try{
+ DeviceAbstraction tmp(open_only, m_name.c_str(), read_write);
+ dev.swap(tmp);
+ created = false;
+ completed = true;
+ }
+ catch(interprocess_exception &ex){
+ if(ex.get_error_code() != not_found_error){
+ throw;
+ }
+ }
+ }
+ }
+ detail::thread_yield();
+ }
+ }
+
+ if(created){
+ try{
+ //If this throws, we are lost
+ truncate_device<FileBased>(dev, size, file_like_t());
+
+ //If the following throws, we will truncate the file to 1
+ mapped_region region(dev, read_write, 0, 0, addr);
+ boost::uint32_t *patomic_word = 0; //avoid gcc warning
+ patomic_word = static_cast<boost::uint32_t*>(region.get_address());
+ boost::uint32_t previous = detail::atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment);
+
+ if(previous == UninitializedSegment){
+ try{
+ write_whole_device<FileBased>(dev, size, file_like_t());
+ construct_func((char*)region.get_address() + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true);
+ //All ok, just move resources to the external mapped region
+ m_mapped_region.swap(region);
+ }
+ catch(...){
+ detail::atomic_write32(patomic_word, CorruptedSegment);
+ throw;
+ }
+ detail::atomic_write32(patomic_word, InitializedSegment);
+ }
+ else if(previous == InitializingSegment || previous == InitializedSegment){
+ throw interprocess_exception(error_info(already_exists_error));
+ }
+ else{
+ throw interprocess_exception(error_info(corrupted_error));
+ }
+ }
+ catch(...){
+ try{
+ truncate_device<FileBased>(dev, 1u, file_like_t());
+ }
+ catch(...){
+ }
+ throw;
+ }
+ }
+ else{
+ if(FileBased){
+ offset_t filesize = 0;
+ while(filesize == 0){
+ if(!detail::get_file_size(detail::file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){
+ throw interprocess_exception(error_info(system_error_code()));
+ }
+ detail::thread_yield();
+ }
+ if(filesize == 1){
+ throw interprocess_exception(error_info(corrupted_error));
+ }
+ }
+
+ mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr);
+
+ boost::uint32_t *patomic_word = static_cast<boost::uint32_t*>(region.get_address());
+ boost::uint32_t value = detail::atomic_read32(patomic_word);
+
+ while(value == InitializingSegment || value == UninitializedSegment){
+ detail::thread_yield();
+ value = detail::atomic_read32(patomic_word);
+ }
+
+ if(value != InitializedSegment)
+ throw interprocess_exception(error_info(corrupted_error));
+
+ construct_func( (char*)region.get_address() + ManagedOpenOrCreateUserOffset
+ , region.get_size() - ManagedOpenOrCreateUserOffset
+ , false);
+ //All ok, just move resources to the external mapped region
+ m_mapped_region.swap(region);
+ }
+ }
+
+ private:
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction()
+ { detail::interprocess_tester::dont_close_on_destruction(m_mapped_region); }
+
+ mapped_region m_mapped_region;
+ std::string m_name;
+};
+
+template<class DeviceAbstraction>
+inline void swap(managed_open_or_create_impl<DeviceAbstraction> &x
+ ,managed_open_or_create_impl<DeviceAbstraction> &y)
+{ x.swap(y); }
+
+} //namespace detail {
+
+
+///@cond
+
+//!Trait class to detect if a type is
+//!movable
+template<class DeviceAbstraction>
+
+struct is_movable<detail::managed_open_or_create_impl<DeviceAbstraction> >
+{
+ enum { value = true };
+};
+
+///@endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL
Added: trunk/boost/interprocess/detail/math_functions.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/interprocess/detail/math_functions.hpp 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
@@ -0,0 +1,107 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Stephen Cleary 2000.
+// (C) Copyright Ion Gaztanaga 2007-2008.
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file 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 is a slightly modified file from Boost.Pool
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
+#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+// Greatest common divisor and least common multiple
+
+//
+// gcd is an algorithm that calculates the greatest common divisor of two
+// integers, using Euclid's algorithm.
+//
+// Pre: A > 0 && B > 0
+// Recommended: A > B
+template <typename Integer>
+inline Integer gcd(Integer A, Integer B)
+{
+ do
+ {
+ const Integer tmp(B);
+ B = A % B;
+ A = tmp;
+ } while (B != 0);
+
+ return A;
+}
+
+//
+// lcm is an algorithm that calculates the least common multiple of two
+// integers.
+//
+// Pre: A > 0 && B > 0
+// Recommended: A > B
+template <typename Integer>
+inline Integer lcm(const Integer & A, const Integer & B)
+{
+ Integer ret = A;
+ ret /= gcd(A, B);
+ ret *= B;
+ return ret;
+}
+
+template <typename Integer>
+inline Integer log2_ceil(const Integer & A)
+{
+ Integer i = 0;
+ Integer power_of_2 = 1;
+
+ while(power_of_2 < A){
+ power_of_2 <<= 1;
+ ++i;
+ }
+ return i;
+}
+
+template <typename Integer>
+inline Integer upper_power_of_2(const Integer & A)
+{
+ Integer power_of_2 = 1;
+
+ while(power_of_2 < A){
+ power_of_2 <<= 1;
+ }
+ return power_of_2;
+}
+
+//This function uses binary search to discover the
+//highest set bit of the integer
+inline std::size_t floor_log2 (std::size_t x)
+{
+ const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT;
+ const bool Size_t_Bits_Power_2= !(Bits & (Bits-1));
+ BOOST_STATIC_ASSERT(Size_t_Bits_Power_2);
+
+ std::size_t n = x;
+ std::size_t log2 = 0;
+
+ for(std::size_t shift = Bits >> 1; shift; shift >>= 1){
+ std::size_t tmp = n >> shift;
+ if (tmp)
+ log2 += shift, n = tmp;
+ }
+
+ return log2;
+}
+
+} // namespace detail
+} // namespace interprocess
+} // namespace boost
+
+#endif
Added: trunk/boost/interprocess/detail/multi_segment_services.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/interprocess/detail/multi_segment_services.hpp 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
@@ -0,0 +1,46 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
+#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+
+/*!\file
+ Describes a named shared memory allocation user class.
+*/
+
+namespace boost {
+
+namespace interprocess {
+
+class multi_segment_services
+{
+ public:
+ virtual std::pair<void *, std::size_t> create_new_segment(std::size_t mem) = 0;
+ virtual bool update_segments () = 0;
+ virtual ~multi_segment_services() = 0;
+};
+
+inline multi_segment_services::~multi_segment_services()
+{}
+
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
Added: trunk/boost/interprocess/detail/segment_manager_helper.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/interprocess/detail/segment_manager_helper.hpp 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
@@ -0,0 +1,477 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// 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_SEGMENT_MANAGER_BASE_HPP
+#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/in_place_interface.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <cstddef> //std::size_t
+#include <string> //char_traits
+#include <new> //std::nothrow
+#include <utility> //std::pair
+#ifndef BOOST_NO_EXCEPTIONS
+#include <exception>
+#endif
+
+//!\file
+//!Describes the object placed in a memory segment that provides
+//!named object allocation capabilities.
+
+namespace boost{
+namespace interprocess{
+
+template<class MemoryManager>
+class segment_manager_base;
+
+//!An integer that describes the type of the
+//!instance constructed in memory
+enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type };
+
+namespace detail{
+
+template<class MemoryAlgorithm>
+class mem_algo_deallocator
+{
+ void * m_ptr;
+ MemoryAlgorithm & m_algo;
+
+ public:
+ mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo)
+ : m_ptr(ptr), m_algo(algo)
+ {}
+
+ void release()
+ { m_ptr = 0; }
+
+ ~mem_algo_deallocator()
+ { if(m_ptr) m_algo.deallocate(m_ptr); }
+};
+
+/// @cond
+struct block_header
+{
+ std::size_t m_value_bytes;
+ unsigned short m_num_char;
+ unsigned char m_value_alignment;
+ unsigned char m_alloc_type_sizeof_char;
+
+ block_header(std::size_t value_bytes
+ ,std::size_t value_alignment
+ ,std::size_t allocation_type
+ ,std::size_t sizeof_char
+ ,std::size_t num_char
+ )
+ : m_value_bytes(value_bytes)
+ , m_num_char(num_char)
+ , m_value_alignment(value_alignment)
+ , m_alloc_type_sizeof_char
+ ( ((unsigned char)allocation_type << 5u) |
+ ((unsigned char)sizeof_char & 0x1F) )
+ {};
+
+
+ template<class T>
+ block_header &operator= (const T& )
+ { return *this; }
+
+ std::size_t total_size() const
+ {
+ if(allocation_type() != anonymous_type){
+ return name_offset() + (m_num_char+1)*sizeof_char();
+ }
+ else{
+ return value_offset() + m_value_bytes;
+ }
+ }
+
+ std::size_t value_bytes() const
+ { return m_value_bytes; }
+
+ template<class Header>
+ std::size_t total_size_with_header() const
+ {
+ return get_rounded_size
+ ( sizeof(Header)
+ , detail::alignment_of<block_header>::value)
+ + total_size();
+ }
+
+ std::size_t allocation_type() const
+ { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }
+
+ std::size_t sizeof_char() const
+ { return m_alloc_type_sizeof_char & (unsigned char)0x1F; }
+
+ template<class CharType>
+ CharType *name() const
+ {
+ return reinterpret_cast<CharType*>
+ (detail::char_ptr_cast(this) + name_offset());
+ }
+
+ std::size_t name_length() const
+ { return m_num_char; }
+
+ std::size_t name_offset() const
+ {
+ return value_offset() + get_rounded_size(m_value_bytes, sizeof_char());
+ }
+
+ void *value() const
+ {
+ return detail::char_ptr_cast(this) + value_offset();
+ }
+
+ std::size_t value_offset() const
+ {
+ return get_rounded_size(sizeof(block_header), m_value_alignment);
+ }
+
+ template<class CharType>
+ bool less_comp(const block_header &b) const
+ {
+ return m_num_char < b.m_num_char ||
+ (m_num_char < b.m_num_char &&
+ std::char_traits<CharType>::compare
+ (name<CharType>(), b.name<CharType>(), m_num_char) < 0);
+ }
+
+ template<class CharType>
+ bool equal_comp(const block_header &b) const
+ {
+ return m_num_char == b.m_num_char &&
+ std::char_traits<CharType>::compare
+ (name<CharType>(), b.name<CharType>(), m_num_char) == 0;
+ }
+
+ template<class T>
+ static block_header *block_header_from_value(T *value)
+ { return block_header_from_value(value, sizeof(T), detail::alignment_of<T>::value); }
+
+ static block_header *block_header_from_value(const void *value, std::size_t sz, std::size_t algn)
+ {
+ block_header * hdr =
+ reinterpret_cast<block_header*>(detail::char_ptr_cast(value) -
+ get_rounded_size(sizeof(block_header), algn));
+ (void)sz;
+ //Some sanity checks
+ assert(hdr->m_value_alignment == algn);
+ assert(hdr->m_value_bytes % sz == 0);
+ return hdr;
+ }
+
+ template<class Header>
+ static block_header *from_first_header(Header *header)
+ {
+ block_header * hdr =
+ reinterpret_cast<block_header*>(detail::char_ptr_cast(header) +
+ get_rounded_size(sizeof(Header), detail::alignment_of<block_header>::value));
+ //Some sanity checks
+ return hdr;
+ }
+
+ template<class Header>
+ static Header *to_first_header(block_header *bheader)
+ {
+ Header * hdr =
+ reinterpret_cast<Header*>(detail::char_ptr_cast(bheader) -
+ get_rounded_size(sizeof(Header), detail::alignment_of<block_header>::value));
+ //Some sanity checks
+ return hdr;
+ }
+};
+
+inline void array_construct(void *mem, std::size_t num, detail::in_place_interface &table)
+{
+ //Try constructors
+ std::size_t constructed = 0;
+ BOOST_TRY{
+ table.construct_n(mem, num, constructed);
+ }
+ //If there is an exception call destructors and erase index node
+ BOOST_CATCH(...){
+ std::size_t destroyed = 0;
+ table.destroy_n(mem, constructed, destroyed);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+}
+
+template<class CharT>
+struct intrusive_compare_key
+{
+ typedef CharT char_type;
+
+ intrusive_compare_key(const CharT *str, std::size_t len)
+ : mp_str(str), m_len(len)
+ {}
+
+ const CharT * mp_str;
+ std::size_t m_len;
+};
+
+//!This struct indicates an anonymous object creation
+//!allocation
+template<instance_type type>
+class instance_t
+{
+ instance_t(){}
+};
+
+template<class T>
+struct char_if_void
+{
+ typedef T type;
+};
+
+template<>
+struct char_if_void<void>
+{
+ typedef char type;
+};
+
+typedef instance_t<anonymous_type> anonymous_instance_t;
+typedef instance_t<unique_type> unique_instance_t;
+
+template<class Hook, class CharType>
+struct intrusive_value_type_impl
+ : public Hook
+{
+ private:
+ //Non-copyable
+ intrusive_value_type_impl(const intrusive_value_type_impl &);
+ intrusive_value_type_impl& operator=(const intrusive_value_type_impl &);
+
+ public:
+ typedef CharType char_type;
+
+ intrusive_value_type_impl(){}
+
+ enum { BlockHdrAlignment = detail::alignment_of<block_header>::value };
+
+ block_header *get_block_header() const
+ {
+ return (block_header *)(detail::char_ptr_cast(this) +
+ get_rounded_size(sizeof(*this), BlockHdrAlignment));
+ }
+
+ bool operator <(const intrusive_value_type_impl<Hook, CharType> & other) const
+ { return (this->get_block_header())->template less_comp<CharType>(*other.get_block_header()); }
+
+ bool operator ==(const intrusive_value_type_impl<Hook, CharType> & other) const
+ { return (this->get_block_header())->template equal_comp<CharType>(*other.get_block_header()); }
+
+ static intrusive_value_type_impl *get_intrusive_value_type(block_header *hdr)
+ {
+ return (intrusive_value_type_impl *)(detail::char_ptr_cast(hdr) -
+ get_rounded_size(sizeof(intrusive_value_type_impl), BlockHdrAlignment));
+ }
+
+ CharType *name() const
+ { return get_block_header()->template name<CharType>(); }
+
+ std::size_t name_length() const
+ { return get_block_header()->name_length(); }
+
+ void *value() const
+ { return get_block_header()->value(); }
+};
+
+template<class CharType>
+class char_ptr_holder
+{
+ public:
+ char_ptr_holder(const CharType *name)
+ : m_name(name)
+ {}
+
+ char_ptr_holder(const detail::anonymous_instance_t *)
+ : m_name((CharType*)0)
+ {}
+
+ char_ptr_holder(const detail::unique_instance_t *)
+ : m_name((CharType*)-1)
+ {}
+
+ operator const CharType *()
+ { return m_name; }
+
+ private:
+ const CharType *m_name;
+};
+
+//!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<class CharT, class VoidPointer>
+struct index_key
+{
+ typedef typename detail::
+ pointer_to_other<VoidPointer, const CharT>::type const_char_ptr_t;
+ typedef CharT char_type;
+
+ private:
+ //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;
+ public:
+
+ //!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
+ {
+ return (m_len < right.m_len) ||
+ (m_len == right.m_len &&
+ std::char_traits<char_type>::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<char_type>::compare
+ (detail::get_pointer(mp_str),
+ detail::get_pointer(right.mp_str), m_len) == 0;
+ }
+
+ void name(const CharT *name)
+ { mp_str = name; }
+
+ void name_length(std::size_t len)
+ { m_len = len; }
+
+ const CharT *name() const
+ { return detail::get_pointer(mp_str); }
+
+ std::size_t name_length() const
+ { return m_len; }
+};
+
+//!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<class VoidPointer>
+struct index_data
+{
+ typedef VoidPointer void_pointer;
+ void_pointer m_ptr;
+ index_data(void *ptr) : m_ptr(ptr){}
+
+ void *value() const
+ { return (void*)detail::get_pointer(m_ptr); }
+};
+
+template<class MemoryAlgorithm>
+struct segment_manager_base_type
+{ typedef segment_manager_base<MemoryAlgorithm> type; };
+
+template<class CharT, class MemoryAlgorithm>
+struct index_config
+{
+ typedef typename MemoryAlgorithm::void_pointer void_pointer;
+ typedef CharT char_type;
+ typedef detail::index_key<CharT, void_pointer> key_type;
+ typedef detail::index_data<void_pointer> mapped_type;
+ typedef typename segment_manager_base_type
+ <MemoryAlgorithm>::type segment_manager_base;
+
+ template<class HeaderBase>
+ struct intrusive_value_type
+ { typedef detail::intrusive_value_type_impl<HeaderBase, CharT> type; };
+
+ typedef intrusive_compare_key<CharT> intrusive_compare_key_type;
+};
+
+template<class Iterator, bool intrusive>
+class segment_manager_iterator_value_adaptor
+{
+ typedef typename Iterator::value_type iterator_val_t;
+ typedef typename iterator_val_t::char_type char_type;
+
+ public:
+ segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
+ : m_val(&val)
+ {}
+
+ const char_type *name() const
+ { return m_val->name(); }
+
+ std::size_t name_length() const
+ { return m_val->name_length(); }
+
+ const void *value() const
+ { return m_val->value(); }
+
+ const typename Iterator::value_type *m_val;
+};
+
+
+template<class Iterator>
+class segment_manager_iterator_value_adaptor<Iterator, false>
+{
+ typedef typename Iterator::value_type iterator_val_t;
+ typedef typename iterator_val_t::first_type first_type;
+ typedef typename iterator_val_t::second_type second_type;
+ typedef typename first_type::char_type char_type;
+
+ public:
+ segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
+ : m_val(&val)
+ {}
+
+ const char_type *name() const
+ { return m_val->first.name(); }
+
+ std::size_t name_length() const
+ { return m_val->first.name_length(); }
+
+ const void *value() const
+ {
+ return reinterpret_cast<block_header*>
+ (detail::get_pointer(m_val->second.m_ptr))->value();
+ }
+
+ const typename Iterator::value_type *m_val;
+};
+
+template<class Iterator, bool intrusive>
+struct segment_manager_iterator_transform
+ : std::unary_function< typename Iterator::value_type
+ , segment_manager_iterator_value_adaptor<Iterator, intrusive> >
+{
+ typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
+
+ result_type operator()(const typename Iterator::value_type &arg) const
+ { return result_type(arg); }
+};
+
+} //namespace detail {
+
+}} //namespace boost { namespace interprocess
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
+
Added: trunk/boost/interprocess/detail/utilities.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/interprocess/detail/utilities.hpp 2008-05-23 19:17:56 EDT (Fri, 23 May 2008)
@@ -0,0 +1,794 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2008.
+// (C) Copyright Gennaro Prota 2003 - 2004.
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
+#define BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/move.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/interprocess/detail/min_max.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/iterators.hpp>
+#include <boost/interprocess/detail/version_type.hpp>
+#include <utility>
+#include <algorithm>
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+template<class SmartPtr>
+struct smart_ptr_type
+{
+ typedef typename SmartPtr::value_type value_type;
+ typedef value_type *pointer;
+ static pointer get (const SmartPtr &smartptr)
+ { return smartptr.get();}
+};
+
+template<class T>
+struct smart_ptr_type<T*>
+{
+ typedef T value_type;
+ typedef value_type *pointer;
+ static pointer get (pointer ptr)
+ { return ptr;}
+};
+
+//!Overload for smart pointers to avoid ADL problems with get_pointer
+template<class Ptr>
+inline typename smart_ptr_type<Ptr>::pointer
+get_pointer(const Ptr &ptr)
+{ return smart_ptr_type<Ptr>::get(ptr); }
+
+//!To avoid ADL problems with swap
+template <class T>
+inline void do_swap(T& x, T& y)
+{
+ using std::swap;
+ swap(x, y);
+}
+
+//!A deleter for scoped_ptr that deallocates the memory
+//!allocated for an object using a STL allocator.
+template <class Allocator>
+struct scoped_ptr_dealloc_functor
+{
+ typedef typename Allocator::pointer pointer;
+ typedef detail::integral_constant<unsigned,
+ boost::interprocess::detail::
+ version<Allocator>::value> alloc_version;
+ typedef detail::integral_constant<unsigned, 1> allocator_v1;
+ typedef detail::integral_constant<unsigned, 2> allocator_v2;
+
+ private:
+ void priv_deallocate(const typename Allocator::pointer &p, allocator_v1)
+ { m_alloc.deallocate(p, 1); }
+
+ void priv_deallocate(const typename Allocator::pointer &p, allocator_v2)
+ { m_alloc.deallocate_one(p); }
+
+ public:
+ Allocator& m_alloc;
+
+ scoped_ptr_dealloc_functor(Allocator& a)
+ : m_alloc(a) {}
+
+ void operator()(pointer ptr)
+ { if (ptr) priv_deallocate(ptr, alloc_version()); }
+};
+
+//!A deleter for scoped_ptr that deallocates the memory
+//!allocated for an object using a STL allocator.
+template <class Allocator>
+struct scoped_deallocator
+{
+ typedef typename Allocator::pointer pointer;
+ typedef detail::integral_constant<unsigned,
+ boost::interprocess::detail::
+ version<Allocator>::value> alloc_version;
+ typedef detail::integral_constant<unsigned, 1> allocator_v1;
+ typedef detail::integral_constant<unsigned, 2> allocator_v2;
+
+ private:
+ void priv_deallocate(allocator_v1)
+ { m_alloc.deallocate(m_ptr, 1); }
+
+ void priv_deallocate(allocator_v2)
+ { m_alloc.deallocate_one(m_ptr); }
+
+ public:
+ pointer m_ptr;
+ Allocator& m_alloc;
+
+ scoped_deallocator(pointer p, Allocator& a)
+ : m_ptr(p), m_alloc(a) {}
+
+ ~scoped_deallocator()
+ { if (m_ptr)priv_deallocate(alloc_version()); }
+
+ void release()
+ { m_ptr = 0; }
+};
+
+//!A deleter for scoped_ptr that deallocates the memory
+//!allocated for an array of objects using a STL allocator.
+template <class Allocator>
+struct scoped_array_deallocator
+{
+ typedef typename Allocator::pointer pointer;
+ typedef typename Allocator::size_type size_type;
+
+ scoped_array_deallocator(pointer p, Allocator& a, size_type length)
+ : m_ptr(p), m_alloc(a), m_length(length) {}
+
+ ~scoped_array_deallocator()
+ { if (m_ptr) m_alloc.deallocate(m_ptr, m_length); }
+
+ void release()
+ { m_ptr = 0; }
+
+ private:
+ pointer m_ptr;
+ Allocator& m_alloc;
+ size_type m_length;
+};
+
+template <class Allocator>
+struct null_scoped_array_deallocator
+{
+ typedef typename Allocator::pointer pointer;
+ typedef typename Allocator::size_type size_type;
+
+ null_scoped_array_deallocator(pointer, Allocator&, size_type)
+ {}
+
+ void release()
+ {}
+};
+
+//!A deleter for scoped_ptr that destroys
+//!an object using a STL allocator.
+template <class Allocator>
+struct scoped_destructor_n
+{
+ typedef typename Allocator::pointer pointer;
+ typedef typename Allocator::value_type value_type;
+ typedef typename Allocator::size_type size_type;
+
+ pointer m_p;
+ size_type m_n;
+
+ scoped_destructor_n(pointer p, size_type n)
+ : m_p(p), m_n(n)
+ {}
+
+ void release()
+ { m_p = 0; }
+
+ void increment_size(size_type inc)
+ { m_n += inc; }
+
+ ~scoped_destructor_n()
+ {
+ if(!m_p) return;
+ value_type *raw_ptr = detail::get_pointer(m_p);
+ for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr)
+ raw_ptr->~value_type();
+ }
+};
+
+//!A deleter for scoped_ptr that destroys
+//!an object using a STL allocator.
+template <class Allocator>
+struct null_scoped_destructor_n
+{
+ typedef typename Allocator::pointer pointer;
+ typedef typename Allocator::size_type size_type;
+
+ null_scoped_destructor_n(pointer, size_type)
+ {}
+
+ void increment_size(size_type)
+ {}
+
+ void release()
+ {}
+};
+
+template <class A>
+class allocator_destroyer
+{
+ typedef typename A::value_type value_type;
+ typedef detail::integral_constant<unsigned,
+ boost::interprocess::detail::
+ version<A>::value> alloc_version;
+ typedef detail::integral_constant<unsigned, 1> allocator_v1;
+ typedef detail::integral_constant<unsigned, 2> allocator_v2;
+
+ private:
+ A & a_;
+
+ private:
+ void priv_deallocate(const typename A::pointer &p, allocator_v1)
+ { a_.deallocate(p, 1); }
+
+ void priv_deallocate(const typename A::pointer &p, allocator_v2)
+ { a_.deallocate_one(p); }
+
+ public:
+ allocator_destroyer(A &a)
+ : a_(a)
+ {}
+
+ void operator()(const typename A::pointer &p)
+ {
+ detail::get_pointer(p)->~value_type();
+ priv_deallocate(p, alloc_version());
+ }
+};
+
+template <class A>
+class allocator_destroyer_and_chain_builder
+{
+ typedef typename A::value_type value_type;
+ typedef typename A::multiallocation_iterator multiallocation_iterator;
+ typedef typename A::multiallocation_chain multiallocation_chain;
+
+ A & a_;
+ multiallocation_chain &c_;
+
+ public:
+ allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c)
+ : a_(a), c_(c)
+ {}
+
+ void operator()(const typename A::pointer &p)
+ {
+ value_type *vp = detail::get_pointer(p);
+ vp->~value_type();
+ c_.push_back(vp);
+ }
+};
+
+template <class A>
+class allocator_multialloc_chain_node_deallocator
+{
+ typedef typename A::value_type value_type;
+ typedef typename A::multiallocation_iterator multiallocation_iterator;
+ typedef typename A::multiallocation_chain multiallocation_chain;
+ typedef allocator_destroyer_and_chain_builder<A> chain_builder;
+
+ A & a_;
+ multiallocation_chain c_;
+
+ public:
+ allocator_multialloc_chain_node_deallocator(A &a)
+ : a_(a), c_()
+ {}
+
+ chain_builder get_chain_builder()
+ { return chain_builder(a_, c_); }
+
+ ~allocator_multialloc_chain_node_deallocator()
+ {
+ multiallocation_iterator it(c_.get_it());
+ if(it != multiallocation_iterator())
+ a_.deallocate_individual(it);
+ }
+};
+
+template <class A>
+class allocator_multialloc_chain_array_deallocator
+{
+ typedef typename A::value_type value_type;
+ typedef typename A::multiallocation_iterator multiallocation_iterator;
+ typedef typename A::multiallocation_chain multiallocation_chain;
+ typedef allocator_destroyer_and_chain_builder<A> chain_builder;
+
+ A & a_;
+ multiallocation_chain c_;
+
+ public:
+ allocator_multialloc_chain_array_deallocator(A &a)
+ : a_(a), c_()
+ {}
+
+ chain_builder get_chain_builder()
+ { return chain_builder(a_, c_); }
+
+ ~allocator_multialloc_chain_array_deallocator()
+ {
+ multiallocation_iterator it(c_.get_it());
+ if(it != multiallocation_iterator())
+ a_.deallocate_many(it);
+ }
+};
+
+//!A class used for exception-safe multi-allocation + construction.
+template <class Allocator>
+struct multiallocation_destroy_dealloc
+{
+ typedef typename Allocator::multiallocation_iterator multiallocation_iterator;
+ typedef typename Allocator::value_type value_type;
+
+ multiallocation_iterator m_itbeg;
+ Allocator& m_alloc;
+
+ multiallocation_destroy_dealloc(multiallocation_iterator itbeg, Allocator& a)
+ : m_itbeg(itbeg), m_alloc(a) {}
+
+ ~multiallocation_destroy_dealloc()
+ {
+ multiallocation_iterator endit;
+ while(m_itbeg != endit){
+ detail::get_pointer(&*m_itbeg)->~value_type();
+ m_alloc.deallocate(&*m_itbeg, 1);
+ ++m_itbeg;
+ }
+ }
+
+ void next()
+ { ++m_itbeg; }
+
+ void release()
+ { m_itbeg = multiallocation_iterator(); }
+};
+
+//!Forces a cast from any pointer to char *pointer
+template<class T>
+inline char* char_ptr_cast(T *ptr)
+{
+ //This is nasty, but we like it a lot!
+ return (char*)(ptr);
+}
+
+inline char* char_ptr_cast()
+{
+ //This is nasty, but we like it a lot!
+ return (char*)(0);
+}
+
+//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;
+}
+
+//Truncates "orig_size" to a multiple of "multiple" bytes.
+inline std::size_t get_truncated_size(std::size_t orig_size, std::size_t multiple)
+{
+ return orig_size/multiple*multiple;
+}
+
+//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two
+inline std::size_t get_rounded_size_po2(std::size_t orig_size, std::size_t round_to)
+{
+ return ((orig_size-1)&(~(round_to-1))) + round_to;
+}
+
+//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two
+inline std::size_t get_truncated_size_po2(std::size_t orig_size, std::size_t multiple)
+{
+ return (orig_size & (~(multiple-1)));
+}
+
+template <std::size_t OrigSize, std::size_t RoundTo>
+struct ct_rounded_size
+{
+ enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo };
+};
+
+template <std::size_t Value1, std::size_t Value2>
+struct ct_min
+{
+ enum { value = (Value1 < Value2)? Value1 : Value2 };
+};
+
+template <std::size_t Value1, std::size_t Value2>
+struct ct_max
+{
+ enum { value = (Value1 > Value2)? Value1 : Value2 };
+};
+
+// Gennaro Prota wrote this. Thanks!
+template <int p, int n = 4>
+struct ct_max_pow2_less
+{
+ enum { c = 2*n < p };
+
+ static const std::size_t value =
+ c ? (ct_max_pow2_less< c*p, 2*c*n>::value) : n;
+};
+
+template <>
+struct ct_max_pow2_less<0, 0>
+{
+ static const std::size_t value = 0;
+};
+
+//!Obtains a generic pointer of the same type that
+//!can point to other pointed type: Ptr<?> -> Ptr<NewValueType>
+template<class T, class U>
+struct pointer_to_other;
+
+template<class T, class U,
+ template<class> class Sp>
+struct pointer_to_other< Sp<T>, U >
+{
+ typedef Sp<U> type;
+};
+
+template<class T, class T2, class U,
+ template<class, class> class Sp>
+struct pointer_to_other< Sp<T, T2>, U >
+{
+ typedef Sp<U, T2> type;
+};
+
+template<class T, class T2, class T3, class U,
+ template<class, class, class> class Sp>
+struct pointer_to_other< Sp<T, T2, T3>, U >
+{
+ typedef Sp<U, T2, T3> type;
+};
+
+template<class T, class U>
+struct pointer_to_other< T*, U >
+{
+ typedef U* type;
+};
+
+} //namespace detail {
+
+//!Trait class to detect if an index is a node
+//!index. This allows more efficient operations
+//!when deallocating named objects.
+template <class Index>
+struct is_node_index
+{
+ enum { value = false };
+};
+
+
+//!Trait class to detect if an index is an intrusive
+//!index. This will embed the derivation hook in each
+//!allocation header, to provide memory for the intrusive
+//!container.
+template <class Index>
+struct is_intrusive_index
+{
+ enum { value = false };
+};
+
+template <class SizeType>
+SizeType
+ get_next_capacity(const SizeType max_size
+ ,const SizeType capacity
+ ,const SizeType n)
+{
+// if (n > max_size - capacity)
+// throw std::length_error("get_next_capacity");
+
+ const SizeType m3 = max_size/3;
+
+ if (capacity < m3)
+ return capacity + max_value(3*(capacity+1)/5, n);
+
+ if (capacity < m3*2)
+ return capacity + max_value((capacity+1)/2, n);
+
+ return max_size;
+}
+
+namespace detail {
+
+template <class T1, class T2>
+struct pair
+{
+ typedef T1 first_type;
+ typedef T2 second_type;
+
+ T1 first;
+ T2 second;
+
+ pair()
+ : first(), second()
+ {}
+
+ pair(const T1& x, const T2& y)
+ : first(x), second(y)
+ {}
+
+ template <class D, class S>
+ pair(const std::pair<D, S>& p)
+ : first(p.first), second(p.second)
+ {}
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ template <class D, class S>
+ pair(const detail::moved_object<std::pair<D, S> >& p)
+ : first(move(p.get().first)), second(move(p.get().second))
+ {}
+ #else
+ template <class D, class S>
+ pair(std::pair<D, S> && p)
+ : first(move(p.first)), second(move(p.second))
+ {}
+ #endif
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ template <class D, class S>
+ pair(const detail::moved_object<pair<D, S> >& p)
+ : first(move(p.get().first)), second(move(p.get().second))
+ {}
+ #else
+ template <class D, class S>
+ pair(pair<D, S> && p)
+ : first(move(p.first)), second(move(p.second))
+ {}
+ #endif
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ template <class U, class V>
+ pair(const detail::moved_object<U> &x, const detail::moved_object<V> &y)
+ : first(move(x.get())), second(move(y.get()))
+ {}
+ #else
+ template <class U, class V>
+ pair(U &&x, V &&y)
+ : first(move(x)), second(move(y))
+ {}
+ #endif
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ pair(const detail::moved_object<pair> &p)
+ : first(move(p.get().first)), second(move(p.get().second))
+ {}
+ #else
+ pair(pair &&p)
+ : first(move(p.first)), second(move(p.second))
+ {}
+ #endif
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ pair& operator=(const detail::moved_object<pair> &p)
+ {
+ first = move(p.get().first);
+ second = move(p.get().second);
+ return *this;
+ }
+ #else
+ pair& operator=(pair &&p)
+ {
+ first = move(p.first);
+ second = move(p.second);
+ return *this;
+ }
+ #endif
+
+ pair& operator=(const pair &p)
+ {
+ first = p.first;
+ second = p.second;
+ return *this;
+ }
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ template <class D, class S>
+ pair& operator=(const detail::moved_object<std::pair<D, S> > &p)
+ {
+ first = move(p.get().first);
+ second = move(p.get().second);
+ return *this;
+ }
+ #else
+ template <class D, class S>
+ pair& operator=(std::pair<D, S> &&p)
+ {
+ first = move(p.first);
+ second = move(p.second);
+ return *this;
+ }
+ #endif
+
+ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+ void swap(const detail::moved_object<pair> &p)
+ { std::swap(*this, p.get()); }
+
+ void swap(pair& p)
+ { std::swap(*this, p); }
+
+ #else
+ void swap(pair &&p)
+ { std::swap(*this, p); }
+ #endif
+};
+
+template <class T1, class T2>
+inline bool operator==(const pair<T1,T2>& x, const pair<T1,T2>& y)
+{ return static_cast<bool>(x.first == y.first && x.second == y.second); }
+
+template <class T1, class T2>
+inline bool operator< (const pair<T1,T2>& x, const pair<T1,T2>& y)
+{ return static_cast<bool>(x.first < y.first ||
+ (!(y.first < x.first) && x.second < y.second)); }
+
+template <class T1, class T2>
+inline bool operator!=(const pair<T1,T2>& x, const pair<T1,T2>& y)
+{ return static_cast<bool>(!(x == y)); }
+
+template <class T1, class T2>
+inline bool operator> (const pair<T1,T2>& x, const pair<T1,T2>& y)
+{ return y < x; }
+
+template <class T1, class T2>
+inline bool operator>=(const pair<T1,T2>& x, const pair<T1,T2>& y)
+{ return static_cast<bool>(!(x < y)); }
+
+template <class T1, class T2>
+inline bool operator<=(const pair<T1,T2>& x, const pair<T1,T2>& y)
+{ return static_cast<bool>(!(y < x)); }
+
+template <class T1, class T2>
+inline pair<T1, T2> make_pair(T1 x, T2 y)
+{ return pair<T1, T2>(x, y); }
+
+#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
+template <class T1, class T2>
+inline void swap(const detail::moved_object<pair<T1, T2> > &x, pair<T1, T2>& y)
+{
+ swap(x.get().first, y.first);
+ swap(x.get().second, y.second);
+}
+
+template <class T1, class T2>
+inline void swap(pair<T1, T2>& x, const detail::moved_object<pair<T1, T2> > &y)
+{
+ swap(x.first, y.get().first);
+ swap(x.second, y.get().second);
+}
+
+template <class T1, class T2>
+inline void swap(pair<T1, T2>& x, pair<T1, T2>& y)
+{
+ swap(x.first, y.first);
+ swap(x.second, y.second);
+}
+
+#else
+template <class T1, class T2>
+inline void swap(pair<T1, T2>&&x, pair<T1, T2>&&y)
+{
+ swap(x.first, y.first);
+ swap(x.second, y.second);
+}
+#endif
+
+template<class T>
+struct cast_functor
+{
+ typedef typename detail::add_reference<T>::type result_type;
+ result_type operator()(char &ptr) const
+ { return *static_cast<T*>(static_cast<void*>(&ptr)); }
+};
+
+template<class MultiallocChain, class T>
+class multiallocation_chain_adaptor
+{
+ private:
+ MultiallocChain chain_;
+
+ multiallocation_chain_adaptor
+ (const multiallocation_chain_adaptor &);
+ multiallocation_chain_adaptor &operator=
+ (const multiallocation_chain_adaptor &);
+
+ public:
+ typedef transform_iterator
+ < typename MultiallocChain::
+ multiallocation_iterator
+ , detail::cast_functor <T> > multiallocation_iterator;
+
+ multiallocation_chain_adaptor()
+ : chain_()
+ {}
+
+ void push_back(T *mem)
+ { chain_.push_back(mem); }
+
+ void push_front(T *mem)
+ { chain_.push_front(mem); }
+
+ void swap(multiallocation_chain_adaptor &other_chain)
+ { chain_.swap(other_chain.chain_); }
+
+ void splice_back(multiallocation_chain_adaptor &other_chain)
+ { chain_.splice_back(other_chain.chain_); }
+
+ T *pop_front()
+ { return static_cast<T*>(chain_.pop_front()); }
+
+ bool empty() const
+ { return chain_.empty(); }
+
+ multiallocation_iterator get_it() const
+ { return multiallocation_iterator(chain_.get_it()); }
+
+ std::size_t size() const
+ { return chain_.size(); }
+};
+
+} //namespace detail {
+
+//!The pair is movable if any of its members is movable
+template <class T1, class T2>
+struct is_movable<boost::interprocess::detail::pair<T1, T2> >
+{
+ enum { value = is_movable<T1>::value || is_movable<T2>::value };
+};
+
+//!The pair is movable if any of its members is movable
+template <class T1, class T2>
+struct is_movable<std::pair<T1, T2> >
+{
+ enum { value = is_movable<T1>::value || is_movable<T2>::value };
+};
+
+///has_trivial_destructor_after_move<> == true_type
+///specialization for optimizations
+template <class T>
+struct has_trivial_destructor_after_move
+ : public boost::has_trivial_destructor<T>
+{};
+
+template <typename T> T*
+addressof(T& v)
+{
+ return reinterpret_cast<T*>(
+ &const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
+}
+
+//Anti-exception node eraser
+template<class Cont>
+class value_eraser
+{
+ public:
+ value_eraser(Cont & cont, typename Cont::iterator it)
+ : m_cont(cont), m_index_it(it), m_erase(true){}
+ ~value_eraser()
+ { if(m_erase) m_cont.erase(m_index_it); }
+
+ void release() { m_erase = false; }
+
+ private:
+ Cont &m_cont;
+ typename Cont::iterator m_index_it;
+ bool m_erase;
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
+
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk