Imported existing code

This commit is contained in:
Hazim Gazov
2010-04-02 02:48:44 -03:00
parent 48fbc5ae91
commit 7a86d01598
13996 changed files with 2468699 additions and 0 deletions

View File

@@ -0,0 +1,465 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_ADAPTIVE_POOL_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/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes adaptive_pool pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail{
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class adaptive_pool_base
: public node_pool_allocation_impl
< adaptive_pool_base
< Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
, Version
, T
, SegmentManager
>
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef SegmentManager segment_manager;
typedef adaptive_pool_base
<Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> self_t;
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::shared_adaptive_node_pool
< SegmentManager, sizeof_value<T>::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
/// @endcond
BOOST_STATIC_ASSERT((Version <=2));
public:
//-------
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type<adaptive_pool_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains adaptive_pool_base from
//!adaptive_pool_base
template<class T2>
struct rebind
{
typedef adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
/// @cond
private:
//!Not assignable from related adaptive_pool_base
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char O2>
adaptive_pool_base& operator=
(const adaptive_pool_base<Version2, T2, SegmentManager2, N2, F2, O2>&);
/// @endcond
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
adaptive_pool_base(segment_manager *segment_mngr)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
//!Copy constructor from other adaptive_pool_base. Increments the reference
//!count of the associated node pool. Never throws
adaptive_pool_base(const adaptive_pool_base &other)
: mp_node_pool(other.get_node_pool())
{
node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count();
}
//!Assignment from other adaptive_pool_base
adaptive_pool_base& operator=(const adaptive_pool_base &other)
{
adaptive_pool_base c(other);
swap(*this, c);
return *this;
}
//!Copy constructor from related adaptive_pool_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
adaptive_pool_base
(const adaptive_pool_base<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~adaptive_pool_base()
{ detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); }
//!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
{ return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); }
//!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)
{ detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
/// @cond
private:
void_pointer mp_node_pool;
/// @endcond
};
//!Equality test for same type
//!of adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
bool operator==(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type
//!of adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NPC, std::size_t F, unsigned char OP> inline
bool operator!=(const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc1,
const adaptive_pool_base<V, T, S, NPC, F, OP> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class adaptive_pool_v1
: public adaptive_pool_base
< 1
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
{
public:
typedef detail::adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
template<class T2>
struct rebind
{
typedef adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
adaptive_pool_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
adaptive_pool_v1
(const adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
//!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 adaptive_pool with equal sizeof(T) placed in the same segment
//!group. NodesPerBlock is the number of nodes allocated at once when the allocator
//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class adaptive_pool
/// @cond
: public detail::adaptive_pool_base
< 2
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
adaptive_pool(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains adaptive_pool from
//!adaptive_pool
template<class T2>
struct rebind
{
typedef adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
adaptive_pool& operator=
(const adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
//!Not assignable from
//!other adaptive_pool
//adaptive_pool& operator=(const adaptive_pool&);
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
adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
adaptive_pool(const adaptive_pool &other);
//!Copy constructor from related adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!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);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!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);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!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();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!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);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain it);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,304 @@
///////////////////////////////////////////////////////////////////////////////
//
// (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_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
#include <stdexcept>
//!\file
//!Describes an allocator that allocates portions of fixed size
//!memory buffer (shared memory, mapped file...)
namespace boost {
namespace interprocess {
//!An STL compatible allocator that uses a segment manager as
//!memory source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
template<class T, class SegmentManager>
class allocator
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
//Self type
typedef allocator<T, SegmentManager> self_t;
//Pointer to void
typedef typename segment_manager::void_pointer aux_pointer_t;
//Typedef to const void pointer
typedef typename
boost::pointer_to_other
<aux_pointer_t, const void>::type cvoid_ptr;
//Pointer to the allocator
typedef typename boost::pointer_to_other
<cvoid_ptr, segment_manager>::type alloc_ptr_t;
//Not assignable from related allocator
template<class T2, class SegmentManager2>
allocator& operator=(const allocator<T2, SegmentManager2>&);
//Not assignable from other allocator
allocator& operator=(const allocator&);
//Pointer to the allocator
alloc_ptr_t mp_mngr;
/// @endcond
public:
typedef T value_type;
typedef typename boost::pointer_to_other
<cvoid_ptr, T>::type pointer;
typedef typename boost::
pointer_to_other<pointer, const T>::type const_pointer;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type<allocator, 2> version;
/// @cond
//Experimental. Don't use.
typedef boost::interprocess::detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
/// @endcond
//!Obtains an allocator that allocates
//!objects of type T2
template<class T2>
struct rebind
{
typedef allocator<T2, SegmentManager> other;
};
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return detail::get_pointer(mp_mngr); }
//!Constructor from the segment manager.
//!Never throws
allocator(segment_manager *segment_mngr)
: mp_mngr(segment_mngr) { }
//!Constructor from other allocator.
//!Never throws
allocator(const allocator &other)
: mp_mngr(other.get_segment_manager()){ }
//!Constructor from related allocator.
//!Never throws
template<class T2>
allocator(const allocator<T2, SegmentManager> &other)
: mp_mngr(other.get_segment_manager()){}
//!Allocates memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_ptr hint = 0)
{
(void)hint;
if(count > this->max_size())
throw bad_alloc();
return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
}
//!Deallocates memory previously allocated.
//!Never throws
void deallocate(const pointer &ptr, size_type)
{ mp_mngr->deallocate((void*)detail::get_pointer(ptr)); }
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const
{ return mp_mngr->get_size()/sizeof(T); }
//!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); }
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)mp_mngr->size(detail::get_pointer(p))/sizeof(T);
}
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0)
{
return mp_mngr->allocation_command
(command, limit_size, preferred_size, received_size, detail::get_pointer(reuse));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many
(size_type elem_size, std::size_t num_elements)
{
return multiallocation_chain(mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements));
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many
(const size_type *elem_sizes, size_type n_elements)
{
multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T)));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain)
{
return mp_mngr->deallocate_many(chain.extract_multiallocation_chain());
}
//!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); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual
(std::size_t num_elements)
{ return this->allocate_many(1, num_elements); }
//!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); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{ return this->deallocate_many(boost::interprocess::move(chain)); }
//!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)); }
//!Copy construct an object
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v)
{ new((void*)detail::get_pointer(ptr)) value_type(v); }
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr)
{ new((void*)detail::get_pointer(ptr)) value_type; }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
//!Equality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator==(const allocator<T , SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
//!Inequality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator!=(const allocator<T, SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
} //namespace interprocess {
/// @cond
template<class T>
struct has_trivial_destructor;
template<class T, class SegmentManager>
struct has_trivial_destructor
<boost::interprocess::allocator <T, SegmentManager> >
{
enum { value = true };
};
/// @endcond
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP

View File

@@ -0,0 +1,354 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_CACHED_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
//!\file
//!Describes cached_adaptive_pool pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class cached_adaptive_pool_v1
: public detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 1>
{
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 1> base_t;
template<class T2>
struct rebind
{
typedef cached_adaptive_pool_v1
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
cached_adaptive_pool_v1(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool_v1
(const cached_adaptive_pool_v1
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
//!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_adaptive_pool with equal sizeof(T) placed in the same
//!memory segment. But also caches some nodes privately to
//!avoid some synchronization overhead.
//!
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class cached_adaptive_pool
/// @cond
: public detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 2>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_adaptive_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
, 2> base_t;
public:
typedef boost::interprocess::version_type<cached_adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef cached_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
cached_adaptive_pool(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains cached_adaptive_pool from
//!cached_adaptive_pool
template<class T2>
struct rebind
{
typedef cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related cached_adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
cached_adaptive_pool& operator=
(const cached_adaptive_pool<T2, SegmentManager2, N2, F2, OP2>&);
//!Not assignable from
//!other cached_adaptive_pool
cached_adaptive_pool& operator=(const cached_adaptive_pool&);
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
cached_adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other cached_adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
cached_adaptive_pool(const cached_adaptive_pool &other);
//!Copy constructor from related cached_adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~cached_adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!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);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!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);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!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();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!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);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
//!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);
//!Returns the max cached nodes parameter.
//!Never throws
std::size_t get_max_cached_nodes() const;
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of cached_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
bool operator==(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of cached_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, std::size_t OP> inline
bool operator!=(const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const cached_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,324 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_CACHED_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <cstddef>
//!\file
//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class cached_node_allocator_v1
: public detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 1>
{
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 1> base_t;
template<class T2>
struct rebind
{
typedef cached_node_allocator_v1
<T2, SegmentManager, NodesPerBlock> other;
};
cached_node_allocator_v1(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_node_allocator_v1
(const cached_node_allocator_v1
<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class cached_node_allocator
/// @cond
: public detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 2>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef detail::cached_allocator_impl
< T
, detail::shared_node_pool
< SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
>
, 2> base_t;
public:
typedef boost::interprocess::version_type<cached_node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef cached_node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
cached_node_allocator(SegmentManager *segment_mngr,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(segment_mngr, max_cached_nodes)
{}
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains cached_node_allocator from
//!cached_node_allocator
template<class T2>
struct rebind
{
typedef cached_node_allocator<T2, SegmentManager> other;
};
private:
//!Not assignable from
//!related cached_node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
cached_node_allocator& operator=
(const cached_node_allocator<T2, SegmentManager2, N2>&);
//!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 associated node pool.
//!Can throw boost::interprocess::bad_alloc
cached_node_allocator(segment_manager *segment_mngr);
//!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);
//!Copy constructor from related cached_node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~cached_node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!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);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!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);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!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();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!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);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain it);
//!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);
//!Returns the max cached nodes parameter.
//!Never throws
std::size_t get_max_cached_nodes() const;
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of cached_node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator==(const cached_node_allocator<T, S, NPC> &alloc1,
const cached_node_allocator<T, S, NPC> &alloc2);
//!Inequality test for same type
//!of cached_node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator!=(const cached_node_allocator<T, S, NPC> &alloc1,
const cached_node_allocator<T, S, NPC> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CACHED_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,639 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_ADAPTIVE_NODE_POOL_HPP
#define BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_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/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/slist.hpp>
#include <boost/math/common_factor_ct.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <cstddef>
#include <boost/config/no_tr1/cmath.hpp>
#include <cassert>
//!\file
//!Describes the real adaptive pool shared by many Interprocess pool allocators
namespace boost {
namespace interprocess {
namespace detail {
template<class SegmentManagerBase>
class private_adaptive_node_pool_impl
{
//Non-copyable
private_adaptive_node_pool_impl();
private_adaptive_node_pool_impl(const private_adaptive_node_pool_impl &);
private_adaptive_node_pool_impl &operator=(const private_adaptive_node_pool_impl &);
typedef typename SegmentManagerBase::void_pointer void_pointer;
static const std::size_t PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation;
public:
typedef typename node_slist<void_pointer>::node_t node_t;
typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain;
private:
typedef typename bi::make_set_base_hook
< bi::void_pointer<void_pointer>
, bi::optimize_size<true>
, bi::constant_time_size<false>
, bi::link_mode<bi::normal_link> >::type multiset_hook_t;
struct hdr_offset_holder
{
hdr_offset_holder(std::size_t offset = 0)
: hdr_offset(offset)
{}
std::size_t hdr_offset;
};
struct block_info_t
:
public hdr_offset_holder,
public multiset_hook_t
{
//An intrusive list of free node from this block
free_nodes_t free_nodes;
friend bool operator <(const block_info_t &l, const block_info_t &r)
{
// { return l.free_nodes.size() < r.free_nodes.size(); }
//Let's order blocks first by free nodes and then by address
//so that highest address fully free blocks are deallocated.
//This improves returning memory to the OS (trimming).
const bool is_less = l.free_nodes.size() < r.free_nodes.size();
const bool is_equal = l.free_nodes.size() == r.free_nodes.size();
return is_less || (is_equal && (&l < &r));
}
};
typedef typename bi::make_multiset
<block_info_t, bi::base_hook<multiset_hook_t> >::type block_multiset_t;
typedef typename block_multiset_t::iterator block_iterator;
static const std::size_t MaxAlign = alignment_of<node_t>::value;
static const std::size_t HdrSize = ((sizeof(block_info_t)-1)/MaxAlign+1)*MaxAlign;
static const std::size_t HdrOffsetSize = ((sizeof(hdr_offset_holder)-1)/MaxAlign+1)*MaxAlign;
static std::size_t calculate_alignment
(std::size_t overhead_percent, std::size_t real_node_size)
{
//to-do: handle real_node_size != node_size
const std::size_t divisor = overhead_percent*real_node_size;
const std::size_t dividend = HdrOffsetSize*100;
std::size_t elements_per_subblock = (dividend - 1)/divisor + 1;
std::size_t candidate_power_of_2 =
upper_power_of_2(elements_per_subblock*real_node_size + HdrOffsetSize);
bool overhead_satisfied = false;
//Now calculate the wors-case overhead for a subblock
const std::size_t max_subblock_overhead = HdrSize + PayloadPerAllocation;
while(!overhead_satisfied){
elements_per_subblock = (candidate_power_of_2 - max_subblock_overhead)/real_node_size;
const std::size_t overhead_size = candidate_power_of_2 - elements_per_subblock*real_node_size;
if(overhead_size*100/candidate_power_of_2 < overhead_percent){
overhead_satisfied = true;
}
else{
candidate_power_of_2 <<= 1;
}
}
return candidate_power_of_2;
}
static void calculate_num_subblocks
(std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_block
,std::size_t &num_subblocks, std::size_t &real_num_node, std::size_t overhead_percent)
{
std::size_t elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size;
std::size_t possible_num_subblock = (elements_per_block - 1)/elements_per_subblock + 1;
std::size_t hdr_subblock_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size;
while(((possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements) < elements_per_block){
++possible_num_subblock;
}
elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size;
bool overhead_satisfied = false;
while(!overhead_satisfied){
const std::size_t total_data = (elements_per_subblock*(possible_num_subblock-1) + hdr_subblock_elements)*real_node_size;
const std::size_t total_size = alignment*possible_num_subblock;
if((total_size - total_data)*100/total_size < overhead_percent){
overhead_satisfied = true;
}
else{
++possible_num_subblock;
}
}
num_subblocks = possible_num_subblock;
real_num_node = (possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements;
}
public:
//!Segment manager typedef
typedef SegmentManagerBase segment_manager_base_type;
//!Constructor from a segment manager. Never throws
private_adaptive_node_pool_impl
( segment_manager_base_type *segment_mngr_base, std::size_t node_size
, std::size_t nodes_per_block, std::size_t max_free_blocks
, unsigned char overhead_percent
)
: m_max_free_blocks(max_free_blocks)
, m_real_node_size(lcm(node_size, std::size_t(alignment_of<node_t>::value)))
//Round the size to a power of two value.
//This is the total memory size (including payload) that we want to
//allocate from the general-purpose allocator
, m_real_block_alignment(calculate_alignment(overhead_percent, m_real_node_size))
//This is the real number of nodes per block
, m_num_subblocks(0)
, m_real_num_node(0)
//General purpose allocator
, mp_segment_mngr_base(segment_mngr_base)
, m_block_multiset()
, m_totally_free_blocks(0)
{
calculate_num_subblocks(m_real_block_alignment, m_real_node_size, nodes_per_block, m_num_subblocks, m_real_num_node, overhead_percent);
}
//!Destructor. Deallocates all allocated blocks. Never throws
~private_adaptive_node_pool_impl()
{ priv_clear(); }
std::size_t get_real_num_node() const
{ return m_real_num_node; }
//!Returns the segment manager. Never throws
segment_manager_base_type* get_segment_manager_base()const
{ return detail::get_pointer(mp_segment_mngr_base); }
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
priv_invariants();
//If there are no free nodes we allocate a new block
if (m_block_multiset.empty()){
priv_alloc_block(1);
}
//We take the first free node the multiset can't be empty
return priv_take_first_node();
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *pElem)
{
multiallocation_chain chain;
chain.push_front(void_pointer(pElem));
this->priv_reinsert_nodes_in_block(chain, 1);
//Update free block count
if(m_totally_free_blocks > m_max_free_blocks){
this->priv_deallocate_free_blocks(m_max_free_blocks);
}
priv_invariants();
}
//!Allocates n nodes.
//!Can throw boost::interprocess::bad_alloc
multiallocation_chain allocate_nodes(const std::size_t n)
{
multiallocation_chain chain;
std::size_t i = 0;
try{
priv_invariants();
while(i != n){
//If there are no free nodes we allocate all needed blocks
if (m_block_multiset.empty()){
priv_alloc_block(((n - i) - 1)/m_real_num_node + 1);
}
free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;
const std::size_t free_nodes_count_before = free_nodes.size();
if(free_nodes_count_before == m_real_num_node){
--m_totally_free_blocks;
}
const std::size_t num_elems = ((n-i) < free_nodes_count_before) ? (n-i) : free_nodes_count_before;
for(std::size_t j = 0; j != num_elems; ++j){
void *new_node = &free_nodes.front();
free_nodes.pop_front();
chain.push_back(new_node);
}
if(free_nodes.empty()){
m_block_multiset.erase(m_block_multiset.begin());
}
i += num_elems;
}
}
catch(...){
this->deallocate_nodes(chain, i);
throw;
}
priv_invariants();
return boost::interprocess::move(chain);
}
//!Deallocates a linked list of nodes. Never throws
void deallocate_nodes(multiallocation_chain nodes)
{
return deallocate_nodes(nodes, nodes.size());
}
//!Deallocates the first n nodes of a linked list of nodes. Never throws
void deallocate_nodes(multiallocation_chain &nodes, std::size_t n)
{
this->priv_reinsert_nodes_in_block(nodes, n);
if(m_totally_free_blocks > m_max_free_blocks){
this->priv_deallocate_free_blocks(m_max_free_blocks);
}
}
void deallocate_free_blocks()
{ this->priv_deallocate_free_blocks(0); }
std::size_t num_free_nodes()
{
typedef typename block_multiset_t::const_iterator citerator;
std::size_t count = 0;
citerator it (m_block_multiset.begin()), itend(m_block_multiset.end());
for(; it != itend; ++it){
count += it->free_nodes.size();
}
return count;
}
void swap(private_adaptive_node_pool_impl &other)
{
assert(m_max_free_blocks == other.m_max_free_blocks);
assert(m_real_node_size == other.m_real_node_size);
assert(m_real_block_alignment == other.m_real_block_alignment);
assert(m_real_num_node == other.m_real_num_node);
std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
std::swap(m_totally_free_blocks, other.m_totally_free_blocks);
m_block_multiset.swap(other.m_block_multiset);
}
//Deprecated, use deallocate_free_blocks
void deallocate_free_chunks()
{ this->priv_deallocate_free_blocks(0); }
private:
void priv_deallocate_free_blocks(std::size_t max_free_blocks)
{
priv_invariants();
//Now check if we've reached the free nodes limit
//and check if we have free blocks. If so, deallocate as much
//as we can to stay below the limit
for( block_iterator itend = m_block_multiset.end()
; m_totally_free_blocks > max_free_blocks
; --m_totally_free_blocks
){
assert(!m_block_multiset.empty());
block_iterator it = itend;
--it;
std::size_t num_nodes = it->free_nodes.size();
assert(num_nodes == m_real_num_node);
(void)num_nodes;
m_block_multiset.erase_and_dispose
(it, block_destroyer(this));
}
}
void priv_reinsert_nodes_in_block(multiallocation_chain &chain, std::size_t n)
{
block_iterator block_it(m_block_multiset.end());
while(n--){
void *pElem = detail::get_pointer(chain.front());
chain.pop_front();
priv_invariants();
block_info_t *block_info = this->priv_block_from_node(pElem);
assert(block_info->free_nodes.size() < m_real_num_node);
//We put the node at the beginning of the free node list
node_t * to_deallocate = static_cast<node_t*>(pElem);
block_info->free_nodes.push_front(*to_deallocate);
block_iterator this_block(block_multiset_t::s_iterator_to(*block_info));
block_iterator next_block(this_block);
++next_block;
//Cache the free nodes from the block
std::size_t this_block_free_nodes = this_block->free_nodes.size();
if(this_block_free_nodes == 1){
m_block_multiset.insert(m_block_multiset.begin(), *block_info);
}
else{
block_iterator next_block(this_block);
++next_block;
if(next_block != block_it){
std::size_t next_free_nodes = next_block->free_nodes.size();
if(this_block_free_nodes > next_free_nodes){
//Now move the block to the new position
m_block_multiset.erase(this_block);
m_block_multiset.insert(*block_info);
}
}
}
//Update free block count
if(this_block_free_nodes == m_real_num_node){
++m_totally_free_blocks;
}
priv_invariants();
}
}
node_t *priv_take_first_node()
{
assert(m_block_multiset.begin() != m_block_multiset.end());
//We take the first free node the multiset can't be empty
free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;
node_t *first_node = &free_nodes.front();
const std::size_t free_nodes_count = free_nodes.size();
assert(0 != free_nodes_count);
free_nodes.pop_front();
if(free_nodes_count == 1){
m_block_multiset.erase(m_block_multiset.begin());
}
else if(free_nodes_count == m_real_num_node){
--m_totally_free_blocks;
}
priv_invariants();
return first_node;
}
class block_destroyer;
friend class block_destroyer;
class block_destroyer
{
public:
block_destroyer(const private_adaptive_node_pool_impl *impl)
: mp_impl(impl)
{}
void operator()(typename block_multiset_t::pointer to_deallocate)
{
std::size_t free_nodes = to_deallocate->free_nodes.size();
(void)free_nodes;
assert(free_nodes == mp_impl->m_real_num_node);
assert(0 == to_deallocate->hdr_offset);
hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block(detail::get_pointer(to_deallocate));
mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder);
}
const private_adaptive_node_pool_impl *mp_impl;
};
//This macro will activate invariant checking. Slow, but helpful for debugging the code.
//#define BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
void priv_invariants()
#ifdef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
#undef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS
{
//We iterate through the block list to free the memory
block_iterator it(m_block_multiset.begin()),
itend(m_block_multiset.end()), to_deallocate;
if(it != itend){
for(++it; it != itend; ++it){
block_iterator prev(it);
--prev;
std::size_t sp = prev->free_nodes.size(),
si = it->free_nodes.size();
assert(sp <= si);
(void)sp; (void)si;
}
}
{
//Check that the total free nodes are correct
it = m_block_multiset.begin();
itend = m_block_multiset.end();
std::size_t total_free_nodes = 0;
for(; it != itend; ++it){
total_free_nodes += it->free_nodes.size();
}
assert(total_free_nodes >= m_totally_free_blocks*m_real_num_node);
}
{
//Check that the total totally free blocks are correct
it = m_block_multiset.begin();
itend = m_block_multiset.end();
std::size_t total_free_blocks = 0;
for(; it != itend; ++it){
total_free_blocks += (it->free_nodes.size() == m_real_num_node);
}
assert(total_free_blocks == m_totally_free_blocks);
}
{
//Check that header offsets are correct
it = m_block_multiset.begin();
for(; it != itend; ++it){
hdr_offset_holder *hdr_off_holder = priv_first_subblock_from_block(&*it);
for(std::size_t i = 0, max = m_num_subblocks; i < max; ++i){
assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(&*it)- reinterpret_cast<char*>(hdr_off_holder)));
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
hdr_off_holder = reinterpret_cast<hdr_offset_holder *>(reinterpret_cast<char*>(hdr_off_holder) + m_real_block_alignment);
}
}
}
}
#else
{} //empty
#endif
//!Deallocates all used memory. Never throws
void priv_clear()
{
#ifndef NDEBUG
block_iterator it = m_block_multiset.begin();
block_iterator itend = m_block_multiset.end();
std::size_t num_free_nodes = 0;
for(; it != itend; ++it){
//Check for memory leak
std::size_t n = (std::size_t)it->free_nodes.size(); (void)n;
assert(it->free_nodes.size() == m_real_num_node);
++num_free_nodes;
}
assert(num_free_nodes == m_totally_free_blocks);
#endif
priv_invariants();
m_block_multiset.clear_and_dispose
(block_destroyer(this));
m_totally_free_blocks = 0;
}
block_info_t *priv_block_from_node(void *node) const
{
hdr_offset_holder *hdr_off_holder =
reinterpret_cast<hdr_offset_holder*>((std::size_t)node & std::size_t(~(m_real_block_alignment - 1)));
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
block_info_t *block = reinterpret_cast<block_info_t *>
(reinterpret_cast<char*>(hdr_off_holder) + hdr_off_holder->hdr_offset);
assert(block->hdr_offset == 0);
return block;
}
hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const
{
hdr_offset_holder *hdr_off_holder = reinterpret_cast<hdr_offset_holder*>
(reinterpret_cast<char*>(block) - (m_num_subblocks-1)*m_real_block_alignment);
assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(block) - reinterpret_cast<char*>(hdr_off_holder)));
assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));
assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));
return hdr_off_holder;
}
//!Allocates a several blocks of nodes. Can throw boost::interprocess::bad_alloc
void priv_alloc_block(std::size_t n)
{
std::size_t real_block_size = m_real_block_alignment*m_num_subblocks - SegmentManagerBase::PayloadPerAllocation;
std::size_t elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size;
std::size_t hdr_subblock_elements = (m_real_block_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size;
for(std::size_t i = 0; i != n; ++i){
//We allocate a new NodeBlock and put it the last
//element of the tree
char *mem_address = static_cast<char*>
(mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment));
if(!mem_address) throw std::bad_alloc();
++m_totally_free_blocks;
//First initialize header information on the last subblock
char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1);
block_info_t *c_info = new(hdr_addr)block_info_t;
//Some structural checks
assert(static_cast<void*>(&static_cast<hdr_offset_holder*>(c_info)->hdr_offset) ==
static_cast<void*>(c_info));
typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin();
for( std::size_t subblock = 0, maxsubblock = m_num_subblocks - 1
; subblock < maxsubblock
; ++subblock, mem_address += m_real_block_alignment){
//Initialize header offset mark
new(mem_address) hdr_offset_holder(std::size_t(hdr_addr - mem_address));
char *pNode = mem_address + HdrOffsetSize;
for(std::size_t i = 0; i < elements_per_subblock; ++i){
prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);
pNode += m_real_node_size;
}
}
{
char *pNode = hdr_addr + HdrSize;
//We initialize all Nodes in Node Block to insert
//them in the free Node list
for(std::size_t i = 0; i < hdr_subblock_elements; ++i){
prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);
pNode += m_real_node_size;
}
}
//Insert the block after the free node list is full
m_block_multiset.insert(m_block_multiset.end(), *c_info);
}
}
private:
typedef typename boost::pointer_to_other
<void_pointer, segment_manager_base_type>::type segment_mngr_base_ptr_t;
const std::size_t m_max_free_blocks;
const std::size_t m_real_node_size;
//Round the size to a power of two value.
//This is the total memory size (including payload) that we want to
//allocate from the general-purpose allocator
const std::size_t m_real_block_alignment;
std::size_t m_num_subblocks;
//This is the real number of nodes per block
//const
std::size_t m_real_num_node;
segment_mngr_base_ptr_t mp_segment_mngr_base;//Segment manager
block_multiset_t m_block_multiset; //Intrusive block list
std::size_t m_totally_free_blocks; //Free blocks
};
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_node_pool
: public private_adaptive_node_pool_impl
<typename SegmentManager::segment_manager_base_type>
{
typedef private_adaptive_node_pool_impl
<typename SegmentManager::segment_manager_base_type> base_t;
//Non-copyable
private_adaptive_node_pool();
private_adaptive_node_pool(const private_adaptive_node_pool &);
private_adaptive_node_pool &operator=(const private_adaptive_node_pool &);
public:
typedef SegmentManager segment_manager;
static const std::size_t nodes_per_block = NodesPerBlock;
//Deprecated, use node_per_block
static const std::size_t nodes_per_chunk = NodesPerBlock;
//!Constructor from a segment manager. Never throws
private_adaptive_node_pool(segment_manager *segment_mngr)
: base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent)
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager() const
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
};
//!Pooled shared memory allocator using adaptive pool. 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 block (NodesPerBlock) are known at compile time
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class shared_adaptive_node_pool
: public detail::shared_pool_impl
< private_adaptive_node_pool
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
>
{
typedef detail::shared_pool_impl
< private_adaptive_node_pool
<SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>
> base_t;
public:
shared_adaptive_node_pool(SegmentManager *segment_mgnr)
: base_t(segment_mgnr)
{}
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP

View File

@@ -0,0 +1,839 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 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_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp> //get_pointer
#include <utility> //std::pair
#include <boost/utility/addressof.hpp> //boost::addressof
#include <boost/assert.hpp> //BOOST_ASSERT
#include <boost/interprocess/exceptions.hpp> //bad_alloc
#include <boost/interprocess/sync/scoped_lock.hpp> //scoped_lock
#include <boost/interprocess/containers/allocation_type.hpp> //boost::interprocess::allocation_type
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/detail/segment_manager_helper.hpp>
#include <algorithm> //std::swap
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
namespace boost {
namespace interprocess {
template <class T>
struct sizeof_value
{
static const std::size_t value = sizeof(T);
};
template <>
struct sizeof_value<void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<const void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<volatile void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<const volatile void>
{
static const std::size_t value = sizeof(void*);
};
namespace detail {
//!Object function that creates the node allocator if it is not created and
//!increments reference count if it is already created
template<class NodePool>
struct get_or_create_node_pool_func
{
//!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_segment_manager->template find_or_construct
<NodePool>(boost::interprocess::unique_instance)(mp_segment_manager);
//If valid, increment link count
if(mp_node_pool != 0)
mp_node_pool->inc_ref_count();
}
//!Constructor. Initializes function
//!object parameters
get_or_create_node_pool_func(typename NodePool::segment_manager *mngr)
: mp_segment_manager(mngr){}
NodePool *mp_node_pool;
typename NodePool::segment_manager *mp_segment_manager;
};
template<class NodePool>
inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr)
{
detail::get_or_create_node_pool_func<NodePool> func(mgnr);
mgnr->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
template<class NodePool>
struct destroy_if_last_link_func
{
//!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_node_pool->get_segment_manager()->template destroy<NodePool>(boost::interprocess::unique_instance);
}
//!Constructor. Initializes function
//!object parameters
destroy_if_last_link_func(NodePool *pool)
: mp_node_pool(pool)
{}
NodePool *mp_node_pool;
};
//!Destruction function, initializes and executes destruction function
//!object. Never throws
template<class NodePool>
inline void destroy_node_pool_if_last_link(NodePool *pool)
{
//Get segment manager
typename NodePool::segment_manager *mngr = pool->get_segment_manager();
//Execute destruction functor atomically
destroy_if_last_link_func<NodePool>func(pool);
mngr->atomic_func(func);
}
template<class NodePool>
class cache_impl
{
typedef typename NodePool::segment_manager::
void_pointer void_pointer;
typedef typename pointer_to_other
<void_pointer, NodePool>::type node_pool_ptr;
typedef typename NodePool::multiallocation_chain multiallocation_chain;
node_pool_ptr mp_node_pool;
multiallocation_chain m_cached_nodes;
std::size_t m_max_cached_nodes;
public:
typedef typename NodePool::segment_manager segment_manager;
cache_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes)
: mp_node_pool(get_or_create_node_pool<NodePool>(segment_mngr))
, m_max_cached_nodes(max_cached_nodes)
{}
cache_impl(const cache_impl &other)
: mp_node_pool(other.get_node_pool())
, m_max_cached_nodes(other.get_max_cached_nodes())
{
mp_node_pool->inc_ref_count();
}
~cache_impl()
{
this->deallocate_all_cached_nodes();
detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool));
}
NodePool *get_node_pool() const
{ return detail::get_pointer(mp_node_pool); }
segment_manager *get_segment_manager() const
{ return mp_node_pool->get_segment_manager(); }
std::size_t get_max_cached_nodes() const
{ return m_max_cached_nodes; }
void *cached_allocation()
{
//If don't have any cached node, we have to get a new list of free nodes from the pool
if(m_cached_nodes.empty()){
m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2);
}
void *ret = detail::get_pointer(m_cached_nodes.front());
m_cached_nodes.pop_front();
return ret;
}
multiallocation_chain cached_allocation(std::size_t n)
{
multiallocation_chain chain;
std::size_t count = n, allocated(0);
BOOST_TRY{
//If don't have any cached node, we have to get a new list of free nodes from the pool
while(!m_cached_nodes.empty() && count--){
void *ret = detail::get_pointer(m_cached_nodes.front());
m_cached_nodes.pop_front();
chain.push_back(ret);
++allocated;
}
if(allocated != n){
multiallocation_chain chain2(mp_node_pool->allocate_nodes(n - allocated));
chain.splice_after(chain.last(), chain2, chain2.before_begin(), chain2.last(), n - allocated);
}
return boost::interprocess::move(chain);
}
BOOST_CATCH(...){
this->cached_deallocation(boost::interprocess::move(chain));
BOOST_RETHROW
}
BOOST_CATCH_END
}
void cached_deallocation(void *ptr)
{
//Check if cache is full
if(m_cached_nodes.size() >= 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.
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2);
}
m_cached_nodes.push_front(ptr);
}
void cached_deallocation(multiallocation_chain chain)
{
m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain);
//Check if cache is full
if(m_cached_nodes.size() >= 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.
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2);
}
}
//!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;
this->priv_deallocate_remaining_nodes();
}
//!Frees all cached nodes.
//!Never throws
void deallocate_all_cached_nodes()
{
if(m_cached_nodes.empty()) return;
mp_node_pool->deallocate_nodes(boost::interprocess::move(m_cached_nodes));
}
private:
//!Frees all cached nodes at once.
//!Never throws
void priv_deallocate_remaining_nodes()
{
if(m_cached_nodes.size() > m_max_cached_nodes){
priv_deallocate_n_nodes(m_cached_nodes.size()-m_max_cached_nodes);
}
}
//!Frees n cached nodes at once. Never throws
void priv_deallocate_n_nodes(std::size_t n)
{
//Deallocate all new linked list at once
mp_node_pool->deallocate_nodes(m_cached_nodes, n);
}
};
template<class Derived, class T, class SegmentManager>
class array_allocation_impl
{
const Derived *derived() const
{ return static_cast<const Derived*>(this); }
Derived *derived()
{ return static_cast<Derived*>(this); }
typedef typename SegmentManager::void_pointer void_pointer;
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
public:
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)this->derived()->get_segment_manager()->size(detail::get_pointer(p))/sizeof(T);
}
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0)
{
return this->derived()->get_segment_manager()->allocation_command
(command, limit_size, preferred_size, received_size, detail::get_pointer(reuse));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements)
{
return this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements);
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements)
{
return this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T));
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain)
{ return this->derived()->get_segment_manager()->deallocate_many(boost::interprocess::move(chain)); }
//!Returns the number of elements that could be
//!allocated. Never throws
size_type max_size() const
{ return this->derived()->get_segment_manager()->get_size()/sizeof(T); }
//!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)); }
//!Default construct an object.
//!Throws if T's default constructor throws
void construct(const pointer &ptr)
{ new((void*)detail::get_pointer(ptr)) value_type; }
//!Copy construct an object
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v)
{ new((void*)detail::get_pointer(ptr)) value_type(v); }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
template<class Derived, unsigned int Version, class T, class SegmentManager>
class node_pool_allocation_impl
: public array_allocation_impl
< Derived
, T
, SegmentManager>
{
const Derived *derived() const
{ return static_cast<const Derived*>(this); }
Derived *derived()
{ return static_cast<Derived*>(this); }
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename boost::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
template <int Dummy>
struct node_pool
{
typedef typename Derived::template node_pool<0>::type type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
public:
//!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)
{
(void)hint;
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
if(count > this->max_size())
throw bad_alloc();
else if(Version == 1 && count == 1)
return pointer(static_cast<value_type*>
(pool->allocate_node()));
else
return pointer(static_cast<value_type*>
(pool->get_segment_manager()->allocate(sizeof(T)*count)));
}
//!Deallocate allocated memory. Never throws
void deallocate(const pointer &ptr, size_type count)
{
(void)count;
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
if(Version == 1 && count == 1)
pool->deallocate_node(detail::get_pointer(ptr));
else
pool->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr));
}
//!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()
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
return pointer(static_cast<value_type*>(pool->allocate_node()));
}
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements)
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
return multiallocation_chain(pool->allocate_nodes(num_elements));
}
//!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)
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
pool->deallocate_node(detail::get_pointer(p));
}
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{
node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes
(chain.extract_multiallocation_chain());
}
//!Deallocates all free blocks of the pool
void deallocate_free_blocks()
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); }
//!Deprecated, use deallocate_free_blocks.
//!Deallocates all free chunks of the pool.
void deallocate_free_chunks()
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); }
};
template<class T, class NodePool, unsigned int Version>
class cached_allocator_impl
: public array_allocation_impl
<cached_allocator_impl<T, NodePool, Version>, T, typename NodePool::segment_manager>
{
cached_allocator_impl & operator=(const cached_allocator_impl& other);
typedef array_allocation_impl
< cached_allocator_impl
<T, NodePool, Version>
, T
, typename NodePool::segment_manager> base_t;
public:
typedef NodePool node_pool_t;
typedef typename NodePool::segment_manager segment_manager;
typedef typename segment_manager::void_pointer void_pointer;
typedef typename boost::
pointer_to_other<void_pointer, const void>::type cvoid_pointer;
typedef typename base_t::pointer pointer;
typedef typename base_t::size_type size_type;
typedef typename base_t::multiallocation_chain multiallocation_chain;
typedef typename base_t::value_type value_type;
public:
enum { DEFAULT_MAX_CACHED_NODES = 64 };
cached_allocator_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes)
: m_cache(segment_mngr, max_cached_nodes)
{}
cached_allocator_impl(const cached_allocator_impl &other)
: m_cache(other.m_cache)
{}
//!Copy constructor from related cached_adaptive_pool_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2, class NodePool2>
cached_allocator_impl
(const cached_allocator_impl
<T2, NodePool2, Version> &other)
: m_cache(other.get_segment_manager(), other.get_max_cached_nodes())
{}
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const
{ return m_cache.get_node_pool(); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return m_cache.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_cache.set_max_cached_nodes(newmax); }
//!Returns the max cached nodes parameter.
//!Never throws
std::size_t get_max_cached_nodes() const
{ return m_cache.get_max_cached_nodes(); }
//!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)
{
(void)hint;
void * ret;
if(count > this->max_size())
throw bad_alloc();
else if(Version == 1 && count == 1){
ret = m_cache.cached_allocation();
}
else{
ret = this->get_segment_manager()->allocate(sizeof(T)*count);
}
return pointer(static_cast<T*>(ret));
}
//!Deallocate allocated memory. Never throws
void deallocate(const pointer &ptr, size_type count)
{
(void)count;
if(Version == 1 && count == 1){
m_cache.cached_deallocation(detail::get_pointer(ptr));
}
else{
this->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr));
}
}
//!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 pointer(static_cast<value_type*>(this->m_cache.cached_allocation())); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements)
{ return multiallocation_chain(this->m_cache.cached_allocation(num_elements)); }
//!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)
{ this->m_cache.cached_deallocation(detail::get_pointer(p)); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain)
{
typename node_pool_t::multiallocation_chain mem
(chain.extract_multiallocation_chain());
m_cache.cached_deallocation(boost::interprocess::move(mem));
}
//!Deallocates all free blocks of the pool
void deallocate_free_blocks()
{ m_cache.get_node_pool()->deallocate_free_blocks(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(cached_allocator_impl &alloc1, cached_allocator_impl &alloc2)
{
detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool);
alloc1.m_cached_nodes.swap(alloc2.m_cached_nodes);
detail::do_swap(alloc1.m_max_cached_nodes, alloc2.m_max_cached_nodes);
}
void deallocate_cache()
{ m_cache.deallocate_all_cached_nodes(); }
//!Deprecated use deallocate_free_blocks.
void deallocate_free_chunks()
{ m_cache.get_node_pool()->deallocate_free_blocks(); }
/// @cond
private:
cache_impl<node_pool_t> m_cache;
};
//!Equality test for same type of
//!cached_allocator_impl
template<class T, class N, unsigned int V> inline
bool operator==(const cached_allocator_impl<T, N, V> &alloc1,
const cached_allocator_impl<T, N, V> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type of
//!cached_allocator_impl
template<class T, class N, unsigned int V> inline
bool operator!=(const cached_allocator_impl<T, N, V> &alloc1,
const cached_allocator_impl<T, N, V> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
//!Pooled shared memory allocator using adaptive pool. 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 block (NodesPerBlock) are known at compile time
template<class private_node_allocator_t>
class shared_pool_impl
: public private_node_allocator_t
{
public:
//!Segment manager typedef
typedef typename private_node_allocator_t::
segment_manager segment_manager;
typedef typename private_node_allocator_t::
multiallocation_chain multiallocation_chain;
private:
typedef typename segment_manager::mutex_family::mutex_type mutex_type;
public:
//!Constructor from a segment manager. Never throws
shared_pool_impl(segment_manager *segment_mngr)
: private_node_allocator_t(segment_mngr)
{}
//!Destructor. Deallocates all allocated blocks. Never throws
~shared_pool_impl()
{}
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_node();
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *ptr)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_node(ptr);
}
/*
//!Allocates a singly linked list of n nodes ending in null pointer.
//!can throw boost::interprocess::bad_alloc
void allocate_nodes(multiallocation_chain &nodes, std::size_t n)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_nodes(nodes, n);
}
*/
//!Allocates n nodes.
//!Can throw boost::interprocess::bad_alloc
multiallocation_chain allocate_nodes(const std::size_t n)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> 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(multiallocation_chain &nodes, std::size_t num)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(nodes, num);
}
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
void deallocate_nodes(multiallocation_chain chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(boost::interprocess::move(chain));
}
//!Deallocates all the free blocks of memory. Never throws
void deallocate_free_blocks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_free_blocks();
}
//!Deallocates all used memory from the common pool.
//!Precondition: all nodes allocated from this pool should
//!already be deallocated. Otherwise, undefined behavior. Never throws
void purge_blocks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::purge_blocks();
}
//!Increments internal reference count and returns new count. Never throws
std::size_t inc_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return ++m_header.m_usecount;
}
//!Decrements internal reference count and returns new count. Never throws
std::size_t dec_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
assert(m_header.m_usecount > 0);
return --m_header.m_usecount;
}
//!Deprecated, use deallocate_free_blocks.
void deallocate_free_chunks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_free_blocks();
}
//!Deprecated, use purge_blocks.
void purge_chunks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::purge_blocks();
}
private:
//!This struct includes needed data and derives from
//!interprocess_mutex to allow EBO when using null_mutex
struct header_t : mutex_type
{
std::size_t m_usecount; //Number of attached allocators
header_t()
: m_usecount(0) {}
} m_header;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP

View File

@@ -0,0 +1,409 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_NODE_POOL_HPP
#define BOOST_INTERPROCESS_DETAIL_NODE_POOL_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/intrusive/slist.hpp>
#include <boost/math/common_factor_ct.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/node_tools.hpp>
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <cstddef>
#include <functional>
#include <algorithm>
#include <cassert>
//!\file
//!Describes the real adaptive pool shared by many Interprocess adaptive pool allocators
namespace boost {
namespace interprocess {
namespace detail {
template<class SegmentManagerBase>
class private_node_pool_impl
{
//Non-copyable
private_node_pool_impl();
private_node_pool_impl(const private_node_pool_impl &);
private_node_pool_impl &operator=(const private_node_pool_impl &);
//A node object will hold node_t when it's not allocated
public:
typedef typename SegmentManagerBase::void_pointer void_pointer;
typedef typename node_slist<void_pointer>::slist_hook_t slist_hook_t;
typedef typename node_slist<void_pointer>::node_t node_t;
typedef typename node_slist<void_pointer>::node_slist_t free_nodes_t;
typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain;
private:
typedef typename bi::make_slist
< node_t, bi::base_hook<slist_hook_t>
, bi::linear<true>
, bi::constant_time_size<false> >::type blockslist_t;
public:
//!Segment manager typedef
typedef SegmentManagerBase segment_manager_base_type;
//!Constructor from a segment manager. Never throws
private_node_pool_impl(segment_manager_base_type *segment_mngr_base, std::size_t node_size, std::size_t nodes_per_block)
: m_nodes_per_block(nodes_per_block)
, m_real_node_size(detail::lcm(node_size, std::size_t(alignment_of<node_t>::value)))
//General purpose allocator
, mp_segment_mngr_base(segment_mngr_base)
, m_blocklist()
, m_freelist()
//Debug node count
, m_allocated(0)
{}
//!Destructor. Deallocates all allocated blocks. Never throws
~private_node_pool_impl()
{ this->purge_blocks(); }
std::size_t get_real_num_node() const
{ return m_nodes_per_block; }
//!Returns the segment manager. Never throws
segment_manager_base_type* get_segment_manager_base()const
{ return detail::get_pointer(mp_segment_mngr_base); }
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
//If there are no free nodes we allocate a new block
if (m_freelist.empty())
priv_alloc_block();
//We take the first free node
node_t *n = &m_freelist.front();
m_freelist.pop_front();
++m_allocated;
return n;
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *ptr)
{
//We put the node at the beginning of the free node list
node_t * to_deallocate = static_cast<node_t*>(ptr);
m_freelist.push_front(*to_deallocate);
assert(m_allocated>0);
--m_allocated;
}
//!Allocates a singly linked list of n nodes ending in null pointer
//!can throw boost::interprocess::bad_alloc
multiallocation_chain allocate_nodes(const std::size_t n)
{
multiallocation_chain nodes;
std::size_t i = 0;
try{
for(; i < n; ++i){
nodes.push_front(this->allocate_node());
}
}
catch(...){
this->deallocate_nodes(nodes, i);
throw;
}
return boost::interprocess::move(nodes);
}
//!Deallocates the first n nodes of a linked list of nodes. Never throws
void deallocate_nodes(multiallocation_chain &nodes, std::size_t n)
{
for(std::size_t i = 0; i < n; ++i){
void *p = detail::get_pointer(nodes.front());
assert(p);
nodes.pop_front();
this->deallocate_node(p);
}
}
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
void deallocate_nodes(multiallocation_chain chain)
{
while(!chain.empty()){
void *addr = detail::get_pointer(chain.front());
chain.pop_front();
deallocate_node(addr);
}
}
//!Deallocates all the free blocks of memory. Never throws
void deallocate_free_blocks()
{
typedef typename free_nodes_t::iterator nodelist_iterator;
typename blockslist_t::iterator bit(m_blocklist.before_begin()),
it(m_blocklist.begin()),
itend(m_blocklist.end());
free_nodes_t backup_list;
nodelist_iterator backup_list_last = backup_list.before_begin();
//Execute the algorithm and get an iterator to the last value
std::size_t blocksize = detail::get_rounded_size
(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
while(it != itend){
//Collect all the nodes from the block pointed by it
//and push them in the list
free_nodes_t free_nodes;
nodelist_iterator last_it = free_nodes.before_begin();
const void *addr = get_block_from_hook(&*it, blocksize);
m_freelist.remove_and_dispose_if
(is_between(addr, blocksize), push_in_list(free_nodes, last_it));
//If the number of nodes is equal to m_nodes_per_block
//this means that the block can be deallocated
if(free_nodes.size() == m_nodes_per_block){
//Unlink the nodes
free_nodes.clear();
it = m_blocklist.erase_after(bit);
mp_segment_mngr_base->deallocate((void*)addr);
}
//Otherwise, insert them in the backup list, since the
//next "remove_if" does not need to check them again.
else{
//Assign the iterator to the last value if necessary
if(backup_list.empty() && !m_freelist.empty()){
backup_list_last = last_it;
}
//Transfer nodes. This is constant time.
backup_list.splice_after
( backup_list.before_begin()
, free_nodes
, free_nodes.before_begin()
, last_it
, free_nodes.size());
bit = it;
++it;
}
}
//We should have removed all the nodes from the free list
assert(m_freelist.empty());
//Now pass all the node to the free list again
m_freelist.splice_after
( m_freelist.before_begin()
, backup_list
, backup_list.before_begin()
, backup_list_last
, backup_list.size());
}
std::size_t num_free_nodes()
{ return m_freelist.size(); }
//!Deallocates all used memory. Precondition: all nodes allocated from this pool should
//!already be deallocated. Otherwise, undefined behaviour. Never throws
void purge_blocks()
{
//check for memory leaks
assert(m_allocated==0);
std::size_t blocksize = detail::get_rounded_size
(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
typename blockslist_t::iterator
it(m_blocklist.begin()), itend(m_blocklist.end()), aux;
//We iterate though the NodeBlock list to free the memory
while(!m_blocklist.empty()){
void *addr = get_block_from_hook(&m_blocklist.front(), blocksize);
m_blocklist.pop_front();
mp_segment_mngr_base->deallocate((void*)addr);
}
//Just clear free node list
m_freelist.clear();
}
void swap(private_node_pool_impl &other)
{
std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base);
m_blocklist.swap(other.m_blocklist);
m_freelist.swap(other.m_freelist);
std::swap(m_allocated, other.m_allocated);
}
private:
struct push_in_list
{
push_in_list(free_nodes_t &l, typename free_nodes_t::iterator &it)
: slist_(l), last_it_(it)
{}
void operator()(typename free_nodes_t::pointer p) const
{
slist_.push_front(*p);
if(slist_.size() == 1){ //Cache last element
++last_it_ = slist_.begin();
}
}
private:
free_nodes_t &slist_;
typename free_nodes_t::iterator &last_it_;
};
struct is_between
: std::unary_function<typename free_nodes_t::value_type, bool>
{
is_between(const void *addr, std::size_t size)
: beg_(static_cast<const char *>(addr)), end_(beg_+size)
{}
bool operator()(typename free_nodes_t::const_reference v) const
{
return (beg_ <= reinterpret_cast<const char *>(&v) &&
end_ > reinterpret_cast<const char *>(&v));
}
private:
const char * beg_;
const char * end_;
};
//!Allocates a block of nodes. Can throw boost::interprocess::bad_alloc
void priv_alloc_block()
{
//We allocate a new NodeBlock and put it as first
//element in the free Node list
std::size_t blocksize =
detail::get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of<node_t>::value);
char *pNode = reinterpret_cast<char*>
(mp_segment_mngr_base->allocate(blocksize + sizeof(node_t)));
if(!pNode) throw bad_alloc();
char *pBlock = pNode;
m_blocklist.push_front(get_block_hook(pBlock, blocksize));
//We initialize all Nodes in Node Block to insert
//them in the free Node list
for(std::size_t i = 0; i < m_nodes_per_block; ++i, pNode += m_real_node_size){
m_freelist.push_front(*new (pNode) node_t);
}
}
//!Deprecated, use deallocate_free_blocks
void deallocate_free_chunks()
{ this->deallocate_free_blocks(); }
//!Deprecated, use purge_blocks
void purge_chunks()
{ this->purge_blocks(); }
private:
//!Returns a reference to the block hook placed in the end of the block
static inline node_t & get_block_hook (void *block, std::size_t blocksize)
{
return *reinterpret_cast<node_t*>(reinterpret_cast<char*>(block) + blocksize);
}
//!Returns the starting address of the block reference to the block hook placed in the end of the block
inline void *get_block_from_hook (node_t *hook, std::size_t blocksize)
{
return (reinterpret_cast<char*>(hook) - blocksize);
}
private:
typedef typename boost::pointer_to_other
<void_pointer, segment_manager_base_type>::type segment_mngr_base_ptr_t;
const std::size_t m_nodes_per_block;
const std::size_t m_real_node_size;
segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager
blockslist_t m_blocklist; //Intrusive container of blocks
free_nodes_t m_freelist; //Intrusive container of free nods
std::size_t m_allocated; //Used nodes for debugging
};
//!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 block (NodesPerBlock) are known at compile time
template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerBlock >
class private_node_pool
//Inherit from the implementation to avoid template bloat
: public private_node_pool_impl<typename SegmentManager::segment_manager_base_type>
{
typedef private_node_pool_impl<typename SegmentManager::segment_manager_base_type> base_t;
//Non-copyable
private_node_pool();
private_node_pool(const private_node_pool &);
private_node_pool &operator=(const private_node_pool &);
public:
typedef SegmentManager segment_manager;
static const std::size_t nodes_per_block = NodesPerBlock;
//Deprecated, use nodes_per_block
static const std::size_t nodes_per_chunk = NodesPerBlock;
//!Constructor from a segment manager. Never throws
private_node_pool(segment_manager *segment_mngr)
: base_t(segment_mngr, NodeSize, NodesPerBlock)
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager() const
{ return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }
};
//!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 block (NodesPerBlock) are known at compile time
//!Pooled shared memory allocator using adaptive pool. 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 block (NodesPerBlock) are known at compile time
template< class SegmentManager
, std::size_t NodeSize
, std::size_t NodesPerBlock
>
class shared_node_pool
: public detail::shared_pool_impl
< private_node_pool
<SegmentManager, NodeSize, NodesPerBlock>
>
{
typedef detail::shared_pool_impl
< private_node_pool
<SegmentManager, NodeSize, NodesPerBlock>
> base_t;
public:
shared_node_pool(SegmentManager *segment_mgnr)
: base_t(segment_mgnr)
{}
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_POOL_HPP

View File

@@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_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/intrusive/slist.hpp>
namespace boost {
namespace interprocess {
namespace detail {
template<class VoidPointer>
struct node_slist
{
//This hook will be used to chain the individual nodes
typedef typename bi::make_slist_base_hook
<bi::void_pointer<VoidPointer>, bi::link_mode<bi::normal_link> >::type slist_hook_t;
//A node object will hold node_t when it's not allocated
struct node_t
: public slist_hook_t
{};
typedef typename bi::make_slist
<node_t, bi::linear<true>, bi::base_hook<slist_hook_t> >::type node_slist_t;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_TOOLS_HPP

View File

@@ -0,0 +1,449 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes node_allocator pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail{
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class node_allocator_base
: public node_pool_allocation_impl
< node_allocator_base
< Version, T, SegmentManager, NodesPerBlock>
, Version
, T
, SegmentManager
>
{
public:
typedef typename SegmentManager::void_pointer void_pointer;
typedef SegmentManager segment_manager;
typedef node_allocator_base
<Version, T, SegmentManager, NodesPerBlock> self_t;
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::shared_node_pool
< SegmentManager, sizeof_value<T>::value, NodesPerBlock> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
/// @endcond
BOOST_STATIC_ASSERT((Version <=2));
public:
//-------
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type<node_allocator_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator_base from
//!node_allocator_base
template<class T2>
struct rebind
{
typedef node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> other;
};
/// @cond
private:
//!Not assignable from related node_allocator_base
template<unsigned int Version2, class T2, class SegmentManager2, std::size_t N2>
node_allocator_base& operator=
(const node_allocator_base<Version2, T2, SegmentManager2, N2>&);
//!Not assignable from other node_allocator_base
//node_allocator_base& operator=(const node_allocator_base&);
/// @endcond
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_base(segment_manager *segment_mngr)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(segment_mngr)) { }
//!Copy constructor from other node_allocator_base. Increments the reference
//!count of the associated node pool. Never throws
node_allocator_base(const node_allocator_base &other)
: mp_node_pool(other.get_node_pool())
{
node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count();
}
//!Copy constructor from related node_allocator_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
node_allocator_base
(const node_allocator_base<Version, T2, SegmentManager, NodesPerBlock> &other)
: mp_node_pool(detail::get_or_create_node_pool<typename node_pool<0>::type>(other.get_segment_manager())) { }
//!Assignment from other node_allocator_base
node_allocator_base& operator=(const node_allocator_base &other)
{
node_allocator_base c(other);
swap(*this, c);
return *this;
}
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~node_allocator_base()
{ detail::destroy_node_pool_if_last_link(node_pool<0>::get(detail::get_pointer(mp_node_pool))); }
//!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
{ return node_pool<0>::get(detail::get_pointer(mp_node_pool))->get_segment_manager(); }
//!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)
{ detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); }
/// @cond
private:
void_pointer mp_node_pool;
/// @endcond
};
//!Equality test for same type
//!of node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator==(const node_allocator_base<V, T, S, NPC> &alloc1,
const node_allocator_base<V, T, S, NPC> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type
//!of node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator!=(const node_allocator_base<V, T, S, NPC> &alloc1,
const node_allocator_base<V, T, S, NPC> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class node_allocator_v1
: public node_allocator_base
< 1
, T
, SegmentManager
, NodesPerBlock
>
{
public:
typedef detail::node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
template<class T2>
struct rebind
{
typedef node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
};
node_allocator_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
node_allocator_v1
(const node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace detail{
/// @endcond
//!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. NodesPerBlock is the number of nodes allocated at once when the allocator
//!needs runs out of nodes
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class node_allocator
/// @cond
: public detail::node_allocator_base
< 2
, T
, SegmentManager
, NodesPerBlock
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::node_allocator_base
< 2, T, SegmentManager, NodesPerBlock> base_t;
public:
typedef boost::interprocess::version_type<node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
node_allocator(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else //BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains node_allocator from
//!node_allocator
template<class T2>
struct rebind
{
typedef node_allocator<T2, SegmentManager, NodesPerBlock> other;
};
private:
//!Not assignable from
//!related node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
node_allocator& operator=
(const node_allocator<T2, SegmentManager2, N2>&);
//!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);
//!Copy constructor from other node_allocator. Increments the reference
//!count of the associated node pool. Never throws
node_allocator(const node_allocator &other);
//!Copy constructor from related node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
void* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!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);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!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);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!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();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!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);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator==(const node_allocator<T, S, NPC> &alloc1,
const node_allocator<T, S, NPC> &alloc2);
//!Inequality test for same type
//!of node_allocator
template<class T, class S, std::size_t NPC> inline
bool operator!=(const node_allocator<T, S, NPC> &alloc1,
const node_allocator<T, S, NPC> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,465 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_PRIVATE_ADAPTIVE_POOL_HPP
#define BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_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/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/allocators/detail/adaptive_node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_pool_base
: public node_pool_allocation_impl
< private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock
, MaxFreeBlocks, OverheadPercent>
, Version
, T
, SegmentManager
>
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
typedef private_adaptive_pool_base
< Version, T, SegmentManager, NodesPerBlock
, MaxFreeBlocks, OverheadPercent> self_t;
typedef detail::private_adaptive_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
> node_pool_t;
BOOST_STATIC_ASSERT((Version <=2));
/// @endcond
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type
<private_adaptive_pool_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator from other node_allocator
template<class T2>
struct rebind
{
typedef private_adaptive_pool_base
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::private_adaptive_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
private:
//!Not assignable from related private_adaptive_pool_base
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2, std::size_t F2, unsigned char OP2>
private_adaptive_pool_base& operator=
(const private_adaptive_pool_base<Version2, T2, MemoryAlgorithm2, N2, F2, OP2>&);
//!Not assignable from other private_adaptive_pool_base
private_adaptive_pool_base& operator=(const private_adaptive_pool_base&);
/// @endcond
public:
//!Constructor from a segment manager
private_adaptive_pool_base(segment_manager *segment_mngr)
: m_node_pool(segment_mngr)
{}
//!Copy constructor from other private_adaptive_pool_base. Never throws
private_adaptive_pool_base(const private_adaptive_pool_base &other)
: m_node_pool(other.get_segment_manager())
{}
//!Copy constructor from related private_adaptive_pool_base. Never throws.
template<class T2>
private_adaptive_pool_base
(const private_adaptive_pool_base
<Version, T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: m_node_pool(other.get_segment_manager())
{}
//!Destructor, frees all used memory. Never throws
~private_adaptive_pool_base()
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
{ return m_node_pool.get_segment_manager(); }
//!Returns the internal node pool. Never throws
node_pool_t* get_node_pool() const
{ return const_cast<node_pool_t*>(&m_node_pool); }
//!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)
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
/// @cond
private:
node_pool_t m_node_pool;
/// @endcond
};
//!Equality test for same type of private_adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
{ return &alloc1 == &alloc2; }
//!Inequality test for same type of private_adaptive_pool_base
template<unsigned int V, class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool_base<V, T, S, NodesPerBlock, F, OP> &alloc2)
{ return &alloc1 != &alloc2; }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class private_adaptive_pool_v1
: public private_adaptive_pool_base
< 1
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
{
public:
typedef detail::private_adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
template<class T2>
struct rebind
{
typedef private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private_adaptive_pool_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_adaptive_pool_v1
(const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
};
} //namespace detail {
/// @endcond
//!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.
//!
//!NodesPerBlock is the minimum number of nodes of nodes allocated at once when
//!the allocator needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks
//!that the adaptive node pool will hold. The rest of the totally free blocks will be
//!deallocated with the segment manager.
//!
//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator:
//!(memory usable for nodes / total memory allocated from the segment manager)
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
, std::size_t MaxFreeBlocks
, unsigned char OverheadPercent
>
class private_adaptive_pool
/// @cond
: public detail::private_adaptive_pool_base
< 2
, T
, SegmentManager
, NodesPerBlock
, MaxFreeBlocks
, OverheadPercent
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::private_adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
template<class T2>
struct rebind
{
typedef private_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private_adaptive_pool(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains private_adaptive_pool from
//!private_adaptive_pool
template<class T2>
struct rebind
{
typedef private_adaptive_pool
<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> other;
};
private:
//!Not assignable from
//!related private_adaptive_pool
template<class T2, class SegmentManager2, std::size_t N2, std::size_t F2, unsigned char OP2>
private_adaptive_pool& operator=
(const private_adaptive_pool<T2, SegmentManager2, N2, F2>&);
//!Not assignable from
//!other private_adaptive_pool
private_adaptive_pool& operator=(const private_adaptive_pool&);
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
private_adaptive_pool(segment_manager *segment_mngr);
//!Copy constructor from other private_adaptive_pool. Increments the reference
//!count of the associated node pool. Never throws
private_adaptive_pool(const private_adaptive_pool &other);
//!Copy constructor from related private_adaptive_pool. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~private_adaptive_pool();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!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);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!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);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!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();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!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);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of private_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of private_adaptive_pool
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc1,
const private_adaptive_pool<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_ADAPTIVE_POOL_HPP

View File

@@ -0,0 +1,441 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_PRIVATE_NODE_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/pointer_to_other.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/allocators/detail/node_pool.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <memory>
#include <algorithm>
#include <cstddef>
//!\file
//!Describes private_node_allocator_base pooled shared memory STL compatible allocator
namespace boost {
namespace interprocess {
/// @cond
namespace detail {
template < unsigned int Version
, class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class private_node_allocator_base
: public node_pool_allocation_impl
< private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock>
, Version
, T
, SegmentManager
>
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
/// @cond
private:
typedef private_node_allocator_base
< Version, T, SegmentManager, NodesPerBlock> self_t;
typedef detail::private_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
> node_pool_t;
BOOST_STATIC_ASSERT((Version <=2));
/// @endcond
public:
typedef typename boost::
pointer_to_other<void_pointer, T>::type pointer;
typedef typename boost::
pointer_to_other<void_pointer, const T>::type const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::interprocess::version_type
<private_node_allocator_base, Version> version;
typedef detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
//!Obtains node_allocator from other node_allocator
template<class T2>
struct rebind
{
typedef private_node_allocator_base
<Version, T2, SegmentManager, NodesPerBlock> other;
};
/// @cond
template <int dummy>
struct node_pool
{
typedef detail::private_node_pool
<SegmentManager
, sizeof_value<T>::value
, NodesPerBlock
> type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
private:
//!Not assignable from related private_node_allocator_base
template<unsigned int Version2, class T2, class MemoryAlgorithm2, std::size_t N2>
private_node_allocator_base& operator=
(const private_node_allocator_base<Version2, T2, MemoryAlgorithm2, N2>&);
//!Not assignable from other private_node_allocator_base
private_node_allocator_base& operator=(const private_node_allocator_base&);
/// @endcond
public:
//!Constructor from a segment manager
private_node_allocator_base(segment_manager *segment_mngr)
: m_node_pool(segment_mngr)
{}
//!Copy constructor from other private_node_allocator_base. Never throws
private_node_allocator_base(const private_node_allocator_base &other)
: m_node_pool(other.get_segment_manager())
{}
//!Copy constructor from related private_node_allocator_base. Never throws.
template<class T2>
private_node_allocator_base
(const private_node_allocator_base
<Version, T2, SegmentManager, NodesPerBlock> &other)
: m_node_pool(other.get_segment_manager())
{}
//!Destructor, frees all used memory. Never throws
~private_node_allocator_base()
{}
//!Returns the segment manager. Never throws
segment_manager* get_segment_manager()const
{ return m_node_pool.get_segment_manager(); }
//!Returns the internal node pool. Never throws
node_pool_t* get_node_pool() const
{ return const_cast<node_pool_t*>(&m_node_pool); }
//!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)
{ alloc1.m_node_pool.swap(alloc2.m_node_pool); }
/// @cond
private:
node_pool_t m_node_pool;
/// @endcond
};
//!Equality test for same type of private_node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator==(const private_node_allocator_base<V, T, S, NPC> &alloc1,
const private_node_allocator_base<V, T, S, NPC> &alloc2)
{ return &alloc1 == &alloc2; }
//!Inequality test for same type of private_node_allocator_base
template<unsigned int V, class T, class S, std::size_t NPC> inline
bool operator!=(const private_node_allocator_base<V, T, S, NPC> &alloc1,
const private_node_allocator_base<V, T, S, NPC> &alloc2)
{ return &alloc1 != &alloc2; }
template < class T
, class SegmentManager
, std::size_t NodesPerBlock = 64
>
class private_node_allocator_v1
: public private_node_allocator_base
< 1
, T
, SegmentManager
, NodesPerBlock
>
{
public:
typedef detail::private_node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
template<class T2>
struct rebind
{
typedef private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> other;
};
private_node_allocator_v1(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_node_allocator_v1
(const private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
};
} //namespace detail {
/// @endcond
//!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. NodesPerBlock is the number of nodes allocated
//!at once when the allocator needs runs out of nodes
template < class T
, class SegmentManager
, std::size_t NodesPerBlock
>
class private_node_allocator
/// @cond
: public detail::private_node_allocator_base
< 2
, T
, SegmentManager
, NodesPerBlock
>
/// @endcond
{
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typedef detail::private_node_allocator_base
< 2, T, SegmentManager, NodesPerBlock> base_t;
public:
typedef boost::interprocess::version_type<private_node_allocator, 2> version;
template<class T2>
struct rebind
{
typedef private_node_allocator
<T2, SegmentManager, NodesPerBlock> other;
};
private_node_allocator(SegmentManager *segment_mngr)
: base_t(segment_mngr)
{}
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
: base_t(other)
{}
#else
public:
typedef implementation_defined::segment_manager segment_manager;
typedef segment_manager::void_pointer void_pointer;
typedef implementation_defined::pointer pointer;
typedef implementation_defined::const_pointer const_pointer;
typedef T value_type;
typedef typename detail::add_reference
<value_type>::type reference;
typedef typename detail::add_reference
<const value_type>::type const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
//!Obtains private_node_allocator from
//!private_node_allocator
template<class T2>
struct rebind
{
typedef private_node_allocator
<T2, SegmentManager, NodesPerBlock> other;
};
private:
//!Not assignable from
//!related private_node_allocator
template<class T2, class SegmentManager2, std::size_t N2>
private_node_allocator& operator=
(const private_node_allocator<T2, SegmentManager2, N2>&);
//!Not assignable from
//!other private_node_allocator
private_node_allocator& operator=(const private_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
private_node_allocator(segment_manager *segment_mngr);
//!Copy constructor from other private_node_allocator. Increments the reference
//!count of the associated node pool. Never throws
private_node_allocator(const private_node_allocator &other);
//!Copy constructor from related private_node_allocator. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other);
//!Destructor, removes node_pool_t from memory
//!if its reference count reaches to zero. Never throws
~private_node_allocator();
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const;
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const;
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const;
//!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);
//!Deallocate allocated memory.
//!Never throws
void deallocate(const pointer &ptr, size_type count);
//!Deallocates all free blocks
//!of the pool
void deallocate_free_blocks();
//!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);
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const;
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const;
//!Copy construct an object.
//!Throws if T's copy constructor throws
void construct(const pointer &ptr, const_reference v);
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr);
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const;
std::pair<pointer, bool>
allocation_command(boost::interprocess::allocation_type command,
size_type limit_size,
size_type preferred_size,
size_type &received_size, const pointer &reuse = 0);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements);
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements);
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain chain);
//!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();
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
multiallocation_chain allocate_individual(std::size_t num_elements);
//!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);
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain chain);
#endif
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Equality test for same type
//!of private_node_allocator
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator==(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
//!Inequality test for same type
//!of private_node_allocator
template<class T, class S, std::size_t NodesPerBlock, std::size_t F, unsigned char OP> inline
bool operator!=(const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc1,
const private_node_allocator<T, S, NodesPerBlock, F, OP> &alloc2);
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP

View File

@@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_ANONYMOUS_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <cstddef>
#if (!defined(BOOST_INTERPROCESS_WINDOWS))
# include <fcntl.h> //open, O_CREAT, O_*...
# include <sys/mman.h> //mmap
# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
#else
#include <boost/interprocess/windows_shared_memory.hpp>
#endif
//!\file
//!Describes a function that creates anonymous shared memory that can be
//!shared between forked processes
namespace boost {
namespace interprocess {
/// @cond
namespace detail{
class raw_mapped_region_creator
{
public:
static mapped_region
create_posix_mapped_region(void *address, offset_t offset, std::size_t size)
{
mapped_region region;
region.m_base = address;
region.m_offset = offset;
region.m_extra_offset = 0;
region.m_size = size;
return region;
}
};
}
/// @endcond
//!A function that creates an anonymous shared memory segment of size "size".
//!If "address" is passed the function will try to map the segment in that address.
//!Otherwise the operating system will choose the mapping address.
//!The function returns a mapped_region holding that segment or throws
//!interprocess_exception if the function fails.
//static mapped_region
static mapped_region
anonymous_shared_memory(std::size_t size, void *address = 0)
#if (!defined(BOOST_INTERPROCESS_WINDOWS))
{
int flags;
int fd = -1;
#if defined(MAP_ANONYMOUS) //Use MAP_ANONYMOUS
flags = MAP_ANONYMOUS | MAP_SHARED;
#elif !defined(MAP_ANONYMOUS) && defined(MAP_ANON) //use MAP_ANON
flags = MAP_ANON | MAP_SHARED;
#else // Use "/dev/zero"
fd = open("/dev/zero", O_RDWR);
flags = MAP_SHARED;
if(fd == -1){
error_info err = system_error_code();
throw interprocess_exception(err);
}
#endif
address = mmap( address
, size
, PROT_READ|PROT_WRITE
, flags
, fd
, 0);
if(address == MAP_FAILED){
if(fd != -1)
close(fd);
error_info err = system_error_code();
throw interprocess_exception(err);
}
if(fd != -1)
close(fd);
return detail::raw_mapped_region_creator::create_posix_mapped_region(address, 0, size);
}
#else
{
windows_shared_memory anonymous_mapping(create_only, 0, read_write, size);
return mapped_region(anonymous_mapping, read_write, 0, size, address);
}
#endif
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP

View File

@@ -0,0 +1,40 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/allocation_type.hpp>
namespace boost {
namespace interprocess {
/// @cond
typedef int allocation_type;
/// @endcond
static const allocation_type allocate_new = boost::interprocess_container::allocate_new;
static const allocation_type expand_fwd = boost::interprocess_container::expand_fwd;
static const allocation_type expand_bwd = boost::interprocess_container::expand_bwd;
static const allocation_type shrink_in_place = boost::interprocess_container::shrink_in_place;
static const allocation_type try_shrink_in_place= boost::interprocess_container::try_shrink_in_place;
static const allocation_type nothrow_allocation = boost::interprocess_container::nothrow_allocation;
static const allocation_type zero_memory = boost::interprocess_container::zero_memory;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP

View File

@@ -0,0 +1,153 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP
#define BOOST_CONTAINERS_CONTAINERS_FWD_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
/// @cond
namespace boost{
namespace intrusive{
//Create namespace to avoid compilation errors
}}
namespace boost{ namespace interprocess_container{ namespace containers_detail{
namespace bi = boost::intrusive;
}}}
namespace std {
template <class T>
class allocator;
template <class T>
struct less;
template <class T1, class T2>
struct pair;
template <class CharType>
struct char_traits;
} //namespace std {
/// @endcond
//////////////////////////////////////////////////////////////////////////////
// Containers
//////////////////////////////////////////////////////////////////////////////
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
namespace boost {
namespace interprocess {
#else
namespace boost {
namespace interprocess_container {
#endif
//vector class
template <class T
,class A = std::allocator<T> >
class vector;
//vector class
template <class T
,class A = std::allocator<T> >
class deque;
//list class
template <class T
,class A = std::allocator<T> >
class list;
//slist class
template <class T
,class Alloc = std::allocator<T> >
class slist;
//set class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class set;
//multiset class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class multiset;
//map class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<const Key, T> > >
class map;
//multimap class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<const Key, T> > >
class multimap;
//flat_set class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class flat_set;
//flat_multiset class
template <class T
,class Pred = std::less<T>
,class Alloc = std::allocator<T> >
class flat_multiset;
//flat_map class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<Key, T> > >
class flat_map;
//flat_multimap class
template <class Key
,class T
,class Pred = std::less<Key>
,class Alloc = std::allocator<std::pair<Key, T> > >
class flat_multimap;
//basic_string class
template <class CharT
,class Traits = std::char_traits<CharT>
,class Alloc = std::allocator<CharT> >
class basic_string;
//string class
typedef basic_string
<char
,std::char_traits<char>
,std::allocator<char> >
string;
}} //namespace boost { namespace interprocess_container {
#endif //#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,386 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP
#define BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <iterator> //std::iterator_traits
#include <algorithm> //std::copy, std::uninitialized_copy
#include <new> //placement new
#include <cassert>
namespace boost { namespace interprocess_container { namespace containers_detail {
//This class will be interface for operations dependent on FwdIt types used advanced_insert_aux_impl
template<class T, class Iterator>
struct advanced_insert_aux_int
{
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
virtual void copy_all_to(Iterator p) = 0;
virtual void uninitialized_copy_all_to(Iterator p) = 0;
virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first) = 0;
virtual void copy_some_and_update(Iterator pos, difference_type division_count, bool first) = 0;
virtual ~advanced_insert_aux_int() {}
};
//This class template will adapt each FwIt types to advanced_insert_aux_int
template<class T, class FwdIt, class Iterator>
struct advanced_insert_aux_proxy
: public advanced_insert_aux_int<T, Iterator>
{
typedef typename advanced_insert_aux_int<T, Iterator>::difference_type difference_type;
advanced_insert_aux_proxy(FwdIt first, FwdIt last)
: first_(first), last_(last)
{}
virtual ~advanced_insert_aux_proxy()
{}
virtual void copy_all_to(Iterator p)
{ std::copy(first_, last_, p); }
virtual void uninitialized_copy_all_to(Iterator p)
{ boost::interprocess::uninitialized_copy_or_move(first_, last_, p); }
virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n)
{
FwdIt mid = first_;
std::advance(mid, division_count);
if(first_n){
boost::interprocess::uninitialized_copy_or_move(first_, mid, pos);
first_ = mid;
}
else{
boost::interprocess::uninitialized_copy_or_move(mid, last_, pos);
last_ = mid;
}
}
virtual void copy_some_and_update(Iterator pos, difference_type division_count, bool first_n)
{
FwdIt mid = first_;
std::advance(mid, division_count);
if(first_n){
std::copy(first_, mid, pos);
first_ = mid;
}
else{
std::copy(mid, last_, pos);
last_ = mid;
}
}
FwdIt first_, last_;
};
//This class template will adapt each FwIt types to advanced_insert_aux_int
template<class T, class Iterator, class SizeType>
struct default_construct_aux_proxy
: public advanced_insert_aux_int<T, Iterator>
{
typedef typename advanced_insert_aux_int<T, Iterator>::difference_type difference_type;
default_construct_aux_proxy(SizeType count)
: count_(count)
{}
void uninitialized_copy_impl(Iterator p, const SizeType n)
{
assert(n <= count_);
Iterator orig_p = p;
SizeType i = 0;
try{
for(; i < n; ++i, ++p){
new(containers_detail::get_pointer(&*p))T();
}
}
catch(...){
while(i--){
containers_detail::get_pointer(&*orig_p++)->~T();
}
throw;
}
count_ -= n;
}
virtual ~default_construct_aux_proxy()
{}
virtual void copy_all_to(Iterator)
{ //This should never be called with any count
assert(count_ == 0);
}
virtual void uninitialized_copy_all_to(Iterator p)
{ this->uninitialized_copy_impl(p, count_); }
virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n)
{
SizeType new_count;
if(first_n){
new_count = division_count;
}
else{
assert(difference_type(count_)>= division_count);
new_count = count_ - division_count;
}
this->uninitialized_copy_impl(pos, new_count);
}
virtual void copy_some_and_update(Iterator , difference_type division_count, bool first_n)
{
assert(count_ == 0);
SizeType new_count;
if(first_n){
new_count = division_count;
}
else{
assert(difference_type(count_)>= division_count);
new_count = count_ - division_count;
}
//This function should never called with a count different to zero
assert(new_count == 0);
(void)new_count;
}
SizeType count_;
};
}}} //namespace boost { namespace interprocess_container { namespace containers_detail {
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
#include <boost/interprocess/containers/container/detail/variadic_templates_tools.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <typeinfo>
//#include <iostream> //For debugging purposes
namespace boost {
namespace interprocess_container {
namespace containers_detail {
//This class template will adapt each FwIt types to advanced_insert_aux_int
template<class T, class Iterator, class ...Args>
struct advanced_insert_aux_emplace
: public advanced_insert_aux_int<T, Iterator>
{
typedef typename advanced_insert_aux_int<T, Iterator>::difference_type difference_type;
typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t;
advanced_insert_aux_emplace(Args&&... args)
: args_(args...), used_(false)
{}
~advanced_insert_aux_emplace()
{}
virtual void copy_all_to(Iterator p)
{ this->priv_copy_all_to(index_tuple_t(), p); }
virtual void uninitialized_copy_all_to(Iterator p)
{ this->priv_uninitialized_copy_all_to(index_tuple_t(), p); }
virtual void uninitialized_copy_some_and_update(Iterator p, difference_type division_count, bool first_n)
{ this->priv_uninitialized_copy_some_and_update(index_tuple_t(), p, division_count, first_n); }
virtual void copy_some_and_update(Iterator p, difference_type division_count, bool first_n)
{ this->priv_copy_some_and_update(index_tuple_t(), p, division_count, first_n); }
private:
template<int ...IdxPack>
void priv_copy_all_to(const index_tuple<IdxPack...>&, Iterator p)
{
if(!used_){
T object(boost::interprocess::forward<Args>(get<IdxPack>(args_))...);
*p = boost::interprocess::move(object);
used_ = true;
}
}
template<int ...IdxPack>
void priv_uninitialized_copy_all_to(const index_tuple<IdxPack...>&, Iterator p)
{
if(!used_){
new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward<Args>(get<IdxPack>(args_))...);
used_ = true;
}
}
template<int ...IdxPack>
void priv_uninitialized_copy_some_and_update(const index_tuple<IdxPack...>&, Iterator p, difference_type division_count, bool first_n)
{
assert(division_count <=1);
if((first_n && division_count == 1) || (!first_n && division_count == 0)){
if(!used_){
new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward<Args>(get<IdxPack>(args_))...);
used_ = true;
}
}
}
template<int ...IdxPack>
void priv_copy_some_and_update(const index_tuple<IdxPack...>&, Iterator p, difference_type division_count, bool first_n)
{
assert(division_count <=1);
if((first_n && division_count == 1) || (!first_n && division_count == 0)){
if(!used_){
T object(boost::interprocess::forward<Args>(get<IdxPack>(args_))...);
*p = boost::interprocess::move(object);
used_ = true;
}
}
}
tuple<Args&&...> args_;
bool used_;
};
}}} //namespace boost { namespace interprocess_container { namespace containers_detail {
#else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
#include <boost/interprocess/containers/container/detail/preprocessor.hpp>
#include <boost/interprocess/containers/container/detail/value_init.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
//This class template will adapt each FwIt types to advanced_insert_aux_int
template<class T, class Iterator>
struct advanced_insert_aux_emplace
: public advanced_insert_aux_int<T, Iterator>
{
typedef typename advanced_insert_aux_int<T, Iterator>::difference_type difference_type;
advanced_insert_aux_emplace()
: used_(false)
{}
~advanced_insert_aux_emplace()
{}
virtual void copy_all_to(Iterator p)
{
if(!used_){
value_init<T>v;
*p = boost::interprocess::move(v.m_t);
used_ = true;
}
}
virtual void uninitialized_copy_all_to(Iterator p)
{
if(!used_){
new(containers_detail::get_pointer(&*p))T();
used_ = true;
}
}
virtual void uninitialized_copy_some_and_update(Iterator p, difference_type division_count, bool first_n)
{
assert(division_count <=1);
if((first_n && division_count == 1) || (!first_n && division_count == 0)){
if(!used_){
new(containers_detail::get_pointer(&*p))T();
used_ = true;
}
}
}
virtual void copy_some_and_update(Iterator p, difference_type division_count, bool first_n)
{
assert(division_count <=1);
if((first_n && division_count == 1) || (!first_n && division_count == 0)){
if(!used_){
value_init<T>v;
*p = boost::interprocess::move(v.m_t);
used_ = true;
}
}
}
private:
bool used_;
};
#define BOOST_PP_LOCAL_MACRO(n) \
template<class T, class Iterator, BOOST_PP_ENUM_PARAMS(n, class P) > \
struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
: public advanced_insert_aux_int<T, Iterator> \
{ \
typedef typename advanced_insert_aux_int<T, Iterator>::difference_type difference_type; \
\
BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \
: used_(false), BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \
\
virtual void copy_all_to(Iterator p) \
{ \
if(!used_){ \
T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \
*p = boost::interprocess::move(v); \
used_ = true; \
} \
} \
\
virtual void uninitialized_copy_all_to(Iterator p) \
{ \
if(!used_){ \
new(containers_detail::get_pointer(&*p))T \
(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \
used_ = true; \
} \
} \
\
virtual void uninitialized_copy_some_and_update \
(Iterator p, difference_type division_count, bool first_n) \
{ \
assert(division_count <=1); \
if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \
if(!used_){ \
new(containers_detail::get_pointer(&*p))T \
(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \
used_ = true; \
} \
} \
} \
\
virtual void copy_some_and_update \
(Iterator p, difference_type division_count, bool first_n) \
{ \
assert(division_count <=1); \
if((first_n && division_count == 1) || (!first_n && division_count == 0)){ \
if(!used_){ \
T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \
*p = boost::interprocess::move(v); \
used_ = true; \
} \
} \
} \
\
bool used_; \
BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \
}; \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
}}} //namespace boost { namespace interprocess_container { namespace containers_detail {
#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP

View File

@@ -0,0 +1,215 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP
#define BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/type_traits/has_trivial_copy.hpp>
#include <boost/type_traits/has_trivial_assign.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/get_pointer.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
#include <boost/interprocess/containers/container/detail/mpl.hpp>
#include <boost/interprocess/containers/container/detail/iterators.hpp>
#include <cstring>
namespace boost {
namespace interprocess_container {
#if !defined(BOOST_HAS_RVALUE_REFS)
template<class T>
struct has_own_construct_from_it
{
static const bool value = false;
};
namespace containers_detail {
template<class T, class InpIt>
inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::true_)
{
T::construct(dest, *source);
}
template<class T, class InpIt>
inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::false_)
{
new((void*)dest)T(*source);
}
} //namespace containers_detail {
template<class T, class InpIt>
inline void construct_in_place(T* dest, InpIt source)
{
typedef containers_detail::bool_<has_own_construct_from_it<T>::value> boolean_t;
containers_detail::construct_in_place_impl(dest, source, boolean_t());
}
#else
template<class T, class InpIt>
inline void construct_in_place(T* dest, InpIt source)
{ ::new((void*)dest)T(*source); }
#endif
template<class T, class U, class D>
inline void construct_in_place(T *dest, default_construct_iterator<U, D>)
{
::new((void*)dest)T();
}
template<class T, class U, class E>
inline void construct_in_place(T *dest, emplace_iterator<U, E> ei)
{
ei.construct_in_place(dest);
}
template<class InIt, class OutIt>
struct optimize_assign
{
static const bool value = false;
};
template<class T>
struct optimize_assign<const T*, T*>
{
static const bool value = boost::has_trivial_assign<T>::value;
};
template<class T>
struct optimize_assign<T*, T*>
: public optimize_assign<const T*, T*>
{};
template<class InIt, class OutIt>
struct optimize_copy
{
static const bool value = false;
};
template<class T>
struct optimize_copy<const T*, T*>
{
static const bool value = boost::has_trivial_copy<T>::value;
};
template<class T>
struct optimize_copy<T*, T*>
: public optimize_copy<const T*, T*>
{};
template<class InIt, class OutIt> inline
OutIt copy_n_dispatch(InIt first, typename std::iterator_traits<InIt>::difference_type length, OutIt dest, containers_detail::bool_<false>)
{
for (; length--; ++dest, ++first)
*dest = *first;
return dest;
}
template<class T> inline
T *copy_n_dispatch(const T *first, typename std::iterator_traits<const T*>::difference_type length, T *dest, containers_detail::bool_<true>)
{
std::size_t size = length*sizeof(T);
return (static_cast<T*>(std::memmove(dest, first, size))) + size;
}
template<class InIt, class OutIt> inline
OutIt copy_n(InIt first, typename std::iterator_traits<InIt>::difference_type length, OutIt dest)
{
const bool do_optimized_assign = optimize_assign<InIt, OutIt>::value;
return copy_n_dispatch(first, length, dest, containers_detail::bool_<do_optimized_assign>());
}
template<class InIt, class FwdIt> inline
FwdIt uninitialized_copy_n_dispatch
(InIt first,
typename std::iterator_traits<InIt>::difference_type count,
FwdIt dest, containers_detail::bool_<false>)
{
typedef typename std::iterator_traits<FwdIt>::value_type value_type;
//Save initial destination position
FwdIt dest_init = dest;
typename std::iterator_traits<InIt>::difference_type new_count = count+1;
BOOST_TRY{
//Try to build objects
for (; --new_count; ++dest, ++first){
construct_in_place(containers_detail::get_pointer(&*dest), first);
}
}
BOOST_CATCH(...){
//Call destructors
new_count = count - new_count;
for (; new_count--; ++dest_init){
containers_detail::get_pointer(&*dest_init)->~value_type();
}
BOOST_RETHROW
}
BOOST_CATCH_END
return dest;
}
template<class T> inline
T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits<const T*>::difference_type length, T *dest, containers_detail::bool_<true>)
{
std::size_t size = length*sizeof(T);
return (static_cast<T*>(std::memmove(dest, first, size))) + size;
}
template<class InIt, class FwdIt> inline
FwdIt uninitialized_copy_n
(InIt first,
typename std::iterator_traits<InIt>::difference_type count,
FwdIt dest)
{
const bool do_optimized_copy = optimize_copy<InIt, FwdIt>::value;
return uninitialized_copy_n_dispatch(first, count, dest, containers_detail::bool_<do_optimized_copy>());
}
// uninitialized_copy_copy
// Copies [first1, last1) into [result, result + (last1 - first1)), and
// copies [first2, last2) into
// [result + (last1 - first1), result + (last1 - first1) + (last2 - first2)).
template <class InpIt1, class InpIt2, class FwdIt>
FwdIt uninitialized_copy_copy
(InpIt1 first1, InpIt1 last1, InpIt2 first2, InpIt2 last2, FwdIt result)
{
typedef typename std::iterator_traits<FwdIt>::value_type value_type;
FwdIt mid = std::uninitialized_copy(first1, last1, result);
BOOST_TRY {
return std::uninitialized_copy(first2, last2, mid);
}
BOOST_CATCH(...){
for(;result != mid; ++result){
containers_detail::get_pointer(&*result)->~value_type();
}
BOOST_RETHROW
}
BOOST_CATCH_END
}
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP

View File

@@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_ALLOCATION_TYPE_HPP
#define BOOST_CONTAINERS_ALLOCATION_TYPE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
namespace boost {
namespace interprocess_container {
/// @cond
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,
zero_memory_v = 0x20,
try_shrink_in_place_v = 0x40
};
typedef int allocation_type;
/// @endcond
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 try_shrink_in_place= (allocation_type)try_shrink_in_place_v;
static const allocation_type nothrow_allocation = (allocation_type)nothrow_allocation_v;
static const allocation_type zero_memory = (allocation_type)zero_memory_v;
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //BOOST_CONTAINERS_ALLOCATION_TYPE_HPP

View File

@@ -0,0 +1,47 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED
#define BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED
#include <boost/config.hpp>
#endif
#ifdef BOOST_MSVC
#ifndef _CRT_SECURE_NO_DEPRECATE
#define BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#pragma warning (push)
#pragma warning (disable : 4702) // unreachable code
#pragma warning (disable : 4706) // assignment within conditional expression
#pragma warning (disable : 4127) // conditional expression is constant
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
#pragma warning (disable : 4284) // odd return type for operator->
#pragma warning (disable : 4244) // possible loss of data
#pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2"
#pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data
#pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier"
#pragma warning (disable : 4355) // "this" : used in base member initializer list
#pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated
#pragma warning (disable : 4511) // copy constructor could not be generated
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4514) // unreferenced inline removed
#pragma warning (disable : 4521) // Disable "multiple copy constructors specified"
#pragma warning (disable : 4522) // "class" : multiple assignment operators specified
#pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter
#pragma warning (disable : 4710) // function not inlined
#pragma warning (disable : 4711) // function selected for automatic inline expansion
#pragma warning (disable : 4786) // identifier truncated in debug info
#pragma warning (disable : 4996) // "function": was declared deprecated
#pragma warning (disable : 4197) // top-level volatile in cast is ignored
#pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception'
// with /GR-; unpredictable behavior may result
#pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site
#pragma warning (disable : 4671) // the copy constructor is inaccessible
#endif

View File

@@ -0,0 +1,17 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#if defined BOOST_MSVC
#pragma warning (pop)
#ifdef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE
#undef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE
#undef _CRT_SECURE_NO_DEPRECATE
#endif
#endif

View File

@@ -0,0 +1,154 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DESTROYERS_HPP
#define BOOST_CONTAINERS_DESTROYERS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/interprocess/containers/container/detail/version_type.hpp>
#include <boost/interprocess/containers/container/detail/utilities.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
//!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 = containers_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 containers_detail::integral_constant<unsigned,
boost::interprocess_container::containers_detail::
version<A>::value> alloc_version;
typedef containers_detail::integral_constant<unsigned, 1> allocator_v1;
typedef containers_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)
{
containers_detail::get_pointer(p)->~value_type();
priv_deallocate(p, alloc_version());
}
};
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DESTROYERS_HPP

View File

@@ -0,0 +1,837 @@
////////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
////////////////////////////////////////////////////////////////////////////////
// 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
//
////////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_FLAT_TREE_HPP
#define BOOST_CONTAINERS_FLAT_TREE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <algorithm>
#include <functional>
#include <utility>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/containers/container/detail/utilities.hpp>
#include <boost/interprocess/containers/container/detail/pair.hpp>
#include <boost/interprocess/containers/container/vector.hpp>
#include <boost/interprocess/containers/container/detail/value_init.hpp>
#include <boost/interprocess/containers/container/detail/destroyers.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
class flat_tree
{
typedef boost::interprocess_container::vector<Value, Alloc> vector_t;
typedef Alloc 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:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_tree)
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 allocator_type stored_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 std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// allocation/deallocation
flat_tree(const Compare& comp = Compare(),
const allocator_type& a = allocator_type())
: m_data(comp, a)
{ }
flat_tree(const flat_tree& x)
: m_data(x.m_data, x.m_data.m_vect)
{ }
flat_tree(BOOST_INTERPROCESS_RV_REF(flat_tree) x)
: m_data(boost::interprocess::move(x.m_data))
{ }
~flat_tree()
{ }
flat_tree& operator=(const flat_tree& x)
{ m_data = x.m_data; return *this; }
flat_tree& operator=(BOOST_INTERPROCESS_RV_REF(flat_tree) mx)
{ m_data = boost::interprocess::move(mx.m_data); 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(); }
const stored_allocator_type &get_stored_allocator() const
{ return this->m_data.m_vect.get_stored_allocator(); }
stored_allocator_type &get_stored_allocator()
{ return this->m_data.m_vect.get_stored_allocator(); }
iterator begin()
{ return this->m_data.m_vect.begin(); }
const_iterator begin() const
{ return this->cbegin(); }
const_iterator cbegin() const
{ return this->m_data.m_vect.begin(); }
iterator end()
{ return this->m_data.m_vect.end(); }
const_iterator end() const
{ return this->cend(); }
const_iterator cend() const
{ return this->m_data.m_vect.end(); }
reverse_iterator rbegin()
{ return reverse_iterator(this->end()); }
const_reverse_iterator rbegin() const
{ return this->crbegin(); }
const_reverse_iterator crbegin() const
{ return const_reverse_iterator(this->cend()); }
reverse_iterator rend()
{ return reverse_iterator(this->begin()); }
const_reverse_iterator rend() const
{ return this->crend(); }
const_reverse_iterator crend() const
{ return const_reverse_iterator(this->cbegin()); }
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)
{
value_compare& mycomp = this->m_data;
value_compare& othercomp = other.m_data;
containers_detail::do_swap(mycomp, othercomp);
vector_t & myvect = this->m_data.m_vect;
vector_t & othervect = other.m_data.m_vect;
myvect.swap(othervect);
}
public:
// insert/erase
std::pair<iterator,bool> insert_unique(const value_type& val)
{
insert_commit_data data;
std::pair<iterator,bool> ret = priv_insert_unique_prepare(val, data);
if(ret.second){
ret.first = priv_insert_commit(data, val);
}
return ret;
}
std::pair<iterator,bool> insert_unique(BOOST_INTERPROCESS_RV_REF(value_type) val)
{
insert_commit_data data;
std::pair<iterator,bool> ret = priv_insert_unique_prepare(val, data);
if(ret.second){
ret.first = priv_insert_commit(data, boost::interprocess::move(val));
}
return ret;
}
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_equal(BOOST_INTERPROCESS_RV_REF(value_type) mval)
{
iterator i = this->upper_bound(KeyOfValue()(mval));
i = this->m_data.m_vect.insert(i, boost::interprocess::move(mval));
return i;
}
iterator insert_unique(const_iterator pos, const value_type& val)
{
insert_commit_data data;
std::pair<iterator,bool> ret = priv_insert_unique_prepare(pos, val, data);
if(ret.second){
ret.first = priv_insert_commit(data, val);
}
return ret.first;
}
iterator insert_unique(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval)
{
insert_commit_data data;
std::pair<iterator,bool> ret = priv_insert_unique_prepare(pos, mval, data);
if(ret.second){
ret.first = priv_insert_commit(data, boost::interprocess::move(mval));
}
return ret.first;
}
iterator insert_equal(const_iterator pos, const value_type& val)
{
insert_commit_data data;
priv_insert_equal_prepare(pos, val, data);
return priv_insert_commit(data, val);
}
iterator insert_equal(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval)
{
insert_commit_data data;
priv_insert_equal_prepare(pos, mval, data);
return priv_insert_commit(data, boost::interprocess::move(mval));
}
template <class InIt>
void insert_unique(InIt first, InIt last)
{
for ( ; first != last; ++first)
this->insert_unique(*first);
}
template <class InIt>
void insert_equal(InIt first, InIt last)
{
typedef typename
std::iterator_traits<InIt>::iterator_category ItCat;
priv_insert_equal(first, last, ItCat());
}
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
template <class... Args>
iterator emplace_unique(Args&&... args)
{
value_type val(boost::interprocess::forward<Args>(args)...);
insert_commit_data data;
std::pair<iterator,bool> ret =
priv_insert_unique_prepare(val, data);
if(ret.second){
ret.first = priv_insert_commit(data, boost::interprocess::move<value_type>(val));
}
return ret.first;
}
template <class... Args>
iterator emplace_hint_unique(const_iterator hint, Args&&... args)
{
value_type val(boost::interprocess::forward<Args>(args)...);
insert_commit_data data;
std::pair<iterator,bool> ret = priv_insert_unique_prepare(hint, val, data);
if(ret.second){
ret.first = priv_insert_commit(data, boost::interprocess::move<value_type>(val));
}
return ret.first;
}
template <class... Args>
iterator emplace_equal(Args&&... args)
{
value_type val(boost::interprocess::forward<Args>(args)...);
iterator i = this->upper_bound(KeyOfValue()(val));
i = this->m_data.m_vect.insert(i, boost::interprocess::move<value_type>(val));
return i;
}
template <class... Args>
iterator emplace_hint_equal(const_iterator hint, Args&&... args)
{
value_type val(boost::interprocess::forward<Args>(args)...);
insert_commit_data data;
priv_insert_equal_prepare(hint, val, data);
return priv_insert_commit(data, boost::interprocess::move<value_type>(val));
}
#else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
iterator emplace_unique()
{
containers_detail::value_init<value_type> vval;
value_type &val = vval.m_t;
insert_commit_data data;
std::pair<iterator,bool> ret =
priv_insert_unique_prepare(val, data);
if(ret.second){
ret.first = priv_insert_commit(data, boost::interprocess::move<value_type>(val));
}
return ret.first;
}
iterator emplace_hint_unique(const_iterator hint)
{
containers_detail::value_init<value_type> vval;
value_type &val = vval.m_t;
insert_commit_data data;
std::pair<iterator,bool> ret = priv_insert_unique_prepare(hint, val, data);
if(ret.second){
ret.first = priv_insert_commit(data, boost::interprocess::move<value_type>(val));
}
return ret.first;
}
iterator emplace_equal()
{
containers_detail::value_init<value_type> vval;
value_type &val = vval.m_t;
iterator i = this->upper_bound(KeyOfValue()(val));
i = this->m_data.m_vect.insert(i, boost::interprocess::move<value_type>(val));
return i;
}
iterator emplace_hint_equal(const_iterator hint)
{
containers_detail::value_init<value_type> vval;
value_type &val = vval.m_t;
insert_commit_data data;
priv_insert_equal_prepare(hint, val, data);
return priv_insert_commit(data, boost::interprocess::move<value_type>(val));
}
#define BOOST_PP_LOCAL_MACRO(n) \
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
{ \
value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
insert_commit_data data; \
std::pair<iterator,bool> ret = priv_insert_unique_prepare(val, data); \
if(ret.second){ \
ret.first = priv_insert_commit(data, boost::interprocess::move<value_type>(val)); \
} \
return ret.first; \
} \
\
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
iterator emplace_hint_unique(const_iterator hint, \
BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
{ \
value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
insert_commit_data data; \
std::pair<iterator,bool> ret = priv_insert_unique_prepare(hint, val, data); \
if(ret.second){ \
ret.first = priv_insert_commit(data, boost::interprocess::move<value_type>(val)); \
} \
return ret.first; \
} \
\
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
{ \
value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
iterator i = this->upper_bound(KeyOfValue()(val)); \
i = this->m_data.m_vect.insert(i, boost::interprocess::move<value_type>(val)); \
return i; \
} \
\
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
iterator emplace_hint_equal(const_iterator hint, \
BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
{ \
value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
insert_commit_data data; \
priv_insert_equal_prepare(hint, val, data); \
return priv_insert_commit(data, boost::interprocess::move<value_type>(val)); \
} \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
iterator erase(const_iterator position)
{ return this->m_data.m_vect.erase(position); }
size_type erase(const key_type& k)
{
std::pair<iterator,iterator > itp = this->equal_range(k);
size_type ret = static_cast<size_type>(itp.second-itp.first);
if (ret){
this->m_data.m_vect.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(); }
//! <b>Effects</b>: Tries to deallocate the excess of memory created
// with previous allocations. The size of the vector is unchanged
//!
//! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
//!
//! <b>Complexity</b>: Linear to size().
void shrink_to_fit()
{ this->m_data.m_vect.shrink_to_fit(); }
// set operations:
iterator find(const key_type& k)
{
const Compare &key_comp = this->m_data.get_comp();
iterator i = this->lower_bound(k);
if (i != this->end() && key_comp(k, KeyOfValue()(*i))){
i = this->end();
}
return i;
}
const_iterator find(const key_type& k) const
{
const Compare &key_comp = this->m_data.get_comp();
const_iterator i = this->lower_bound(k);
if (i != this->end() && key_comp(k, KeyOfValue()(*i))){
i = this->end();
}
return i;
}
size_type count(const key_type& k) const
{
std::pair<const_iterator, const_iterator> p = this->equal_range(k);
size_type n = p.second - p.first;
return n;
}
iterator lower_bound(const key_type& k)
{ return this->priv_lower_bound(this->begin(), this->end(), k); }
const_iterator lower_bound(const key_type& k) const
{ return this->priv_lower_bound(this->begin(), this->end(), k); }
iterator upper_bound(const key_type& k)
{ return this->priv_upper_bound(this->begin(), this->end(), k); }
const_iterator upper_bound(const key_type& k) const
{ return this->priv_upper_bound(this->begin(), this->end(), k); }
std::pair<iterator,iterator> equal_range(const key_type& k)
{ return this->priv_equal_range(this->begin(), this->end(), k); }
std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
{ return this->priv_equal_range(this->begin(), this->end(), k); }
size_type capacity() const
{ return this->m_data.m_vect.capacity(); }
void reserve(size_type count)
{ this->m_data.m_vect.reserve(count); }
private:
struct insert_commit_data
{
const_iterator position;
};
// insert/erase
void priv_insert_equal_prepare
(const_iterator pos, const value_type& val, insert_commit_data &data)
{
// 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->cend() || !value_comp(*pos, val)){
if (pos == this->cbegin() || !value_comp(val, pos[-1])){
data.position = pos;
}
else{
data.position =
this->priv_upper_bound(this->cbegin(), pos, KeyOfValue()(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{
data.position =
this->priv_lower_bound(pos, this->cend(), KeyOfValue()(val));
}
}
std::pair<iterator,bool> priv_insert_unique_prepare
(const_iterator beg, const_iterator end, const value_type& val, insert_commit_data &commit_data)
{
const value_compare &value_comp = this->m_data;
commit_data.position = this->priv_lower_bound(beg, end, KeyOfValue()(val));
return std::pair<iterator,bool>
( *reinterpret_cast<iterator*>(&commit_data.position)
, commit_data.position == end || value_comp(val, *commit_data.position));
}
std::pair<iterator,bool> priv_insert_unique_prepare
(const value_type& val, insert_commit_data &commit_data)
{ return priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); }
std::pair<iterator,bool> priv_insert_unique_prepare
(const_iterator pos, const value_type& val, insert_commit_data &commit_data)
{
//N1780. Props to Howard Hinnant!
//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->cend() || value_comp(val, *pos)){
if(pos != this->cbegin() && !value_comp(val, pos[-1])){
if(value_comp(pos[-1], val)){
commit_data.position = pos;
return std::pair<iterator,bool>(*reinterpret_cast<iterator*>(&pos), true);
}
else{
return std::pair<iterator,bool>(*reinterpret_cast<iterator*>(&pos), false);
}
}
return this->priv_insert_unique_prepare(this->cbegin(), pos, val, commit_data);
}
// Works, but increases code complexity
//Next check
//else if (value_comp(*pos, val) && !value_comp(pos[1], val)){
// if(value_comp(val, pos[1])){
// commit_data.position = pos+1;
// return std::pair<iterator,bool>(pos+1, true);
// }
// else{
// return std::pair<iterator,bool>(pos+1, false);
// }
//}
else{
//[... pos ... val ... ]
//The hint is before the insertion position, so insert it
//in the remaining range
return this->priv_insert_unique_prepare(pos, this->end(), val, commit_data);
}
}
template<class Convertible>
iterator priv_insert_commit
(insert_commit_data &commit_data, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible)
{
return this->m_data.m_vect.insert
( commit_data.position
, boost::interprocess::forward<Convertible>(convertible));
}
template <class RanIt>
RanIt priv_lower_bound(RanIt first, RanIt last,
const key_type & key) const
{
const Compare &key_comp = this->m_data.get_comp();
KeyOfValue key_extract;
difference_type len = last - first, half;
RanIt middle;
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (key_comp(key_extract(*middle), key)) {
++middle;
first = middle;
len = len - half - 1;
}
else
len = half;
}
return first;
}
template <class RanIt>
RanIt priv_upper_bound(RanIt first, RanIt last,
const key_type & key) const
{
const Compare &key_comp = this->m_data.get_comp();
KeyOfValue key_extract;
difference_type len = last - first, half;
RanIt middle;
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (key_comp(key, key_extract(*middle))) {
len = half;
}
else{
first = ++middle;
len = len - half - 1;
}
}
return first;
}
template <class RanIt>
std::pair<RanIt, RanIt>
priv_equal_range(RanIt first, RanIt last, const key_type& key) const
{
const Compare &key_comp = this->m_data.get_comp();
KeyOfValue key_extract;
difference_type len = last - first, half;
RanIt middle, left, right;
while (len > 0) {
half = len >> 1;
middle = first;
middle += half;
if (key_comp(key_extract(*middle), key)){
first = middle;
++first;
len = len - half - 1;
}
else if (key_comp(key, key_extract(*middle))){
len = half;
}
else {
left = this->priv_lower_bound(first, middle, key);
first += len;
right = this->priv_upper_bound(++middle, first, key);
return std::pair<RanIt, RanIt>(left, right);
}
}
return std::pair<RanIt, RanIt>(first, first);
}
template <class FwdIt>
void priv_insert_equal(FwdIt first, FwdIt last, std::forward_iterator_tag)
{
size_type len = static_cast<size_type>(std::distance(first, last));
this->reserve(this->size()+len);
this->priv_insert_equal(first, last, std::input_iterator_tag());
}
template <class InIt>
void priv_insert_equal(InIt first, InIt last, std::input_iterator_tag)
{
for ( ; first != last; ++first)
this->insert_equal(*first);
}
/*
template <class FwdIt>
void priv_insert_unique(FwdIt first, FwdIt last, std::forward_iterator_tag)
{
size_type len = static_cast<size_type>(std::distance(first, last));
this->reserve(this->size()+len);
priv_insert_unique(first, last, std::input_iterator_tag());
}
template <class InIt>
void priv_insert_unique(InIt first, InIt last, std::input_iterator_tag)
{
for ( ; first != last; ++first)
this->insert_unique(*first);
}
*/
};
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator==(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return x.size() == y.size() &&
std::equal(x.begin(), x.end(), y.begin());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{
return std::lexicographical_compare(x.begin(), x.end(),
y.begin(), y.end());
}
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator!=(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return !(x == y); }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return y < x; }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator<=(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return !(y < x); }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline bool
operator>=(const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
const flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ return !(x < y); }
template <class Key, class Value, class KeyOfValue,
class Compare, class Alloc>
inline void
swap(flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& x,
flat_tree<Key,Value,KeyOfValue,Compare,Alloc>& y)
{ x.swap(y); }
} //namespace containers_detail {
} //namespace interprocess_container {
namespace interprocess {
//!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations
template <class K, class V, class KOV,
class C, class A>
struct has_trivial_destructor_after_move<boost::interprocess_container::containers_detail::flat_tree<K, V, KOV, C, A> >
{
static const bool value = has_trivial_destructor<A>::value && has_trivial_destructor<C>::value;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif // BOOST_CONTAINERS_FLAT_TREE_HPP

View File

@@ -0,0 +1,492 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP
#define BOOST_CONTAINERS_DETAIL_ITERATORS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/interprocess/detail/move.hpp>
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
#include <boost/interprocess/containers/container/detail/variadic_templates_tools.hpp>
#else
#include <boost/interprocess/containers/container/detail/preprocessor.hpp>
#endif
#include <iterator>
namespace boost {
namespace interprocess_container {
template <class T, class Difference = std::ptrdiff_t>
class constant_iterator
: public std::iterator
<std::random_access_iterator_tag, T, Difference, const T*, const T &>
{
typedef constant_iterator<T, Difference> this_type;
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){}
constant_iterator& operator++()
{ increment(); return *this; }
constant_iterator operator++(int)
{
constant_iterator result (*this);
increment();
return result;
}
friend bool operator== (const constant_iterator& i, const constant_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const constant_iterator& i, const constant_iterator& i2)
{ return !(i == i2); }
friend bool operator< (const constant_iterator& i, const constant_iterator& i2)
{ return i.less(i2); }
friend bool operator> (const constant_iterator& i, const constant_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const constant_iterator& i, const constant_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const constant_iterator& i, const constant_iterator& i2)
{ return !(i < i2); }
friend Difference operator- (const constant_iterator& i, const constant_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
constant_iterator& operator+=(Difference off)
{ this->advance(off); return *this; }
constant_iterator operator+(Difference off) const
{
constant_iterator other(*this);
other.advance(off);
return other;
}
friend constant_iterator operator+(Difference off, const constant_iterator& right)
{ return right + off; }
constant_iterator& operator-=(Difference off)
{ this->advance(-off); return *this; }
constant_iterator operator-(Difference off) const
{ return *this + (-off); }
const T& operator*() const
{ return dereference(); }
const T* operator->() const
{ return &(dereference()); }
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; }
bool less(const this_type &other) const
{ return other.m_num < m_num; }
const T & dereference() const
{ return *m_ptr; }
void advance(Difference n)
{ m_num -= n; }
Difference distance_to(const this_type &other)const
{ return m_num - other.m_num; }
};
template <class T, class Difference = std::ptrdiff_t>
class default_construct_iterator
: public std::iterator
<std::random_access_iterator_tag, T, Difference, const T*, const T &>
{
typedef default_construct_iterator<T, Difference> this_type;
public:
explicit default_construct_iterator(Difference range_size)
: m_num(range_size){}
//Constructors
default_construct_iterator()
: m_num(0){}
default_construct_iterator& operator++()
{ increment(); return *this; }
default_construct_iterator operator++(int)
{
default_construct_iterator result (*this);
increment();
return result;
}
friend bool operator== (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return !(i == i2); }
friend bool operator< (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return i.less(i2); }
friend bool operator> (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return !(i < i2); }
friend Difference operator- (const default_construct_iterator& i, const default_construct_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
default_construct_iterator& operator+=(Difference off)
{ this->advance(off); return *this; }
default_construct_iterator operator+(Difference off) const
{
default_construct_iterator other(*this);
other.advance(off);
return other;
}
friend default_construct_iterator operator+(Difference off, const default_construct_iterator& right)
{ return right + off; }
default_construct_iterator& operator-=(Difference off)
{ this->advance(-off); return *this; }
default_construct_iterator operator-(Difference off) const
{ return *this + (-off); }
const T& operator*() const
{ return dereference(); }
const T* operator->() const
{ return &(dereference()); }
private:
Difference m_num;
void increment()
{ --m_num; }
void decrement()
{ ++m_num; }
bool equal(const this_type &other) const
{ return m_num == other.m_num; }
bool less(const this_type &other) const
{ return other.m_num < m_num; }
const T & dereference() const
{
static T dummy;
return dummy;
}
void advance(Difference n)
{ m_num -= n; }
Difference distance_to(const this_type &other)const
{ return m_num - other.m_num; }
};
template <class T, class Difference = std::ptrdiff_t>
class repeat_iterator
: public std::iterator
<std::random_access_iterator_tag, T, Difference>
{
typedef repeat_iterator<T, Difference> this_type;
public:
explicit repeat_iterator(T &ref, Difference range_size)
: m_ptr(&ref), m_num(range_size){}
//Constructors
repeat_iterator()
: m_ptr(0), m_num(0){}
this_type& operator++()
{ increment(); return *this; }
this_type operator++(int)
{
this_type result (*this);
increment();
return result;
}
friend bool operator== (const this_type& i, const this_type& i2)
{ return i.equal(i2); }
friend bool operator!= (const this_type& i, const this_type& i2)
{ return !(i == i2); }
friend bool operator< (const this_type& i, const this_type& i2)
{ return i.less(i2); }
friend bool operator> (const this_type& i, const this_type& i2)
{ return i2 < i; }
friend bool operator<= (const this_type& i, const this_type& i2)
{ return !(i > i2); }
friend bool operator>= (const this_type& i, const this_type& i2)
{ return !(i < i2); }
friend Difference operator- (const this_type& i, const this_type& i2)
{ return i2.distance_to(i); }
//Arithmetic
this_type& operator+=(Difference off)
{ this->advance(off); return *this; }
this_type operator+(Difference off) const
{
this_type other(*this);
other.advance(off);
return other;
}
friend this_type operator+(Difference off, const this_type& right)
{ return right + off; }
this_type& operator-=(Difference off)
{ this->advance(-off); return *this; }
this_type operator-(Difference off) const
{ return *this + (-off); }
T& operator*() const
{ return dereference(); }
T *operator->() const
{ return &(dereference()); }
private:
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; }
bool less(const this_type &other) const
{ return other.m_num < m_num; }
T & dereference() const
{ return *m_ptr; }
void advance(Difference n)
{ m_num -= n; }
Difference distance_to(const this_type &other)const
{ return m_num - other.m_num; }
};
template <class T, class E>
class emplace_iterator
: public std::iterator
<std::random_access_iterator_tag, T, std::ptrdiff_t, const T*, const T &>
{
typedef emplace_iterator this_type;
public:
explicit emplace_iterator(E&e)
: m_num(1), m_pe(&e){}
emplace_iterator()
: m_num(0), m_pe(0){}
this_type& operator++()
{ increment(); return *this; }
this_type operator++(int)
{
this_type result (*this);
increment();
return result;
}
friend bool operator== (const this_type& i, const this_type& i2)
{ return i.equal(i2); }
friend bool operator!= (const this_type& i, const this_type& i2)
{ return !(i == i2); }
friend bool operator< (const this_type& i, const this_type& i2)
{ return i.less(i2); }
friend bool operator> (const this_type& i, const this_type& i2)
{ return i2 < i; }
friend bool operator<= (const this_type& i, const this_type& i2)
{ return !(i > i2); }
friend bool operator>= (const this_type& i, const this_type& i2)
{ return !(i < i2); }
friend std::ptrdiff_t operator- (const this_type& i, const this_type& i2)
{ return i2.distance_to(i); }
//Arithmetic
this_type& operator+=(std::ptrdiff_t off)
{ this->advance(off); return *this; }
this_type operator+(std::ptrdiff_t off) const
{
this_type other(*this);
other.advance(off);
return other;
}
friend this_type operator+(std::ptrdiff_t off, const this_type& right)
{ return right + off; }
this_type& operator-=(std::ptrdiff_t off)
{ this->advance(-off); return *this; }
this_type operator-(std::ptrdiff_t off) const
{ return *this + (-off); }
const T& operator*() const
{ return dereference(); }
const T* operator->() const
{ return &(dereference()); }
void construct_in_place(T* ptr)
{ (*m_pe)(ptr); }
private:
std::ptrdiff_t m_num;
E * m_pe;
void increment()
{ --m_num; }
void decrement()
{ ++m_num; }
bool equal(const this_type &other) const
{ return m_num == other.m_num; }
bool less(const this_type &other) const
{ return other.m_num < m_num; }
const T & dereference() const
{
static T dummy;
return dummy;
}
void advance(std::ptrdiff_t n)
{ m_num -= n; }
std::ptrdiff_t distance_to(const this_type &other)const
{ return m_num - other.m_num; }
};
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
template<class T, class ...Args>
struct emplace_functor
{
typedef typename containers_detail::build_number_seq<sizeof...(Args)>::type index_tuple_t;
emplace_functor(Args&&... args)
: args_(args...)
{}
void operator()(T *ptr)
{ emplace_functor::inplace_impl(ptr, index_tuple_t()); }
template<int ...IdxPack>
void inplace_impl(T* ptr, const containers_detail::index_tuple<IdxPack...>&)
{ ::new(ptr) T(boost::interprocess::forward<Args>(containers_detail::get<IdxPack>(args_))...); }
containers_detail::tuple<Args&&...> args_;
};
#else
template<class T>
struct emplace_functor
{
emplace_functor()
{}
void operator()(T *ptr)
{ new(ptr) T(); }
};
#define BOOST_PP_LOCAL_MACRO(n) \
template <class T, BOOST_PP_ENUM_PARAMS(n, class P) > \
struct BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \
{ \
BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \
( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \
: BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \
\
void operator()(T *ptr) \
{ \
new(ptr)T (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \
} \
BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \
}; \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
#endif
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP

View File

@@ -0,0 +1,152 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP
#define BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <cstddef>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
template <class T, T val>
struct integral_constant
{
static const T value = val;
typedef integral_constant<T,val> type;
};
template< bool C_ >
struct bool_ : integral_constant<bool, C_>
{
static const bool value = C_;
};
typedef bool_<true> true_;
typedef bool_<false> false_;
typedef true_ true_type;
typedef false_ false_type;
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <bool B, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <class Cond, class T = void>
struct disable_if : public enable_if_c<!Cond::value, T> {};
template <class T, class U>
class is_convertible
{
typedef char true_t;
class false_t { char dummy[2]; };
static true_t dispatch(U);
static false_t dispatch(...);
static T trigger();
public:
enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
};
template<
bool C
, typename T1
, typename T2
>
struct if_c
{
typedef T1 type;
};
template<
typename T1
, typename T2
>
struct if_c<false,T1,T2>
{
typedef T2 type;
};
template<
typename T1
, typename T2
, typename T3
>
struct if_
{
typedef typename if_c<0 != T1::value, T2, T3>::type type;
};
template <class Pair>
struct select1st
// : public std::unary_function<Pair, typename Pair::first_type>
{
template<class OtherPair>
const typename Pair::first_type& operator()(const OtherPair& x) const
{ return x.first; }
const typename Pair::first_type& operator()(const typename Pair::first_type& x) const
{ return x; }
};
// identity is an extension: it is not part of the standard.
template <class T>
struct identity
// : public std::unary_function<T,T>
{
typedef T type;
const T& operator()(const T& x) const
{ return x; }
};
template<std::size_t S>
struct ls_zeros
{
static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value);
};
template<>
struct ls_zeros<0>
{
static const std::size_t value = 0;
};
template<>
struct ls_zeros<1>
{
static const std::size_t value = 0;
};
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost {
#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP

View File

@@ -0,0 +1,554 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP
#define BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/utilities.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
#include <boost/interprocess/containers/container/detail/transform_iterator.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
template<class VoidPointer>
class basic_multiallocation_slist
{
public:
typedef VoidPointer void_pointer;
private:
static VoidPointer &priv_get_ref(const VoidPointer &p)
{ return *static_cast<void_pointer*>(containers_detail::get_pointer(p)); }
basic_multiallocation_slist(basic_multiallocation_slist &);
basic_multiallocation_slist &operator=(basic_multiallocation_slist &);
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist)
//!This iterator is returned by "allocate_many" functions so that
//!the user can access the multiple buffers allocated in a single call
class iterator
: public std::iterator<std::input_iterator_tag, char>
{
friend class basic_multiallocation_slist<void_pointer>;
void unspecified_bool_type_func() const {}
typedef void (iterator::*unspecified_bool_type)() const;
iterator(void_pointer node_range)
: next_node_(node_range)
{}
public:
typedef char value_type;
typedef value_type & reference;
typedef value_type * pointer;
iterator()
: next_node_(0)
{}
iterator &operator=(const iterator &other)
{ next_node_ = other.next_node_; return *this; }
public:
iterator& operator++()
{
next_node_ = *static_cast<void_pointer*>(containers_detail::get_pointer(next_node_));
return *this;
}
iterator operator++(int)
{
iterator result(*this);
++*this;
return result;
}
bool operator== (const iterator& other) const
{ return next_node_ == other.next_node_; }
bool operator!= (const iterator& other) const
{ return !operator== (other); }
reference operator*() const
{ return *static_cast<char*>(containers_detail::get_pointer(next_node_)); }
operator unspecified_bool_type() const
{ return next_node_? &iterator::unspecified_bool_type_func : 0; }
pointer operator->() const
{ return &(*(*this)); }
private:
void_pointer next_node_;
};
private:
iterator it_;
public:
basic_multiallocation_slist()
: it_(iterator())
{}
basic_multiallocation_slist(void_pointer p)
: it_(p ? iterator_to(p) : iterator())
{}
basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other)
: it_(iterator())
{ this->swap(other); }
basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other)
{
basic_multiallocation_slist tmp(boost::interprocess::move(other));
this->swap(tmp);
return *this;
}
bool empty() const
{ return !it_; }
iterator before_begin() const
{ return iterator(void_pointer(const_cast<void*>(static_cast<const void*>(&it_.next_node_)))); }
iterator begin() const
{ return it_; }
iterator end() const
{ return iterator(); }
void clear()
{ this->it_.next_node_ = void_pointer(0); }
iterator insert_after(iterator it, void_pointer m)
{
priv_get_ref(m) = priv_get_ref(it.next_node_);
priv_get_ref(it.next_node_) = m;
return iterator(m);
}
void push_front(void_pointer m)
{
priv_get_ref(m) = this->it_.next_node_;
this->it_.next_node_ = m;
}
void pop_front()
{ ++it_; }
void *front() const
{ return containers_detail::get_pointer(it_.next_node_); }
void splice_after(iterator after_this, iterator before_begin, iterator before_end)
{
if (after_this != before_begin && after_this != before_end && before_begin != before_end) {
void_pointer next_b = priv_get_ref(before_begin.next_node_);
void_pointer next_e = priv_get_ref(before_end.next_node_);
void_pointer next_p = priv_get_ref(after_this.next_node_);
priv_get_ref(before_begin.next_node_) = next_e;
priv_get_ref(before_end.next_node_) = next_p;
priv_get_ref(after_this.next_node_) = next_b;
}
}
void swap(basic_multiallocation_slist &other_chain)
{
std::swap(this->it_, other_chain.it_);
}
static iterator iterator_to(void_pointer p)
{ return iterator(p); }
void_pointer extract_data()
{
void_pointer ret = empty() ? void_pointer(0) : void_pointer(&*it_);
it_ = iterator();
return ret;
}
};
template<class VoidPointer>
class basic_multiallocation_cached_slist
{
private:
basic_multiallocation_slist<VoidPointer> slist_;
typename basic_multiallocation_slist<VoidPointer>::iterator last_;
basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &);
basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &);
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist)
typedef typename basic_multiallocation_slist<VoidPointer>::void_pointer void_pointer;
typedef typename basic_multiallocation_slist<VoidPointer>::iterator iterator;
basic_multiallocation_cached_slist()
: slist_(), last_(slist_.before_begin())
{}
/*
basic_multiallocation_cached_slist(iterator first_node)
: slist_(first_node), last_(slist_.before_begin())
{
iterator end;
while(first_node != end){
++last_;
}
}*/
basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2)
: slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin())
{}
basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other)
: slist_(), last_(slist_.before_begin())
{ this->swap(other); }
basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other)
{
basic_multiallocation_cached_slist tmp(boost::interprocess::move(other));
this->swap(tmp);
return *this;
}
bool empty() const
{ return slist_.empty(); }
iterator before_begin() const
{ return slist_.before_begin(); }
iterator begin() const
{ return slist_.begin(); }
iterator end() const
{ return slist_.end(); }
iterator last() const
{ return last_; }
void clear()
{
slist_.clear();
last_ = slist_.before_begin();
}
iterator insert_after(iterator it, void_pointer m)
{
slist_.insert_after(it, m);
if(it == last_){
last_ = slist_.iterator_to(m);
}
return iterator_to(m);
}
void push_front(void_pointer m)
{ this->insert_after(this->before_begin(), m); }
void push_back(void_pointer m)
{ this->insert_after(last_, m); }
void pop_front()
{
if(last_ == slist_.begin()){
last_ = slist_.before_begin();
}
slist_.pop_front();
}
void *front() const
{ return slist_.front(); }
void splice_after(iterator after_this, iterator before_begin, iterator before_end)
{
if(before_begin == before_end)
return;
if(after_this == last_){
last_ = before_end;
}
slist_.splice_after(after_this, before_begin, before_end);
}
void swap(basic_multiallocation_cached_slist &x)
{
slist_.swap(x.slist_);
using std::swap;
swap(last_, x.last_);
if(last_ == x.before_begin()){
last_ = this->before_begin();
}
if(x.last_ == this->before_begin()){
x.last_ = x.before_begin();
}
}
static iterator iterator_to(void_pointer p)
{ return basic_multiallocation_slist<VoidPointer>::iterator_to(p); }
std::pair<void_pointer, void_pointer> extract_data()
{
if(this->empty()){
return std::pair<void_pointer, void_pointer>(void_pointer(0), void_pointer(0));
}
else{
void_pointer p1 = slist_.extract_data();
void_pointer p2 = void_pointer(&*last_);
last_ = iterator();
return std::pair<void_pointer, void_pointer>(p1, p2);
}
}
};
template<class MultiallocatorCachedSlist>
class basic_multiallocation_cached_counted_slist
{
private:
MultiallocatorCachedSlist cached_slist_;
std::size_t size_;
basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &);
basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &);
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist)
typedef typename MultiallocatorCachedSlist::void_pointer void_pointer;
typedef typename MultiallocatorCachedSlist::iterator iterator;
basic_multiallocation_cached_counted_slist()
: cached_slist_(), size_(0)
{}
basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n)
: cached_slist_(p1, p2), size_(n)
{}
basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other)
: cached_slist_(), size_(0)
{ this->swap(other); }
basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other)
{
basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other));
this->swap(tmp);
return *this;
}
basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n)
: cached_slist_(boost::interprocess::move(mem)), size_(n)
{}
bool empty() const
{ return cached_slist_.empty(); }
std::size_t size() const
{ return size_; }
iterator before_begin() const
{ return cached_slist_.before_begin(); }
iterator begin() const
{ return cached_slist_.begin(); }
iterator end() const
{ return cached_slist_.end(); }
iterator last() const
{ return cached_slist_.last(); }
void clear()
{
cached_slist_.clear();
size_ = 0;
}
iterator insert_after(iterator it, void_pointer m)
{
iterator ret = cached_slist_.insert_after(it, m);
++size_;
return ret;
}
void push_front(void_pointer m)
{ this->insert_after(this->before_begin(), m); }
void push_back(void_pointer m)
{ this->insert_after(this->before_begin(), m); }
void pop_front()
{
cached_slist_.pop_front();
--size_;
}
void *front() const
{ return cached_slist_.front(); }
void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end)
{
std::size_t n = static_cast<std::size_t>(std::distance(before_begin, before_end));
this->splice_after(after_this, x, before_begin, before_end, n);
}
void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end, std::size_t n)
{
cached_slist_.splice_after(after_this, before_begin, before_end);
size_ += n;
x.size_ -= n;
}
void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x)
{
cached_slist_.splice_after(after_this, x.before_begin(), x.last());
size_ += x.size_;
x.size_ = 0;
}
void swap(basic_multiallocation_cached_counted_slist &x)
{
cached_slist_.swap(x.cached_slist_);
using std::swap;
swap(size_, x.size_);
}
static iterator iterator_to(void_pointer p)
{ return MultiallocatorCachedSlist::iterator_to(p); }
std::pair<void_pointer, void_pointer> extract_data()
{
size_ = 0;
return cached_slist_.extract_data();
}
};
template<class T>
struct cast_functor
{
typedef typename containers_detail::add_reference<T>::type result_type;
result_type operator()(char &ptr) const
{ return *static_cast<T*>(static_cast<void*>(&ptr)); }
};
template<class MultiallocationChain, class T>
class transform_multiallocation_chain
{
private:
MultiallocationChain holder_;
typedef typename MultiallocationChain::void_pointer void_pointer;
typedef typename boost::pointer_to_other
<void_pointer, T>::type pointer;
transform_multiallocation_chain(transform_multiallocation_chain &);
transform_multiallocation_chain &operator=(transform_multiallocation_chain &);
static pointer cast(void_pointer p)
{
return pointer(static_cast<T*>(containers_detail::get_pointer(p)));
}
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain)
typedef transform_iterator
< typename MultiallocationChain::iterator
, containers_detail::cast_functor <T> > iterator;
transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n)
: holder_(p1, p2, n)
{}
transform_multiallocation_chain()
: holder_()
{}
transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other)
: holder_()
{ this->swap(other); }
transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other)
: holder_(boost::interprocess::move(other))
{}
transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other)
{
transform_multiallocation_chain tmp(boost::interprocess::move(other));
this->swap(tmp);
return *this;
}
void push_front(pointer mem)
{ holder_.push_front(mem); }
void swap(transform_multiallocation_chain &other_chain)
{ holder_.swap(other_chain.holder_); }
/*
void splice_after(iterator after_this, iterator before_begin, iterator before_end)
{ holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); }
*/
void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n)
{ holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); }
void pop_front()
{ holder_.pop_front(); }
pointer front() const
{ return cast(holder_.front()); }
bool empty() const
{ return holder_.empty(); }
iterator before_begin() const
{ return iterator(holder_.before_begin()); }
iterator begin() const
{ return iterator(holder_.begin()); }
iterator end() const
{ return iterator(holder_.end()); }
iterator last() const
{ return iterator(holder_.last()); }
std::size_t size() const
{ return holder_.size(); }
void clear()
{ holder_.clear(); }
iterator insert_after(iterator it, pointer m)
{ return iterator(holder_.insert_after(it.base(), m)); }
static iterator iterator_to(pointer p)
{ return iterator(MultiallocationChain::iterator_to(p)); }
std::pair<void_pointer, void_pointer> extract_data()
{ return holder_.extract_data(); }
MultiallocationChain extract_multiallocation_chain()
{
return MultiallocationChain(boost::interprocess::move(holder_));
}
};
}}}
// namespace containers_detail {
// namespace interprocess_container {
// namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP

View File

@@ -0,0 +1,499 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_
#define BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <utility>
#include <functional>
#include <boost/interprocess/detail/move.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/interprocess/containers/container/detail/version_type.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
#include <boost/interprocess/containers/container/detail/utilities.hpp>
#include <boost/interprocess/containers/container/detail/mpl.hpp>
#include <boost/interprocess/containers/container/detail/destroyers.hpp>
#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
#include <boost/interprocess/containers/container/detail/preprocessor.hpp>
#endif
#include <boost/interprocess/containers/container/detail/algorithms.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
//!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 containers_detail::integral_constant<unsigned,
boost::interprocess_container::containers_detail::
version<Allocator>::value> alloc_version;
typedef containers_detail::integral_constant<unsigned, 1> allocator_v1;
typedef containers_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); }
scoped_deallocator(scoped_deallocator &);
scoped_deallocator& operator=(scoped_deallocator &);
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_deallocator)
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()); }
scoped_deallocator(BOOST_INTERPROCESS_RV_REF(scoped_deallocator) o)
: m_ptr(o.m_ptr), m_alloc(o.m_alloc)
{ o.release(); }
pointer get() const
{ return m_ptr; }
void release()
{ m_ptr = 0; }
};
template <class A>
class allocator_destroyer_and_chain_builder
{
typedef typename A::value_type value_type;
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 = containers_detail::get_pointer(p);
vp->~value_type();
c_.push_front(vp);
}
};
template <class A>
class allocator_multialloc_chain_node_deallocator
{
typedef typename A::value_type value_type;
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()
{
if(!c_.empty())
a_.deallocate_individual(boost::interprocess::move(c_));
}
};
template<class ValueCompare, class Node>
struct node_compare
: private ValueCompare
{
typedef typename ValueCompare::key_type key_type;
typedef typename ValueCompare::value_type value_type;
typedef typename ValueCompare::key_of_value key_of_value;
node_compare(const ValueCompare &pred)
: ValueCompare(pred)
{}
ValueCompare &value_comp()
{ return static_cast<ValueCompare &>(*this); }
ValueCompare &value_comp() const
{ return static_cast<const ValueCompare &>(*this); }
bool operator()(const Node &a, const Node &b) const
{ return ValueCompare::operator()(a.get_data(), b.get_data()); }
};
template<class A, class ICont>
struct node_alloc_holder
{
typedef node_alloc_holder<A, ICont> self_t;
typedef typename A::value_type value_type;
typedef typename ICont::value_type Node;
typedef typename A::template rebind<Node>::other NodeAlloc;
typedef A ValAlloc;
typedef typename NodeAlloc::pointer NodePtr;
typedef containers_detail::scoped_deallocator<NodeAlloc> Deallocator;
typedef typename NodeAlloc::size_type size_type;
typedef typename NodeAlloc::difference_type difference_type;
typedef containers_detail::integral_constant<unsigned, 1> allocator_v1;
typedef containers_detail::integral_constant<unsigned, 2> allocator_v2;
typedef containers_detail::integral_constant<unsigned,
boost::interprocess_container::containers_detail::
version<NodeAlloc>::value> alloc_version;
typedef typename ICont::iterator icont_iterator;
typedef typename ICont::const_iterator icont_citerator;
typedef allocator_destroyer<NodeAlloc> Destroyer;
private:
node_alloc_holder(node_alloc_holder&);
node_alloc_holder & operator=(node_alloc_holder&);
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(node_alloc_holder)
node_alloc_holder(const ValAlloc &a)
: members_(a)
{}
node_alloc_holder(const node_alloc_holder &other)
: members_(other.node_alloc())
{}
node_alloc_holder(BOOST_INTERPROCESS_RV_REF(node_alloc_holder) other)
: members_(boost::interprocess::move(other.node_alloc()))
{ this->swap(other); }
template<class Pred>
node_alloc_holder(const ValAlloc &a, const Pred &c)
: members_(a, typename ICont::value_compare(c))
{}
template<class Pred>
node_alloc_holder(BOOST_INTERPROCESS_RV_REF(ValAlloc) a, const Pred &c)
: members_(a, typename ICont::value_compare(c))
{}
template<class Pred>
node_alloc_holder(const node_alloc_holder &other, const Pred &c)
: members_(other.node_alloc(), typename ICont::value_compare(c))
{}
~node_alloc_holder()
{ this->clear(alloc_version()); }
size_type max_size() const
{ return this->node_alloc().max_size(); }
NodePtr allocate_one()
{ return this->allocate_one(alloc_version()); }
NodePtr allocate_one(allocator_v1)
{ return this->node_alloc().allocate(1); }
NodePtr allocate_one(allocator_v2)
{ return this->node_alloc().allocate_one(); }
void deallocate_one(NodePtr p)
{ return this->deallocate_one(p, alloc_version()); }
void deallocate_one(NodePtr p, allocator_v1)
{ this->node_alloc().deallocate(p, 1); }
void deallocate_one(NodePtr p, allocator_v2)
{ this->node_alloc().deallocate_one(p); }
template<class Convertible1, class Convertible2>
static void construct(const NodePtr &ptr,
#ifdef BOOST_HAS_RVALUE_REFS
std::pair<Convertible1, Convertible2> &&
#else
boost::interprocess::rv<std::pair<Convertible1, Convertible2> > &
#endif
value)
{
typedef typename Node::hook_type hook_type;
typedef typename Node::value_type::first_type first_type;
typedef typename Node::value_type::second_type second_type;
Node *nodeptr = containers_detail::get_pointer(ptr);
//Hook constructor does not throw
new(static_cast<hook_type*>(nodeptr))hook_type();
//Now construct pair members_holder
value_type *valueptr = &nodeptr->get_data();
new((void*)&valueptr->first) first_type(boost::interprocess::move(value.first));
BOOST_TRY{
new((void*)&valueptr->second) second_type(boost::interprocess::move(value.second));
}
BOOST_CATCH(...){
valueptr->first.~first_type();
static_cast<hook_type*>(nodeptr)->~hook_type();
BOOST_RETHROW
}
BOOST_CATCH_END
}
static void destroy(const NodePtr &ptr)
{ containers_detail::get_pointer(ptr)->~Node(); }
Deallocator create_node_and_deallocator()
{
return Deallocator(this->allocate_one(), this->node_alloc());
}
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
template<class ...Args>
static void construct(const NodePtr &ptr, Args &&...args)
{ new((void*)containers_detail::get_pointer(ptr)) Node(boost::interprocess::forward<Args>(args)...); }
template<class ...Args>
NodePtr create_node(Args &&...args)
{
NodePtr p = this->allocate_one();
Deallocator node_deallocator(p, this->node_alloc());
self_t::construct(p, boost::interprocess::forward<Args>(args)...);
node_deallocator.release();
return (p);
}
#else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
static void construct(const NodePtr &ptr)
{ new((void*)containers_detail::get_pointer(ptr)) Node(); }
NodePtr create_node()
{
NodePtr p = this->allocate_one();
Deallocator node_deallocator(p, this->node_alloc());
self_t::construct(p);
node_deallocator.release();
return (p);
}
#define BOOST_PP_LOCAL_MACRO(n) \
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
{ \
new((void*)containers_detail::get_pointer(ptr)) \
Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
} \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
#define BOOST_PP_LOCAL_MACRO(n) \
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
{ \
NodePtr p = this->allocate_one(); \
Deallocator node_deallocator(p, this->node_alloc()); \
self_t::construct(p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \
node_deallocator.release(); \
return (p); \
} \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
template<class It>
NodePtr create_node_from_it(It it)
{
NodePtr p = this->allocate_one();
Deallocator node_deallocator(p, this->node_alloc());
::boost::interprocess_container::construct_in_place(containers_detail::get_pointer(p), it);
node_deallocator.release();
return (p);
}
void destroy_node(NodePtr node)
{
self_t::destroy(node);
this->deallocate_one(node);
}
void swap(node_alloc_holder &x)
{
NodeAlloc& this_alloc = this->node_alloc();
NodeAlloc& other_alloc = x.node_alloc();
if (this_alloc != other_alloc){
containers_detail::do_swap(this_alloc, other_alloc);
}
this->icont().swap(x.icont());
}
template<class FwdIterator, class Inserter>
FwdIterator allocate_many_and_construct
(FwdIterator beg, difference_type n, Inserter inserter)
{
if(n){
typedef typename NodeAlloc::multiallocation_chain multiallocation_chain;
//Try to allocate memory in a single block
multiallocation_chain mem(this->node_alloc().allocate_individual(n));
int constructed = 0;
Node *p = 0;
BOOST_TRY{
for(difference_type i = 0; i < n; ++i, ++beg, --constructed){
p = containers_detail::get_pointer(mem.front());
mem.pop_front();
//This can throw
constructed = 0;
boost::interprocess_container::construct_in_place(p, beg);
++constructed;
//This can throw in some containers (predicate might throw)
inserter(*p);
}
}
BOOST_CATCH(...){
if(constructed){
this->destroy(p);
}
this->node_alloc().deallocate_individual(boost::interprocess::move(mem));
BOOST_RETHROW
}
BOOST_CATCH_END
}
return beg;
}
void clear(allocator_v1)
{ this->icont().clear_and_dispose(Destroyer(this->node_alloc())); }
void clear(allocator_v2)
{
typename NodeAlloc::multiallocation_chain chain;
allocator_destroyer_and_chain_builder<NodeAlloc> builder(this->node_alloc(), chain);
this->icont().clear_and_dispose(builder);
BOOST_STATIC_ASSERT((boost::interprocess::is_movable<typename NodeAlloc::multiallocation_chain>::value == true));
if(!chain.empty())
this->node_alloc().deallocate_individual(boost::interprocess::move(chain));
}
icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v1)
{ return this->icont().erase_and_dispose(first, last, Destroyer(this->node_alloc())); }
icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v2)
{
allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
return this->icont().erase_and_dispose(first, last, chain_holder.get_chain_builder());
}
template<class Key, class Comparator>
size_type erase_key(const Key& k, const Comparator &comp, allocator_v1)
{ return this->icont().erase_and_dispose(k, comp, Destroyer(this->node_alloc())); }
template<class Key, class Comparator>
size_type erase_key(const Key& k, const Comparator &comp, allocator_v2)
{
allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
return this->icont().erase_and_dispose(k, comp, chain_holder.get_chain_builder());
}
protected:
struct cloner
{
cloner(node_alloc_holder &holder)
: m_holder(holder)
{}
NodePtr operator()(const Node &other) const
{ return m_holder.create_node(other.get_data()); }
node_alloc_holder &m_holder;
};
struct destroyer
{
destroyer(node_alloc_holder &holder)
: m_holder(holder)
{}
void operator()(NodePtr n) const
{ m_holder.destroy_node(n); }
node_alloc_holder &m_holder;
};
struct members_holder
: public NodeAlloc
{
private:
members_holder(const members_holder&);
public:
template<class ConvertibleToAlloc>
members_holder(const ConvertibleToAlloc &c2alloc)
: NodeAlloc(c2alloc)
{}
template<class ConvertibleToAlloc, class Pred>
members_holder(const ConvertibleToAlloc &c2alloc, const Pred &c)
: NodeAlloc(c2alloc), m_icont(c)
{}
//The intrusive container
ICont m_icont;
} members_;
ICont &non_const_icont() const
{ return const_cast<ICont&>(this->members_.m_icont); }
ICont &icont()
{ return this->members_.m_icont; }
const ICont &icont() const
{ return this->members_.m_icont; }
NodeAlloc &node_alloc()
{ return static_cast<NodeAlloc &>(this->members_); }
const NodeAlloc &node_alloc() const
{ return static_cast<const NodeAlloc &>(this->members_); }
};
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif // BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_

View File

@@ -0,0 +1,189 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP
#define BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/interprocess/containers/container/detail/mpl.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
#include <utility> //std::pair
#include <boost/interprocess/detail/move.hpp>
#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING
#include <boost/interprocess/containers/container/detail/preprocessor.hpp>
#endif
namespace boost {
namespace interprocess_container {
namespace containers_detail {
template <class T1, class T2>
struct pair
{
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(pair)
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
//std::pair compatibility
template <class D, class S>
pair(const std::pair<D, S>& p)
: first(p.first), second(p.second)
{}
//To resolve ambiguity with the variadic constructor of 1 argument
//and the previous constructor
pair(std::pair<T1, T2>& x)
: first(x.first), second(x.second)
{}
template <class D, class S>
pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p)
: first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second))
{}
pair()
: first(), second()
{}
pair(const pair<T1, T2>& x)
: first(x.first), second(x.second)
{}
//To resolve ambiguity with the variadic constructor of 1 argument
//and the copy constructor
pair(pair<T1, T2>& x)
: first(x.first), second(x.second)
{}
pair(BOOST_INTERPROCESS_RV_REF(pair) p)
: first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second))
{}
template <class D, class S>
pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(pair, D, S) p)
: first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second))
{}
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
template<class U, class ...Args>
pair(U &&u, Args &&... args)
: first(boost::interprocess::forward<U>(u))
, second(boost::interprocess::forward<Args>(args)...)
{}
#else
template<class U>
pair( BOOST_CONTAINERS_PARAM(U, u)
#ifndef BOOST_HAS_RVALUE_REFS
, typename containers_detail::disable_if
< containers_detail::is_same<U, boost::interprocess::rv<pair> > >::type* = 0
#endif
)
: first(boost::interprocess::forward<U>(const_cast<U&>(u)))
{}
#define BOOST_PP_LOCAL_MACRO(n) \
template<class U, BOOST_PP_ENUM_PARAMS(n, class P)> \
pair(BOOST_CONTAINERS_PARAM(U, u) \
,BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \
: first(boost::interprocess::forward<U>(const_cast<U&>(u))) \
, second(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \
{} \
//!
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS)
#include BOOST_PP_LOCAL_ITERATE()
#endif
pair& operator=(BOOST_INTERPROCESS_RV_REF(pair) p)
{
first = boost::interprocess::move(p.first);
second = boost::interprocess::move(p.second);
return *this;
}
pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, T1, T2) p)
{
first = boost::interprocess::move(p.first);
second = boost::interprocess::move(p.second);
return *this;
}
template <class D, class S>
pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p)
{
first = boost::interprocess::move(p.first);
second = boost::interprocess::move(p.second);
return *this;
}
void swap(pair& p)
{ std::swap(*this, p); }
};
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); }
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);
}
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_PAIR_HPP

View File

@@ -0,0 +1,101 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP
#define BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
#error "This file is not needed when perfect forwarding is available"
#endif
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#define BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS 10
//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
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \
//!
#else
#define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \
const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \
//!
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_CONTAINERS_PARAM(U, u) \
U && u \
//!
#else
#define BOOST_CONTAINERS_PARAM(U, u) \
const U & u \
//!
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \
//!
#else
#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \
//!
#endif
#define BOOST_CONTAINERS_AUX_PARAM_INC(z, n, data) \
BOOST_PP_CAT(++m_p, n) \
//!
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \
//!
#else
#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
//!
#endif
#define BOOST_CONTAINERS_PP_PARAM_FORWARD(z, n, data) \
boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \
//!
#define BOOST_CONTAINERS_PP_MEMBER_FORWARD(z, n, data) \
boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \
//!
#define BOOST_CONTAINERS_PP_MEMBER_IT_FORWARD(z, n, data) \
BOOST_PP_CAT(*m_p, n) \
//!
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#else
#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING
#error "This file is not needed when perfect forwarding is available"
#endif
#endif //#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP

View File

@@ -0,0 +1,176 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP
#define BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
#include <iterator>
namespace boost {
namespace interprocess_container {
template <class PseudoReference>
struct operator_arrow_proxy
{
operator_arrow_proxy(const PseudoReference &px)
: m_value(px)
{}
PseudoReference* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable PseudoReference m_value;
};
template <class T>
struct operator_arrow_proxy<T&>
{
operator_arrow_proxy(T &px)
: m_value(px)
{}
T* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable T &m_value;
};
template <class Iterator, class UnaryFunction>
class transform_iterator
: public UnaryFunction
, public std::iterator
< typename Iterator::iterator_category
, typename containers_detail::remove_reference<typename UnaryFunction::result_type>::type
, typename Iterator::difference_type
, operator_arrow_proxy<typename UnaryFunction::result_type>
, typename UnaryFunction::result_type>
{
public:
explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
: UnaryFunction(f), m_it(it)
{}
explicit transform_iterator()
: UnaryFunction(), m_it()
{}
//Constructors
transform_iterator& operator++()
{ increment(); return *this; }
transform_iterator operator++(int)
{
transform_iterator result (*this);
increment();
return result;
}
friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i == i2); }
/*
friend bool operator> (const transform_iterator& i, const transform_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i < i2); }
*/
friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(typename Iterator::difference_type off)
{ this->advance(off); return *this; }
transform_iterator operator+(typename Iterator::difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
{ return right + off; }
transform_iterator& operator-=(typename Iterator::difference_type off)
{ this->advance(-off); return *this; }
transform_iterator operator-(typename Iterator::difference_type off) const
{ return *this + (-off); }
typename UnaryFunction::result_type operator*() const
{ return dereference(); }
operator_arrow_proxy<typename UnaryFunction::result_type>
operator->() const
{ return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
Iterator & base()
{ return m_it; }
const Iterator & base() const
{ return m_it; }
private:
Iterator m_it;
void increment()
{ ++m_it; }
void decrement()
{ --m_it; }
bool equal(const transform_iterator &other) const
{ return m_it == other.m_it; }
bool less(const transform_iterator &other) const
{ return other.m_it < m_it; }
typename UnaryFunction::result_type dereference() const
{ return UnaryFunction::operator()(*m_it); }
void advance(typename Iterator::difference_type n)
{ std::advance(m_it, n); }
typename Iterator::difference_type distance_to(const transform_iterator &other)const
{ return std::distance(other.m_it, m_it); }
};
template <class Iterator, class UnaryFunc>
transform_iterator<Iterator, UnaryFunc>
make_transform_iterator(Iterator it, UnaryFunc fun)
{
return transform_iterator<Iterator, UnaryFunc>(it, fun);
}
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
//////////////////////////////////////////////////////////////////////////////
// (C) Copyright John Maddock 2000.
// (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/container for documentation.
//
// The alignment_of implementation comes from John Maddock's boost::alignment_of code
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP
#define BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
struct nat{};
//boost::alignment_of yields to 10K lines of preprocessed code, so we
//need an alternative
template <typename T> struct alignment_of;
template <typename T>
struct alignment_of_hack
{
char c;
T t;
alignment_of_hack();
};
template <unsigned A, unsigned S>
struct alignment_logic
{
enum{ value = A < S ? A : S };
};
template< typename T >
struct alignment_of
{
enum{ value = alignment_logic
< sizeof(alignment_of_hack<T>) - sizeof(T)
, sizeof(T)>::value };
};
//This is not standard, but should work with all compilers
union max_align
{
char char_;
short short_;
int int_;
long long_;
#ifdef BOOST_HAS_LONG_LONG
long long long_long_;
#endif
float float_;
double double_;
long double long_double_;
void * void_ptr_;
};
template<class T>
struct remove_reference
{
typedef T type;
};
template<class T>
struct remove_reference<T&>
{
typedef T type;
};
template<class T>
struct is_reference
{
enum { value = false };
};
template<class T>
struct is_reference<T&>
{
enum { value = true };
};
template<class T>
struct is_pointer
{
enum { value = false };
};
template<class T>
struct is_pointer<T*>
{
enum { value = true };
};
template <typename T>
struct add_reference
{
typedef T& type;
};
template<class T>
struct add_reference<T&>
{
typedef T& type;
};
template<>
struct add_reference<void>
{
typedef nat &type;
};
template<>
struct add_reference<const void>
{
typedef const nat &type;
};
template <class T>
struct add_const_reference
{ typedef const T &type; };
template <class T>
struct add_const_reference<T&>
{ typedef T& type; };
template <typename T, typename U>
struct is_same
{
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <typename V>
static yes_type is_same_tester(V*, V*);
static no_type is_same_tester(...);
static T *t;
static U *u;
static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
};
} // namespace containers_detail
} //namespace interprocess_container {
} //namespace boost {
#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP
#include <boost/interprocess/containers/container/detail/config_end.hpp>

View File

@@ -0,0 +1,95 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP
#define BOOST_CONTAINERS_DETAIL_UTILITIES_HPP
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <cstdio>
#include <algorithm>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
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;
}
template<class T>
const T &max_value(const T &a, const T &b)
{ return a > b ? a : b; }
template<class T>
const T &min_value(const T &a, const T &b)
{ return a < b ? a : b; }
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);
}
template <std::size_t OrigSize, std::size_t RoundTo>
struct ct_rounded_size
{
enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo };
};
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP

View File

@@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2009.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP
#define BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
namespace boost {
namespace interprocess_container {
namespace containers_detail {
template<class T>
struct value_init
{
value_init()
: m_t()
{}
T m_t;
};
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP

View File

@@ -0,0 +1,153 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#define BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/workaround.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
#include <cstddef> //std::size_t
namespace boost {
namespace interprocess_container {
namespace containers_detail {
template<typename... Values>
class tuple;
template<> class tuple<>
{};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
: private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() { }
// implicit copy-constructor is okay
// Construct tuple from separate arguments.
tuple(typename add_const_reference<Head>::type v,
typename add_const_reference<Tail>::type... vtail)
: inherited(vtail...), m_head(v)
{}
// Construct tuple from another tuple.
template<typename... VValues>
tuple(const tuple<VValues...>& other)
: m_head(other.head()), inherited(other.tail())
{}
template<typename... VValues>
tuple& operator=(const tuple<VValues...>& other)
{
m_head = other.head();
tail() = other.tail();
return this;
}
typename add_reference<Head>::type head() { return m_head; }
typename add_reference<const Head>::type head() const { return m_head; }
inherited& tail() { return *this; }
const inherited& tail() const { return *this; }
protected:
Head m_head;
};
template<typename... Values>
tuple<Values&&...> tie_forward(Values&&... values)
{ return tuple<Values&&...>(values...); }
template<int I, typename Tuple>
struct tuple_element;
template<int I, typename Head, typename... Tail>
struct tuple_element<I, tuple<Head, Tail...> >
{
typedef typename tuple_element<I-1, tuple<Tail...> >::type type;
};
template<typename Head, typename... Tail>
struct tuple_element<0, tuple<Head, Tail...> >
{
typedef Head type;
};
template<int I, typename Tuple>
class get_impl;
template<int I, typename Head, typename... Values>
class get_impl<I, tuple<Head, Values...> >
{
typedef typename tuple_element<I-1, tuple<Values...> >::type Element;
typedef get_impl<I-1, tuple<Values...> > Next;
public:
typedef typename add_reference<Element>::type type;
typedef typename add_const_reference<Element>::type const_type;
static type get(tuple<Head, Values...>& t) { return Next::get(t.tail()); }
static const_type get(const tuple<Head, Values...>& t) { return Next::get(t.tail()); }
};
template<typename Head, typename... Values>
class get_impl<0, tuple<Head, Values...> >
{
public:
typedef typename add_reference<Head>::type type;
typedef typename add_const_reference<Head>::type const_type;
static type get(tuple<Head, Values...>& t) { return t.head(); }
static const_type get(const tuple<Head, Values...>& t){ return t.head(); }
};
template<int I, typename... Values>
typename get_impl<I, tuple<Values...> >::type get(tuple<Values...>& t)
{ return get_impl<I, tuple<Values...> >::get(t); }
template<int I, typename... Values>
typename get_impl<I, tuple<Values...> >::const_type get(const tuple<Values...>& t)
{ return get_impl<I, tuple<Values...> >::get(t); }
////////////////////////////////////////////////////
// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will
// be used to "unpack" into comma-separated values
// in a function call.
////////////////////////////////////////////////////
template<int... Indexes>
struct index_tuple{};
template<std::size_t Num, typename Tuple = index_tuple<> >
struct build_number_seq;
template<std::size_t Num, int... Indexes>
struct build_number_seq<Num, index_tuple<Indexes...> >
: build_number_seq<Num - 1, index_tuple<Indexes..., sizeof...(Indexes)> >
{};
template<int... Indexes>
struct build_number_seq<0, index_tuple<Indexes...> >
{ typedef index_tuple<Indexes...> type; };
}}} //namespace boost { namespace interprocess_container { namespace containers_detail {
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP

View File

@@ -0,0 +1,89 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// This code comes from N1953 document by Howard E. Hinnant
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP
#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP
#include <boost/interprocess/containers/container/detail/mpl.hpp>
#include <boost/interprocess/containers/container/detail/type_traits.hpp>
namespace boost{
namespace interprocess_container {
namespace containers_detail {
//using namespace boost;
template <class T, unsigned V>
struct version_type
: public containers_detail::integral_constant<unsigned, V>
{
typedef T type;
version_type(const version_type<T, 0>&);
};
namespace impl{
template <class T,
bool = containers_detail::is_convertible<version_type<T, 0>, typename T::version>::value>
struct extract_version
{
static const unsigned value = 1;
};
template <class T>
struct extract_version<T, true>
{
static const unsigned value = T::version::value;
};
template <class T>
struct has_version
{
private:
struct two {char _[2];};
template <class U> static two test(...);
template <class U> static char test(const typename U::version*);
public:
static const bool value = sizeof(test<T>(0)) == 1;
void dummy(){}
};
template <class T, bool = has_version<T>::value>
struct version
{
static const unsigned value = 1;
};
template <class T>
struct version<T, true>
{
static const unsigned value = extract_version<T>::value;
};
} //namespace impl
template <class T>
struct version
: public containers_detail::integral_constant<unsigned, impl::version<T>::value>
{
};
} //namespace containers_detail {
} //namespace interprocess_container {
} //namespace boost{
#endif //#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP

View File

@@ -0,0 +1,24 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP
#define BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP
#include <boost/interprocess/containers/container/detail/config_begin.hpp>
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\
&& !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL)
#define BOOST_CONTAINERS_PERFECT_FORWARDING
#endif
#include <boost/interprocess/containers/container/detail/config_end.hpp>
#endif //#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/deque.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::deque;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP
#define BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/flat_map.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::flat_map;
using boost::interprocess_container::flat_multimap;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP
#define BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/flat_set.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::flat_set;
using boost::interprocess_container::flat_multiset;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP
#define BOOST_INTERPROCESS_CONTAINERS_LIST_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/list.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::list;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP
#define BOOST_INTERPROCESS_CONTAINERS_MAP_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/map.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::map;
using boost::interprocess_container::multimap;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/pair.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::containers_detail::pair;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP
#define BOOST_INTERPROCESS_CONTAINERS_SET_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/set.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::set;
using boost::interprocess_container::multiset;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP

View File

@@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP
#define BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/slist.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::slist;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP

View File

@@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/stable_vector.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::stable_vector;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/string.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::basic_string;
using boost::interprocess_container::string;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP

View File

@@ -0,0 +1,32 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/vector.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::vector;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/containers/container/detail/version_type.hpp>
namespace boost {
namespace interprocess {
using boost::interprocess_container::containers_detail::version_type;
using boost::interprocess_container::containers_detail::version;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP

View File

@@ -0,0 +1,73 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_CREATION_TAGS_HPP
#define BOOST_INTERPROCESS_CREATION_TAGS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
//!Tag to indicate that the resource must
//!be only created
struct create_only_t {};
//!Tag to indicate that the resource must
//!be only opened
struct open_only_t {};
//!Tag to indicate that the resource must
//!be only opened for reading
struct open_read_only_t {};
//!Tag to indicate that the resource must
//!be only opened for reading
struct open_copy_on_write_t {};
//!Tag to indicate that the resource must
//!be created. If already created, it must be opened.
struct open_or_create_t {};
//!Value to indicate that the resource must
//!be only created
static const create_only_t create_only = create_only_t();
//!Value to indicate that the resource must
//!be only opened
static const open_only_t open_only = open_only_t();
//!Value to indicate that the resource must
//!be only opened for reading
static const open_read_only_t open_read_only = open_read_only_t();
//!Value to indicate that the resource must
//!be created. If already created, it must be opened.
static const open_or_create_t open_or_create = open_or_create_t();
//!Value to indicate that the resource must
//!be only opened for reading
static const open_copy_on_write_t open_copy_on_write = open_copy_on_write_t();
namespace detail {
enum create_enum_t
{ DoCreate, DoOpen, DoOpenOrCreate };
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_CREATION_TAGS_HPP

View File

@@ -0,0 +1,472 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2008
// (C) Copyright Markus Schoepflin 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_DETAIL_ATOMIC_HPP
#define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/cstdint.hpp>
namespace boost{
namespace interprocess{
namespace detail{
//! Atomically increment an apr_uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem);
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem);
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val);
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with": what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
inline boost::uint32_t atomic_cas32
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp);
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#if (defined BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/detail/win32_api.hpp>
namespace boost{
namespace interprocess{
namespace detail{
//! Atomically decrement an boost::uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ return winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; }
//! Atomically increment an apr_uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ return winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), val); }
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with": what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
inline boost::uint32_t atomic_cas32
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{ return winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), with, cmp); }
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
namespace boost {
namespace interprocess {
namespace detail{
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with" what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
inline boost::uint32_t atomic_cas32
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{
boost::uint32_t prev = cmp;
asm volatile( "lock\n\t"
"cmpxchg %3,%1"
: "=a" (prev), "=m" (*(mem))
: "0" (prev), "r" (with)
: "memory", "cc");
return prev;
/*
boost::uint32_t prev;
asm volatile ("lock; cmpxchgl %1, %2"
: "=a" (prev)
: "r" (with), "m" (*(mem)), "0"(cmp));
asm volatile("" : : : "memory");
return prev;
*/
}
//! Atomically add 'val' to an boost::uint32_t
//! "mem": pointer to the object
//! "val": amount to add
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_add32
(volatile boost::uint32_t *mem, boost::uint32_t val)
{
// int r = *pw;
// *mem += val;
// return r;
int r;
asm volatile
(
"lock\n\t"
"xadd %1, %0":
"+m"( *mem ), "=r"( r ): // outputs (%0, %1)
"1"( val ): // inputs (%2 == %1)
"memory", "cc" // clobbers
);
return r;
/*
asm volatile( "lock\n\t; xaddl %0,%1"
: "=r"(val), "=m"(*mem)
: "0"(val), "m"(*mem));
asm volatile("" : : : "memory");
return val;
*/
}
//! Atomically increment an apr_uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ return atomic_add32(mem, 1); }
//! Atomically decrement an boost::uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ return atomic_add32(mem, (boost::uint32_t)-1); }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ *mem = val; }
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__))
namespace boost {
namespace interprocess {
namespace detail{
//! Atomically add 'val' to an boost::uint32_t
//! "mem": pointer to the object
//! "val": amount to add
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val)
{
boost::uint32_t prev, temp;
asm volatile ("0:\n\t" // retry local label
"lwarx %0,0,%2\n\t" // load prev and reserve
"add %1,%0,%3\n\t" // temp = prev + val
"stwcx. %1,0,%2\n\t" // conditionally store
"bne- 0b" // start over if we lost
// the reservation
//XXX find a cleaner way to define the temp
//it's not an output
: "=&r" (prev), "=&r" (temp) // output, temp
: "b" (mem), "r" (val) // inputs
: "memory", "cc"); // clobbered
return prev;
}
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with" what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
inline boost::uint32_t atomic_cas32
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{
boost::uint32_t prev;
asm volatile ("0:\n\t" // retry local label
"lwarx %0,0,%1\n\t" // load prev and reserve
"cmpw %0,%3\n\t" // does it match cmp?
"bne- 1f\n\t" // ...no, bail out
"stwcx. %2,0,%1\n\t" // ...yes, conditionally
// store with
"bne- 0b\n\t" // start over if we lost
// the reservation
"1:" // exit local label
: "=&r"(prev) // output
: "b" (mem), "r" (with), "r"(cmp) // inputs
: "memory", "cc"); // clobbered
return prev;
}
//! Atomically increment an apr_uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ return atomic_add32(mem, 1); }
//! Atomically decrement an boost::uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ return atomic_add32(mem, boost::uint32_t(-1u)); }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ *mem = val; }
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
namespace boost {
namespace interprocess {
namespace detail{
//! Atomically add 'val' to an boost::uint32_t
//! "mem": pointer to the object
//! "val": amount to add
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_add32
(volatile boost::uint32_t *mem, boost::uint32_t val)
{ return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); }
//! Atomically increment an apr_uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ return atomic_add32(mem, 1); }
//! Atomically decrement an boost::uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ return atomic_add32(mem, (boost::uint32_t)-1); }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with" what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
inline boost::uint32_t atomic_cas32
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{ return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), with, cmp); }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ *mem = val; }
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#elif (defined(sun) || defined(__sun))
#include <atomic.h>
namespace boost{
namespace interprocess{
namespace detail{
//! Atomically add 'val' to an boost::uint32_t
//! "mem": pointer to the object
//! "val": amount to add
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (int32_t)val) - val; }
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with" what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
inline boost::uint32_t atomic_cas32
(volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{ return atomic_cas_32(reinterpret_cast<volatile ::uint32_t*>(mem), cmp, with); }
//! Atomically increment an apr_uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), 1) - 1; }
//! Atomically decrement an boost::uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (boost::uint32_t)-1) + 1; }
//! Atomically read an boost::uint32_t from memory
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ return *mem; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ *mem = val; }
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#elif defined(__osf__) && defined(__DECCXX)
#include <machine/builtins.h>
#include <c_asm.h>
namespace boost{
namespace interprocess{
namespace detail{
//! Atomically decrement a uint32_t by 1
//! "mem": pointer to the atomic value
//! Returns the old value pointed to by mem
//! Acquire, memory barrier after decrement.
inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
{ boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; }
//! Atomically increment a uint32_t by 1
//! "mem": pointer to the object
//! Returns the old value pointed to by mem
//! Release, memory barrier before increment.
inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
{ __MB(); return __ATOMIC_INCREMENT_LONG(mem); }
// Rational for the implementation of the atomic read and write functions.
//
// 1. The Alpha Architecture Handbook requires that access to a byte,
// an aligned word, an aligned longword, or an aligned quadword is
// atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.)
//
// 2. The CXX User's Guide states that volatile quantities are accessed
// with single assembler instructions, and that a compilation error
// occurs when declaring a quantity as volatile which is not properly
// aligned.
//! Atomically read an boost::uint32_t from memory
//! Acquire, memory barrier after load.
inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
{ boost::uint32_t old_val = *mem; __MB(); return old_val; }
//! Atomically set an boost::uint32_t in memory
//! "mem": pointer to the object
//! "param": val value that the object will assume
//! Release, memory barrier before store.
inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
{ __MB(); *mem = val; }
//! Compare an boost::uint32_t's value with "cmp".
//! If they are the same swap the value with "with"
//! "mem": pointer to the value
//! "with" what to swap it with
//! "cmp": the value to compare it to
//! Returns the old value of *mem
//! Memory barrier between load and store.
inline boost::uint32_t atomic_cas32(
volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
{
// Note:
//
// Branch prediction prefers backward branches, and the Alpha Architecture
// Handbook explicitely states that the loop should not be implemented like
// it is below. (See chapter 4.2.5.) Therefore the code should probably look
// like this:
//
// return asm(
// "10: ldl_l %v0,(%a0) ;"
// " cmpeq %v0,%a2,%t0 ;"
// " beq %t0,20f ;"
// " mb ;"
// " mov %a1,%t0 ;"
// " stl_c %t0,(%a0) ;"
// " beq %t0,30f ;"
// "20: ret ;"
// "30: br 10b;",
// mem, with, cmp);
//
// But as the compiler always transforms this into the form where a backward
// branch is taken on failure, we can as well implement it in the straight
// forward form, as this is what it will end up in anyway.
return asm(
"10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem
" cmpeq %v0,%a2,%t0 ;" // compare with given value
" beq %t0,20f ;" // if not equal, we're done
" mb ;" // memory barrier
" mov %a1,%t0 ;" // load new value into scratch register
" stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch)
" beq %t0,10b ;" // store failed because lock has been stolen, retry
"20: ",
mem, with, cmp);
}
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#else
#error No atomic operations implemented for this platform, sorry!
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP

View File

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

View File

@@ -0,0 +1,47 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_CONFIG_INCLUDED
#define BOOST_INTERPROCESS_CONFIG_INCLUDED
#include <boost/config.hpp>
#endif
#ifdef BOOST_MSVC
#ifndef _CRT_SECURE_NO_DEPRECATE
#define BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#pragma warning (push)
#pragma warning (disable : 4702) // unreachable code
#pragma warning (disable : 4706) // assignment within conditional expression
#pragma warning (disable : 4127) // conditional expression is constant
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
#pragma warning (disable : 4284) // odd return type for operator->
#pragma warning (disable : 4244) // possible loss of data
#pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2"
#pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data
#pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier"
#pragma warning (disable : 4355) // "this" : used in base member initializer list
#pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated
#pragma warning (disable : 4511) // copy constructor could not be generated
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4514) // unreferenced inline removed
#pragma warning (disable : 4521) // Disable "multiple copy constructors specified"
#pragma warning (disable : 4522) // "class" : multiple assignment operators specified
#pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter
#pragma warning (disable : 4710) // function not inlined
#pragma warning (disable : 4711) // function selected for automatic inline expansion
#pragma warning (disable : 4786) // identifier truncated in debug info
#pragma warning (disable : 4996) // "function": was declared deprecated
#pragma warning (disable : 4197) // top-level volatile in cast is ignored
#pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception'
// with /GR-; unpredictable behavior may result
#pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site
#pragma warning (disable : 4671) // the copy constructor is inaccessible
#endif

View File

@@ -0,0 +1,17 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
//////////////////////////////////////////////////////////////////////////////
#if defined BOOST_MSVC
#pragma warning (pop)
#ifdef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
#undef BOOST_INTERPROCESS_CRT_SECURE_NO_DEPRECATE
#undef _CRT_SECURE_NO_DEPRECATE
#endif
#endif

View File

@@ -0,0 +1,202 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_FILE_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/creation_tags.hpp>
namespace boost {
namespace interprocess {
namespace detail{
class file_wrapper
{
/// @cond
file_wrapper(file_wrapper&);
file_wrapper & operator=(file_wrapper&);
/// @endcond
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_wrapper)
//!Default constructor.
//!Represents an empty file_wrapper.
file_wrapper();
//!Creates a file object with name "name" and mode "mode", with the access mode "mode"
//!If the file previously exists, throws an error.
file_wrapper(create_only_t, const char *name, mode_t mode)
{ this->priv_open_or_create(detail::DoCreate, name, mode); }
//!Tries to create a file with name "name" and mode "mode", with the
//!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
//!Otherwise throws an error.
file_wrapper(open_or_create_t, const char *name, mode_t mode)
{ this->priv_open_or_create(detail::DoOpenOrCreate, name, mode); }
//!Tries to open a file with name "name", with the access mode "mode".
//!If the file does not previously exist, it throws an error.
file_wrapper(open_only_t, const char *name, mode_t mode)
{ this->priv_open_or_create(detail::DoOpen, name, mode); }
//!Moves the ownership of "moved"'s file to *this.
//!After the call, "moved" does not represent any file.
//!Does not throw
file_wrapper(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved)
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file to *this.
//!After the call, "moved" does not represent any file.
//!Does not throw
file_wrapper &operator=(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved)
{
file_wrapper tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps to file_wrappers.
//!Does not throw
void swap(file_wrapper &other);
//!Erases a file from the system.
//!Returns false on error. Never throws
static bool remove(const char *name);
//!Sets the size of the file
void truncate(offset_t length);
//!Closes the
//!file
~file_wrapper();
//!Returns the name of the file
//!used in the constructor
const char *get_name() const;
//!Returns the name of the file
//!used in the constructor
bool get_size(offset_t &size) const;
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Get mapping handle
//!to use with mapped_region
mapping_handle_t get_mapping_handle() const;
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Closes a previously opened file mapping. Never throws.
bool priv_open_or_create(detail::create_enum_t type, const char *filename, mode_t mode);
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
};
inline file_wrapper::file_wrapper()
: m_handle(file_handle_t(detail::invalid_file()))
{}
inline file_wrapper::~file_wrapper()
{ this->priv_close(); }
inline const char *file_wrapper::get_name() const
{ return m_filename.c_str(); }
inline bool file_wrapper::get_size(offset_t &size) const
{ return get_file_size((file_handle_t)m_handle, size); }
inline void file_wrapper::swap(file_wrapper &other)
{
std::swap(m_handle, other.m_handle);
std::swap(m_mode, other.m_mode);
m_filename.swap(other.m_filename);
}
inline mapping_handle_t file_wrapper::get_mapping_handle() const
{ return mapping_handle_from_file_handle(m_handle); }
inline mode_t file_wrapper::get_mode() const
{ return m_mode; }
inline bool file_wrapper::priv_open_or_create
(detail::create_enum_t type,
const char *filename,
mode_t mode)
{
m_filename = filename;
if(mode != read_only && mode != read_write){
error_info err(mode_error);
throw interprocess_exception(err);
}
//Open file existing native API to obtain the handle
switch(type){
case detail::DoOpen:
m_handle = open_existing_file(filename, mode);
break;
case detail::DoCreate:
m_handle = create_new_file(filename, mode);
break;
case detail::DoOpenOrCreate:
m_handle = create_or_open_file(filename, mode);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == invalid_file()){
throw interprocess_exception(error_info(system_error_code()));
}
m_mode = mode;
return true;
}
inline bool file_wrapper::remove(const char *filename)
{ return delete_file(filename); }
inline void file_wrapper::truncate(offset_t length)
{
if(!truncate_file(m_handle, length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void file_wrapper::priv_close()
{
if(m_handle != invalid_file()){
close_file(m_handle);
m_handle = invalid_file();
}
}
} //namespace detail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP

View File

@@ -0,0 +1,72 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_IN_PLACE_INTERFACE_HPP
#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_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/type_traits.hpp>
#include <typeinfo> //typeid
//!\file
//!Describes an abstract interface for placement construction and destruction.
namespace boost {
namespace interprocess {
namespace detail {
struct in_place_interface
{
in_place_interface(std::size_t alignm, std::size_t sz, const char *tname)
: alignment(alignm), size(sz), type_name(tname)
{}
std::size_t alignment;
std::size_t size;
const char *type_name;
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) = 0;
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) = 0;
virtual ~in_place_interface(){}
};
template<class T>
struct placement_destroy : public in_place_interface
{
placement_destroy()
: in_place_interface(detail::alignment_of<T>::value, sizeof(T), typeid(T).name())
{}
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed)
{
T* memory = static_cast<T*>(mem);
for(destroyed = 0; destroyed < num; ++destroyed)
(memory++)->~T();
}
virtual void construct_n(void *, std::size_t, std::size_t &) {}
private:
void destroy(void *mem)
{ static_cast<T*>(mem)->~T(); }
};
}
}
} //namespace boost { namespace interprocess { namespace detail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP

View File

@@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP
#define BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP
namespace boost{
namespace interprocess{
namespace detail{
class interprocess_tester
{
public:
template<class T>
static void dont_close_on_destruction(T &t)
{ t.dont_close_on_destruction(); }
};
} //namespace detail{
} //namespace interprocess{
} //namespace boost{
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_INTERPROCESS_TESTER_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,743 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_MANAGED_MEMORY_IMPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
#include <boost/interprocess/sync/mutex_family.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/segment_manager.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
//
#include <boost/detail/no_exceptions_support.hpp>
//
#include <utility>
#include <fstream>
#include <new>
#include <cassert>
//!\file
//!Describes a named shared memory allocation user class.
//!
namespace boost {
namespace interprocess {
namespace detail {
template<class BasicManagedMemoryImpl>
class create_open_func;
template<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
struct segment_manager_type
{
typedef segment_manager<CharType, MemoryAlgorithm, IndexType> type;
};
//!This class is designed to be a base class to classes that manage
//!creation of objects in a fixed size memory buffer. Apart
//!from allocating raw memory, the user can construct named objects. To
//!achieve this, this class uses the reserved space provided by the allocation
//!algorithm to place a named_allocator_algo, who takes care of name mappings.
//!The class can be customized with the char type used for object names
//!and the memory allocation algorithm to be used.*/
template < class CharType
, class MemoryAlgorithm
, template<class IndexConfig> class IndexType
, std::size_t Offset = 0
>
class basic_managed_memory_impl
{
//Non-copyable
basic_managed_memory_impl(const basic_managed_memory_impl &);
basic_managed_memory_impl &operator=(const basic_managed_memory_impl &);
template<class BasicManagedMemoryImpl>
friend class create_open_func;
public:
typedef typename segment_manager_type
<CharType, MemoryAlgorithm, IndexType>::type segment_manager;
typedef CharType char_type;
typedef MemoryAlgorithm memory_algorithm;
typedef typename MemoryAlgorithm::mutex_family mutex_family;
typedef CharType char_t;
typedef std::ptrdiff_t handle_t;
typedef typename segment_manager::
const_named_iterator const_named_iterator;
typedef typename segment_manager::
const_unique_iterator const_unique_iterator;
/// @cond
typedef typename
segment_manager::char_ptr_holder_t char_ptr_holder_t;
//Experimental. Don't use.
typedef typename segment_manager::multiallocation_chain multiallocation_chain;
/// @endcond
static const std::size_t PayloadPerAllocation = segment_manager::PayloadPerAllocation;
private:
typedef basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType, Offset> self_t;
protected:
template<class ManagedMemory>
static bool grow(const char *filename, std::size_t extra_bytes)
{
typedef typename ManagedMemory::device_type device_type;
//Increase file size
try{
offset_t old_size;
{
device_type f(open_or_create, filename, read_write);
if(!f.get_size(old_size))
return false;
f.truncate(old_size + extra_bytes);
}
ManagedMemory managed_memory(open_only, filename);
//Grow always works
managed_memory.self_t::grow(extra_bytes);
}
catch(...){
return false;
}
return true;
}
template<class ManagedMemory>
static bool shrink_to_fit(const char *filename)
{
typedef typename ManagedMemory::device_type device_type;
std::size_t new_size, old_size;
try{
ManagedMemory managed_memory(open_only, filename);
old_size = managed_memory.get_size();
managed_memory.self_t::shrink_to_fit();
new_size = managed_memory.get_size();
}
catch(...){
return false;
}
//Decrease file size
{
device_type f(open_or_create, filename, read_write);
f.truncate(new_size);
}
return true;
}
//!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)
{
if(mp_header) return false;
mp_header = static_cast<segment_manager*>(addr);
return true;
}
//!Frees resources. Never throws.
bool close_impl()
{
bool ret = mp_header != 0;
mp_header = 0;
return ret;
}
//!Frees resources and destroys common resources. Never throws.
bool destroy_impl()
{
if(mp_header == 0)
return false;
mp_header->~segment_manager();
this->close_impl();
return true;
}
//!
void grow(std::size_t extra_bytes)
{ mp_header->grow(extra_bytes); }
void shrink_to_fit()
{ mp_header->shrink_to_fit(); }
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 reinterpret_cast<char*>(mp_header) - Offset; }
//!Returns the size of memory segment. Never throws.
std::size_t get_size () const
{ return mp_header->get_size() + Offset; }
//!Returns the number of free bytes of the memory
//!segment
std::size_t get_free_memory() const
{ return mp_header->get_free_memory(); }
//!Returns the result of "all_memory_deallocated()" function
//!of the used memory algorithm
bool all_memory_deallocated()
{ return mp_header->all_memory_deallocated(); }
//!Returns the result of "check_sanity()" function
//!of the used memory algorithm
bool check_sanity()
{ return mp_header->check_sanity(); }
//!Writes to zero free memory (memory not yet allocated) of
//!the memory algorithm
void zero_free_memory()
{ mp_header->zero_free_memory(); }
//!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 reinterpret_cast<const char*>(ptr) -
reinterpret_cast<const char*>(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 < (reinterpret_cast<const char*>(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 reinterpret_cast<char*>(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 returns 0. Never throws.
void* allocate (std::size_t nbytes, std::nothrow_t nothrow)
{ return mp_header->allocate(nbytes, nothrow); }
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
//!must be power of two. If no memory
//!is available returns 0. Never throws.
void * allocate_aligned (std::size_t nbytes, std::size_t alignment, std::nothrow_t nothrow)
{ return mp_header->allocate_aligned(nbytes, alignment, nothrow); }
template<class T>
std::pair<T *, bool>
allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size,
std::size_t preferred_size,std::size_t &received_size,
T *reuse_ptr = 0)
{
return mp_header->allocation_command
(command, limit_size, preferred_size, received_size, reuse_ptr);
}
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
//!must be power of two. If no
//!memory is available throws a boost::interprocess::bad_alloc exception
void * allocate_aligned(std::size_t nbytes, std::size_t alignment)
{ return mp_header->allocate_aligned(nbytes, alignment); }
/// @cond
//Experimental. Don't use.
//!Allocates n_elements of elem_size bytes.
multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements)
{ return mp_header->allocate_many(elem_bytes, num_elements); }
//!Allocates n_elements, each one of elem_sizes[i] bytes.
multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements)
{ return mp_header->allocate_many(elem_sizes, n_elements); }
//!Allocates n_elements of elem_size bytes.
multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t nothrow)
{ return mp_header->allocate_many(elem_bytes, num_elements, nothrow); }
//!Allocates n_elements, each one of elem_sizes[i] bytes.
multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow)
{ return mp_header->allocate_many(elem_sizes, n_elements, nothrow); }
//!Allocates n_elements, each one of elem_sizes[i] bytes.
void deallocate_many(multiallocation_chain chain)
{ return mp_header->deallocate_many(boost::interprocess::move(chain)); }
/// @endcond
//!Marks previously allocated memory as free. Never throws.
void deallocate (void *addr)
{ if (mp_header) mp_header->deallocate(addr); }
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, std::size_t> find (char_ptr_holder_t name)
{ return mp_header->template find<T>(name); }
//!Creates a named object or array in memory
//!
//!Allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name)
{ return mp_header->template construct<T>(name); }
//!Finds or creates a named object or array in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name)
{ return mp_header->template find_or_construct<T>(name); }
//!Creates a named object or array in memory
//!
//!Allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Returns 0 if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->template construct<T>(name, nothrow); }
//!Finds or creates a named object or array in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> Returns 0 if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->template find_or_construct<T>(name, nothrow); }
//!Creates a named array from iterators in memory
//!
//!Allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
construct_it(char_ptr_holder_t name)
{ return mp_header->template construct_it<T>(name); }
//!Finds or creates a named array from iterators in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
find_or_construct_it(char_ptr_holder_t name)
{ return mp_header->template find_or_construct_it<T>(name); }
//!Creates a named array from iterators in memory
//!
//!Allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
construct_it(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->template construct_it<T>(name, nothrow); }
//!Finds or creates a named array from iterators in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
find_or_construct_it(char_ptr_holder_t name, std::nothrow_t nothrow)
{ return mp_header->template find_or_construct_it<T>(name, nothrow); }
//!Calls a functor and guarantees that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the functor throws, this function throws.
template <class Func>
void atomic_func(Func &f)
{ mp_header->atomic_func(f); }
//!Destroys a named memory object or array.
//!
//!Finds the object with the given name, calls its destructors,
//!frees used memory and returns true.
//!
//!-> If the object is not found, it returns false.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object or array, the Standard
//!does not guarantee that dynamically allocated memory, will be released.
//!Also, when deleting arrays, the Standard doesn't require calling
//!destructors for the rest of the objects if for one of them the destructor
//!terminated with an exception.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!Destroying an array:
//!
//!When destroying an array, if a destructor throws, the rest of
//!destructors are called. If any of these throws, the exceptions are
//!ignored. The name association will be erased, memory will be freed and
//!the first exception will be thrown. This guarantees the unlocking of
//!mutexes and other resources.
//!
//!For all theses reasons, classes with throwing destructors are not
//!recommended.
template <class T>
bool destroy(const CharType *name)
{ return mp_header->template destroy<T>(name); }
//!Destroys the unique instance of type T
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!For all theses reasons, classes with throwing destructors are not
//!recommended for memory.
template <class T>
bool destroy(const detail::unique_instance_t *const )
{ return mp_header->template destroy<T>(unique_instance); }
//!Destroys the object (named, unique, or anonymous)
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!For all theses reasons, classes with throwing destructors are not
//!recommended for memory.
template <class T>
void destroy_ptr(const T *ptr)
{ mp_header->template destroy_ptr<T>(ptr); }
//!Returns the name of an object created with construct/find_or_construct
//!functions. Does not throw
template<class T>
static const char_type *get_instance_name(const T *ptr)
{ return segment_manager::get_instance_name(ptr); }
//!Returns is the type an object created with construct/find_or_construct
//!functions. Does not throw.
template<class T>
static instance_type get_instance_type(const T *ptr)
{ return segment_manager::get_instance_type(ptr); }
//!Returns the length of an object created with construct/find_or_construct
//!functions (1 if is a single element, >=1 if it's an array). Does not throw.
template<class T>
static std::size_t get_instance_length(const T *ptr)
{ return segment_manager::get_instance_length(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); }
//!Calls shrink_to_fit in both named and unique object indexes
//to try to free unused memory from those indexes.
void shrink_to_fit_indexes()
{ mp_header->shrink_to_fit_indexes(); }
//!Returns the number of named objects stored
//!in the managed segment.
std::size_t get_num_named_objects()
{ return mp_header->get_num_named_objects(); }
//!Returns the number of unique objects stored
//!in the managed segment.
std::size_t get_num_unique_objects()
{ return mp_header->get_num_unique_objects(); }
//!Returns a constant iterator to the index storing the
//!named allocations. NOT thread-safe. Never throws.
const_named_iterator named_begin() const
{ return mp_header->named_begin(); }
//!Returns a constant iterator to the end of the index
//!storing the named allocations. NOT thread-safe. Never throws.
const_named_iterator named_end() const
{ return mp_header->named_end(); }
//!Returns a constant iterator to the index storing the
//!unique allocations. NOT thread-safe. Never throws.
const_unique_iterator unique_begin() const
{ return mp_header->unique_begin(); }
//!Returns a constant iterator to the end of the index
//!storing the unique allocations. NOT thread-safe. Never throws.
const_unique_iterator unique_end() const
{ return mp_header->unique_end(); }
//!This is the default allocator to allocate types T
//!from this managed segment
template<class T>
struct allocator
{
typedef typename segment_manager::template allocator<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename allocator<T>::type
get_allocator()
{ return mp_header->get_allocator<T>(); }
//!This is the default deleter to delete types T
//!from this managed segment.
template<class T>
struct deleter
{
typedef typename segment_manager::template deleter<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename deleter<T>::type
get_deleter()
{ return mp_header->get_deleter<T>(); }
/// @cond
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, std::size_t> find_no_lock (char_ptr_holder_t name)
{ return mp_header->template find_no_lock<T>(name); }
/// @endcond
protected:
//!Swaps the segment manager's managed by this managed memory segment.
//!NOT thread-safe. Never throws.
void swap(basic_managed_memory_impl &other)
{ std::swap(mp_header, other.mp_header); }
private:
segment_manager *mp_header;
};
template<class BasicManagedMemoryImpl>
class create_open_func
{
public:
create_open_func(BasicManagedMemoryImpl * const frontend, detail::create_enum_t type)
: m_frontend(frontend), m_type(type){}
bool operator()(void *addr, std::size_t size, bool created) const
{
if(((m_type == detail::DoOpen) && created) ||
((m_type == detail::DoCreate) && !created))
return false;
if(created)
return m_frontend->create_impl(addr, size);
else
return m_frontend->open_impl (addr, size);
}
private:
BasicManagedMemoryImpl *m_frontend;
detail::create_enum_t m_type;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP

View File

@@ -0,0 +1,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(static_cast<void *>(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
, static_cast<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 &region, bool last) const
{
if(last) mp_frontend->destroy_impl();
else mp_frontend->close_impl();
}
self_t * const mp_frontend;
};
typedef detail::basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType> base_t;
//Friend declarations
friend struct basic_managed_multi_shared_memory::create_open_func;
friend struct basic_managed_multi_shared_memory::close_func;
friend class basic_managed_multi_shared_memory::group_services;
typedef 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 = boost::interprocess::move(shm);
}
break;
case create_open_func::DoOpen:
{
managed_impl shm(open_only, name,read_write, addr, func);
mshm = boost::interprocess::move(shm);
}
break;
case create_open_func::DoOpenOrCreate:
{
managed_impl shm(open_or_create, name, size, read_write, addr, func);
mshm = boost::interprocess::move(shm);
}
break;
default:
return false;
break;
}
//This can throw.
m_shmem_list.push_back(boost::interprocess::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

View File

@@ -0,0 +1,426 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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(managed_open_or_create_impl &);
managed_open_or_create_impl &operator=(managed_open_or_create_impl &);
enum
{
UninitializedSegment,
InitializingSegment,
InitializedSegment,
CorruptedSegment
};
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(managed_open_or_create_impl)
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);
}
managed_open_or_create_impl(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved)
{ this->swap(moved); }
managed_open_or_create_impl &operator=(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved)
{
managed_open_or_create_impl tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
~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 static_cast<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 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(); }
const mapped_region &get_mapped_region() const
{ return m_mapped_region; }
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(static_cast<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( static_cast<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 {
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL

View File

@@ -0,0 +1,110 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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
#include <climits>
#include <boost/static_assert.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)== true));
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

View File

@@ -0,0 +1,40 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_MIN_MAX_HPP
#define BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
namespace boost {
namespace interprocess {
template<class T>
const T &max_value(const T &a, const T &b)
{ return a > b ? a : b; }
template<class T>
const T &min_value(const T &a, const T &b)
{ return a < b ? a : b; }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MIN_MAX_HPP

View File

@@ -0,0 +1,747 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of this file come from Adobe's Move library:
//
// Copyright 2005-2007 Adobe Systems Incorporated
// Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
// or a copy at http://stlab.adobe.com/licenses.html)
//
//////////////////////////////////////////////////////////////////////////////
//! \file
#ifndef BOOST_INTERPROCESS_MOVE_HPP
#define BOOST_INTERPROCESS_MOVE_HPP
#include <boost/config.hpp>
#include <algorithm> //copy, copy_backward
#include <memory> //uninitialized_copy
#include <iterator> //std::iterator
#include <boost/mpl/if.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
namespace boost {
namespace interprocess {
namespace move_detail {
template <class T>
struct identity
{
typedef T type;
};
template <class T, class U>
class is_convertible
{
typedef char true_t;
class false_t { char dummy[2]; };
static true_t dispatch(U);
static false_t dispatch(...);
static T trigger();
public:
enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
};
} //namespace move_detail {
} //namespace interprocess {
} //namespace boost {
#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_MOVE_DOXYGEN_INVOKED)
namespace boost {
namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
//
// struct rv
//
//////////////////////////////////////////////////////////////////////////////
template <class T>
class rv : public T
{
rv();
~rv();
rv(rv const&);
void operator=(rv const&);
public:
//T &get() { return *this; }
};
//////////////////////////////////////////////////////////////////////////////
//
// move_detail::is_rv
//
//////////////////////////////////////////////////////////////////////////////
namespace move_detail {
template <class T>
struct is_rv
{
static const bool value = false;
};
template <class T>
struct is_rv< rv<T> >
{
static const bool value = true;
};
} //namespace move_detail {
//////////////////////////////////////////////////////////////////////////////
//
// is_movable
//
//////////////////////////////////////////////////////////////////////////////
template<class T>
class is_movable
{
public:
static const bool value = move_detail::is_convertible<T, rv<T>&>::value;
};
template<class T>
class is_movable< rv<T> >
{
public:
static const bool value = false;
};
//////////////////////////////////////////////////////////////////////////////
//
// move()
//
//////////////////////////////////////////////////////////////////////////////
template <class T>
typename boost::disable_if<is_movable<T>, T&>::type move(T& x)
{
return x;
}
template <class T>
typename enable_if<is_movable<T>, rv<T>&>::type move(T& x)
{
return reinterpret_cast<rv<T>& >(x);
}
template <class T>
typename enable_if<is_movable<T>, rv<T>&>::type move(const rv<T>& x)
{
return const_cast<rv<T>& >(x);
}
//////////////////////////////////////////////////////////////////////////////
//
// forward()
//
//////////////////////////////////////////////////////////////////////////////
template <class T>
typename enable_if<boost::interprocess::move_detail::is_rv<T>, T &>::type
forward(const typename move_detail::identity<T>::type &x)
{
return const_cast<T&>(x);
}
/*
template <class T>
typename enable_if<boost::interprocess::move_detail::is_rv<T>, T &>::type
forward(typename move_detail::identity<T>::type &x)
{
return x;
}
template <class T>
typename disable_if<boost::interprocess::move_detail::is_rv<T>, T &>::type
forward(typename move_detail::identity<T>::type &x)
{
return x;
}
*/
template <class T>
typename disable_if<boost::interprocess::move_detail::is_rv<T>, const T &>::type
forward(const typename move_detail::identity<T>::type &x)
{
return x;
}
//////////////////////////////////////////////////////////////////////////////
//
// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION
//
//////////////////////////////////////////////////////////////////////////////
#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\
operator boost::interprocess::rv<TYPE>&() \
{ return reinterpret_cast<boost::interprocess::rv<TYPE>& >(*this); }\
//
#define BOOST_INTERPROCESS_RV_REF(TYPE)\
boost::interprocess::rv< TYPE >& \
//
#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\
boost::interprocess::rv< TYPE<ARG1, ARG2> >& \
//
#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\
boost::interprocess::rv< TYPE<ARG1, ARG2, ARG3> >& \
//
#define BOOST_INTERPROCESS_FWD_REF(TYPE)\
const TYPE & \
//
} //namespace interprocess {
} //namespace boost
#else //BOOST_HAS_RVALUE_REFS
#include <boost/type_traits/remove_reference.hpp>
namespace boost {
namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
//
// is_movable
//
//////////////////////////////////////////////////////////////////////////////
//! For compilers with rvalue references, this traits class returns true
//! if T && is convertible to T.
//!
//! For other compilers returns true if T is convertible to <i>boost::interprocess::rv<T>&</i>
template<class T>
class is_movable
{
public:
static const bool value = move_detail::is_convertible<T&&, T>::value;
};
//////////////////////////////////////////////////////////////////////////////
//
// move
//
//////////////////////////////////////////////////////////////////////////////
#if defined(BOOST_MOVE_DOXYGEN_INVOKED)
//! This function provides a way to convert a reference into a rvalue reference
//! in compilers with rvalue reference. For other compilers converts T & into
//! <i>boost::interprocess::rv<T> &</i> so that move emulation is activated.
template <class T> inline
rvalue_reference move (input_reference);
#else
template <class T> inline
typename remove_reference<T>::type&& move(T&& t)
{ return t; }
#endif
//////////////////////////////////////////////////////////////////////////////
//
// forward
//
//////////////////////////////////////////////////////////////////////////////
#if defined(BOOST_MOVE_DOXYGEN_INVOKED)
//! This function provides limited form of forwarding that is usually enough for
//! in-place construction and avoids the exponential overloading necessary for
//! perfect forwarding in C++03.
//!
//! For compilers with rvalue references this function provides perfect forwarding.
//!
//! Otherwise:
//! * If input_reference binds to const boost::interprocess::rv<T> & then it output_reference is
//! boost::rev<T> &
//!
//! * Else, input_reference is equal to output_reference is equal to input_reference.
template <class T> inline output_reference forward(input_reference);
#else
template <class T> inline
T&& forward (typename move_detail::identity<T>::type&& t)
{ return t; }
#endif
//////////////////////////////////////////////////////////////////////////////
//
// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION
//
//////////////////////////////////////////////////////////////////////////////
//! This macro expands to nothing for compilers with rvalue references.
//! Otherwise expands to:
//! \code
//! operator boost::interprocess::rv<TYPE>&()
//! { return static_cast<boost::interprocess::rv<TYPE>& >(*this); }
//! \endcode
#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\
//
#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\
TYPE<ARG1, ARG2> && \
//
#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\
TYPE<ARG1, ARG2, ARG3> && \
//
//! This macro expands to <i>T&&</i> for compilers with rvalue references.
//! Otherwise expands to <i>boost::interprocess::rv<T> &</i>.
#define BOOST_INTERPROCESS_RV_REF(TYPE)\
TYPE && \
//
//! This macro expands to <i>T&&</i> for compilers with rvalue references.
//! Otherwise expands to <i>const T &</i>.
#define BOOST_INTERPROCESS_FWD_REF(TYPE)\
TYPE && \
//
} //namespace interprocess {
} //namespace boost {
#endif //BOOST_HAS_RVALUE_REFS
namespace boost {
namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
//
// move_iterator
//
//////////////////////////////////////////////////////////////////////////////
//! Class template move_iterator is an iterator adaptor with the same behavior
//! as the underlying iterator except that its dereference operator implicitly
//! converts the value returned by the underlying iterator's dereference operator
//! to an rvalue reference. Some generic algorithms can be called with move
//! iterators to replace copying with moving.
template <class It>
class move_iterator
{
public:
typedef It iterator_type;
typedef typename std::iterator_traits<iterator_type>::value_type value_type;
#if defined(BOOST_HAS_RVALUE_REFS) || defined(BOOST_MOVE_DOXYGEN_INVOKED)
typedef value_type && reference;
#else
typedef typename boost::mpl::if_
< boost::interprocess::is_movable<value_type>
, boost::interprocess::rv<value_type>&
, value_type & >::type reference;
#endif
typedef typename std::iterator_traits<iterator_type>::pointer pointer;
typedef typename std::iterator_traits<iterator_type>::difference_type difference_type;
typedef typename std::iterator_traits<iterator_type>::iterator_category iterator_category;
move_iterator()
{}
explicit move_iterator(It i)
: m_it(i)
{}
template <class U>
move_iterator(const move_iterator<U>& u)
: m_it(u.base())
{}
iterator_type base() const
{ return m_it; }
reference operator*() const
{
#if defined(BOOST_HAS_RVALUE_REFS)
return *m_it;
#else
return boost::interprocess::move(*m_it);
#endif
}
pointer operator->() const
{ return m_it; }
move_iterator& operator++()
{ ++m_it; return *this; }
move_iterator<iterator_type> operator++(int)
{ move_iterator<iterator_type> tmp(*this); ++(*this); return tmp; }
move_iterator& operator--()
{ --m_it; return *this; }
move_iterator<iterator_type> operator--(int)
{ move_iterator<iterator_type> tmp(*this); --(*this); return tmp; }
move_iterator<iterator_type> operator+ (difference_type n) const
{ return move_iterator<iterator_type>(m_it + n); }
move_iterator& operator+=(difference_type n)
{ m_it += n; return *this; }
move_iterator<iterator_type> operator- (difference_type n) const
{ return move_iterator<iterator_type>(m_it - n); }
move_iterator& operator-=(difference_type n)
{ m_it -= n; return *this; }
reference operator[](difference_type n) const
{
#if defined(BOOST_HAS_RVALUE_REFS)
return m_it[n];
#else
return boost::interprocess::move(m_it[n]);
#endif
}
friend bool operator==(const move_iterator& x, const move_iterator& y)
{ return x.base() == y.base(); }
friend bool operator!=(const move_iterator& x, const move_iterator& y)
{ return x.base() != y.base(); }
friend bool operator< (const move_iterator& x, const move_iterator& y)
{ return x.base() < y.base(); }
friend bool operator<=(const move_iterator& x, const move_iterator& y)
{ return x.base() <= y.base(); }
friend bool operator> (const move_iterator& x, const move_iterator& y)
{ return x.base() > y.base(); }
friend bool operator>=(const move_iterator& x, const move_iterator& y)
{ return x.base() >= y.base(); }
friend difference_type operator-(const move_iterator& x, const move_iterator& y)
{ return x.base() - y.base(); }
friend move_iterator operator+(difference_type n, const move_iterator& x)
{ return move_iterator(x.base() + n); }
private:
It m_it;
};
//is_move_iterator
namespace move_detail {
template <class I>
struct is_move_iterator
{
static const bool value = false;
};
template <class I>
struct is_move_iterator< ::boost::interprocess::move_iterator<I> >
{
static const bool value = true;
};
} //namespace move_detail {
//////////////////////////////////////////////////////////////////////////////
//
// move_iterator
//
//////////////////////////////////////////////////////////////////////////////
//!
//! <b>Returns</b>: move_iterator<It>(i).
template<class It>
move_iterator<It> make_move_iterator(const It &it)
{ return move_iterator<It>(it); }
//////////////////////////////////////////////////////////////////////////////
//
// back_move_insert_iterator
//
//////////////////////////////////////////////////////////////////////////////
//! A move insert iterator that move constructs elements at the
//! back of a container
template <typename C> // C models Container
class back_move_insert_iterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
C* container_m;
public:
typedef C container_type;
explicit back_move_insert_iterator(C& x) : container_m(&x) { }
back_move_insert_iterator& operator=(typename C::reference x)
{ container_m->push_back(boost::interprocess::move(x)); return *this; }
back_move_insert_iterator& operator*() { return *this; }
back_move_insert_iterator& operator++() { return *this; }
back_move_insert_iterator& operator++(int) { return *this; }
};
//!
//! <b>Returns</b>: back_move_insert_iterator<C>(x).
template <typename C> // C models Container
inline back_move_insert_iterator<C> back_move_inserter(C& x)
{
return back_move_insert_iterator<C>(x);
}
//////////////////////////////////////////////////////////////////////////////
//
// front_move_insert_iterator
//
//////////////////////////////////////////////////////////////////////////////
//! A move insert iterator that move constructs elements int the
//! front of a container
template <typename C> // C models Container
class front_move_insert_iterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
C* container_m;
public:
typedef C container_type;
explicit front_move_insert_iterator(C& x) : container_m(&x) { }
front_move_insert_iterator& operator=(typename C::reference x)
{ container_m->push_front(boost::interprocess::move(x)); return *this; }
front_move_insert_iterator& operator*() { return *this; }
front_move_insert_iterator& operator++() { return *this; }
front_move_insert_iterator& operator++(int) { return *this; }
};
//!
//! <b>Returns</b>: front_move_insert_iterator<C>(x).
template <typename C> // C models Container
inline front_move_insert_iterator<C> front_move_inserter(C& x)
{
return front_move_insert_iterator<C>(x);
}
//////////////////////////////////////////////////////////////////////////////
//
// insert_move_iterator
//
//////////////////////////////////////////////////////////////////////////////
template <typename C> // C models Container
class move_insert_iterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
C* container_m;
typename C::iterator pos_;
public:
typedef C container_type;
explicit move_insert_iterator(C& x, typename C::iterator pos)
: container_m(&x), pos_(pos)
{}
move_insert_iterator& operator=(typename C::reference x)
{
pos_ = container_m->insert(pos_, boost::interprocess::move(x));
++pos_;
return *this;
}
move_insert_iterator& operator*() { return *this; }
move_insert_iterator& operator++() { return *this; }
move_insert_iterator& operator++(int) { return *this; }
};
//!
//! <b>Returns</b>: move_insert_iterator<C>(x, it).
template <typename C> // C models Container
inline move_insert_iterator<C> move_inserter(C& x, typename C::iterator it)
{
return move_insert_iterator<C>(x, it);
}
//////////////////////////////////////////////////////////////////////////////
//
// move
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>: Moves elements in the range [first,last) into the range [result,result + (last -
//! first)) starting from first and proceeding to last. For each non-negative integer n < (last-first),
//! performs *(result + n) = boost::interprocess::move (*(first + n)).
//!
//! <b>Effects</b>: result + (last - first).
//!
//! <b>Requires</b>: result shall not be in the range [first,last).
//!
//! <b>Complexity</b>: Exactly last - first move assignments.
template <typename I, // I models InputIterator
typename O> // O models OutputIterator
O move(I f, I l, O result)
{
while (f != l) {
*result = boost::interprocess::move(*f);
++f; ++result;
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
//
// move_backward
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>: Moves elements in the range [first,last) into the range
//! [result - (last-first),result) starting from last - 1 and proceeding to
//! first. For each positive integer n <= (last - first),
//! performs *(result - n) = boost::interprocess::move(*(last - n)).
//!
//! <b>Requires</b>: result shall not be in the range [first,last).
//!
//! <b>Returns</b>: result - (last - first).
//!
//! <b>Complexity</b>: Exactly last - first assignments.
template <typename I, // I models BidirectionalIterator
typename O> // O models BidirectionalIterator
O move_backward(I f, I l, O result)
{
while (f != l) {
--l; --result;
*result = boost::interprocess::move(*l);
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
//
// uninitialized_move
//
//////////////////////////////////////////////////////////////////////////////
//! <b>Effects</b>:
//! \code
//! for (; first != last; ++result, ++first)
//! new (static_cast<void*>(&*result))
//! typename iterator_traits<ForwardIterator>::value_type(boost::interprocess::move(*first));
//! \endcode
//!
//! <b>Returns</b>: result
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r
/// @cond
,typename enable_if<is_movable<typename std::iterator_traits<I>::value_type> >::type* = 0
/// @endcond
)
{
typedef typename std::iterator_traits<I>::value_type input_value_type;
while (f != l) {
::new(static_cast<void*>(&*r)) input_value_type(boost::interprocess::move(*f));
++f; ++r;
}
return r;
}
/// @cond
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move(I f, I l, F r,
typename disable_if<is_movable<typename std::iterator_traits<I>::value_type> >::type* = 0)
{
return std::uninitialized_copy(f, l, r);
}
//////////////////////////////////////////////////////////////////////////////
//
// uninitialized_copy_or_move
//
//////////////////////////////////////////////////////////////////////////////
namespace move_detail {
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move_move_iterator(I f, I l, F r,
typename enable_if< is_movable<typename I::value_type> >::type* = 0)
{
return boost::interprocess::uninitialized_move(f, l, r);
}
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_move_move_iterator(I f, I l, F r,
typename disable_if< is_movable<typename I::value_type> >::type* = 0)
{
return std::uninitialized_copy(f.base(), l.base(), r);
}
} //namespace move_detail {
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_copy_or_move(I f, I l, F r,
typename enable_if< move_detail::is_move_iterator<I> >::type* = 0)
{
return boost::interprocess::move_detail::uninitialized_move_move_iterator(f, l, r);
}
/// @endcond
//! <b>Effects</b>:
//! \code
//! for (; first != last; ++result, ++first)
//! new (static_cast<void*>(&*result))
//! typename iterator_traits<ForwardIterator>::value_type(*first);
//! \endcode
//!
//! <b>Returns</b>: result
//!
//! <b>Note</b>: This function is provided because
//! <i>std::uninitialized_copy</i> from some STL implementations
//! is not compatible with <i>move_iterator</i>
template
<typename I, // I models InputIterator
typename F> // F models ForwardIterator
F uninitialized_copy_or_move(I f, I l, F r
/// @cond
,typename disable_if< move_detail::is_move_iterator<I> >::type* = 0
/// @endcond
)
{
return std::uninitialized_copy(f, l, r);
}
///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>
{};
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP

View File

@@ -0,0 +1,152 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_MPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MPL_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <cstddef>
namespace boost {
namespace interprocess {
namespace detail {
template <class T, T val>
struct integral_constant
{
static const T value = val;
typedef integral_constant<T,val> type;
};
template< bool C_ >
struct bool_ : integral_constant<bool, C_>
{
static const bool value = C_;
};
typedef bool_<true> true_;
typedef bool_<false> false_;
typedef true_ true_type;
typedef false_ false_type;
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <bool B, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <class Cond, class T = void>
struct disable_if : public enable_if_c<!Cond::value, T> {};
template <class T, class U>
class is_convertible
{
typedef char true_t;
class false_t { char dummy[2]; };
static true_t dispatch(U);
static false_t dispatch(...);
static T trigger();
public:
enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
};
template<
bool C
, typename T1
, typename T2
>
struct if_c
{
typedef T1 type;
};
template<
typename T1
, typename T2
>
struct if_c<false,T1,T2>
{
typedef T2 type;
};
template<
typename T1
, typename T2
, typename T3
>
struct if_
{
typedef typename if_c<0 != T1::value, T2, T3>::type type;
};
template <class Pair>
struct select1st
// : public std::unary_function<Pair, typename Pair::first_type>
{
template<class OtherPair>
const typename Pair::first_type& operator()(const OtherPair& x) const
{ return x.first; }
const typename Pair::first_type& operator()(const typename Pair::first_type& x) const
{ return x; }
};
// identity is an extension: it is not part of the standard.
template <class T>
struct identity
// : public std::unary_function<T,T>
{
typedef T type;
const T& operator()(const T& x) const
{ return x; }
};
template<std::size_t S>
struct ls_zeros
{
static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value);
};
template<>
struct ls_zeros<0>
{
static const std::size_t value = 0;
};
template<>
struct ls_zeros<1>
{
static const std::size_t value = 0;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MPL_HPP

View File

@@ -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

View File

@@ -0,0 +1,348 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_NAMED_PROXY_HPP
#define BOOST_INTERPROCESS_NAMED_PROXY_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <new>
#include <iterator>
#include <boost/interprocess/detail/in_place_interface.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/interprocess/detail/preprocessor.hpp>
#else
#include <boost/interprocess/detail/move.hpp>
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
//!\file
//!Describes a proxy class that implements named allocation syntax.
namespace boost {
namespace interprocess {
namespace detail {
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
template<class T, bool is_iterator, class ...Args>
struct CtorNArg : public placement_destroy<T>
{
typedef detail::bool_<is_iterator> IsIterator;
typedef CtorNArg<T, is_iterator, Args...> self_t;
typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t;
self_t& operator++()
{
this->do_increment(IsIterator(), index_tuple_t());
return *this;
}
self_t operator++(int) { return ++*this; *this; }
CtorNArg(Args && ...args)
: args_(args...)
{}
virtual void construct_n(void *mem
, std::size_t num
, std::size_t &constructed)
{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed){
this->construct(memory++, IsIterator(), index_tuple_t());
this->do_increment(IsIterator(), index_tuple_t());
}
}
private:
template<int ...IdxPack>
void construct(void *mem, detail::true_, const index_tuple<IdxPack...>&)
{ new((void*)mem)T(*boost::interprocess::forward<Args>(get<IdxPack>(args_))...); }
template<int ...IdxPack>
void construct(void *mem, detail::false_, const index_tuple<IdxPack...>&)
{ new((void*)mem)T(boost::interprocess::forward<Args>(get<IdxPack>(args_))...); }
template<int ...IdxPack>
void do_increment(detail::true_, const index_tuple<IdxPack...>&)
{
this->expansion_helper(++get<IdxPack>(args_)...);
}
template<class ...ExpansionArgs>
void expansion_helper(ExpansionArgs &&...)
{}
template<int ...IdxPack>
void do_increment(detail::false_, const index_tuple<IdxPack...>&)
{}
tuple<Args&&...> args_;
};
//!Describes a proxy class that implements named
//!allocation syntax.
template
< class SegmentManager //segment manager to construct the object
, class T //type of object to build
, bool is_iterator //passing parameters are normal object or iterators?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
template<class ...Args>
T *operator()(Args &&...args) const
{
CtorNArg<T, is_iterator, Args...> ctor_obj(boost::interprocess::forward<Args>(args)...);
return mp_mngr->template
generic_construct<T>(mp_name, m_num, m_find, m_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; }
};
#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
//!Function object that makes placement new
//!without arguments
template<class T>
struct Ctor0Arg : public placement_destroy<T>
{
typedef Ctor0Arg self_t;
Ctor0Arg(){}
self_t& operator++() { return *this; }
self_t operator++(int) { return *this; }
void construct(void *mem)
{ new((void*)mem)T; }
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)
{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed)
new((void*)memory++)T;
}
};
////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2):
//
// template<class T, bool is_iterator, class P1, class P2>
// struct Ctor2Arg
// : public placement_destroy<T>
// {
// typedef detail::bool_<is_iterator> IsIterator;
// typedef Ctor2Arg self_t;
//
// void do_increment(detail::false_)
// { ++m_p1; ++m_p2; }
//
// void do_increment(detail::true_){}
//
// self_t& operator++()
// {
// this->do_increment(IsIterator());
// 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 construct(void *mem)
// { new((void*)object)T(m_p1, m_p2); }
//
// virtual void construct_n(void *mem
// , std::size_t num
// , std::size_t &constructed)
// {
// T* memory = static_cast<T*>(mem);
// for(constructed = 0; constructed < num; ++constructed){
// this->construct(memory++, IsIterator());
// this->do_increment(IsIterator());
// }
// }
//
// private:
// void construct(void *mem, detail::true_)
// { new((void*)mem)T(*m_p1, *m_p2); }
//
// void construct(void *mem, detail::false_)
// { new((void*)mem)T(m_p1, m_p2); }
//
// 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 lvalues with non-const references, we have to be ugly
#define BOOST_PP_LOCAL_MACRO(n) \
template<class T, bool is_iterator, BOOST_PP_ENUM_PARAMS(n, class P) > \
struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
: public placement_destroy<T> \
{ \
typedef detail::bool_<is_iterator> IsIterator; \
typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) self_t; \
\
void do_increment(detail::true_) \
{ BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INC, _); } \
\
void do_increment(detail::false_){} \
\
self_t& operator++() \
{ \
this->do_increment(IsIterator()); \
return *this; \
} \
\
self_t operator++(int) { return ++*this; *this; } \
\
BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _) ) \
: BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INIT, _) {} \
\
virtual void construct_n(void *mem \
, std::size_t num \
, std::size_t &constructed) \
{ \
T* memory = static_cast<T*>(mem); \
for(constructed = 0; constructed < num; ++constructed){ \
this->construct(memory++, IsIterator()); \
this->do_increment(IsIterator()); \
} \
} \
\
private: \
void construct(void *mem, detail::true_) \
{ \
new((void*)mem) T \
(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD, _)); \
} \
\
void construct(void *mem, detail::false_) \
{ \
new((void*)mem) T \
(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \
} \
\
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()
//!Describes a proxy class that implements named
//!allocation syntax.
template
< class SegmentManager //segment manager to construct the object
, class T //type of object to build
, bool is_iterator //passing parameters are normal object or iterators?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
//!makes a named allocation and calls the
//!default constructor
T *operator()() const
{
Ctor0Arg<T> ctor_obj;
return mp_mngr->template
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
}
//!
#define BOOST_PP_LOCAL_MACRO(n) \
template<BOOST_PP_ENUM_PARAMS(n, class P)> \
T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) const\
{ \
typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \
<T, is_iterator, BOOST_PP_ENUM_PARAMS(n, P)> \
ctor_obj_t; \
ctor_obj_t ctor_obj \
(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
return mp_mngr->template generic_construct<T> \
(mp_name, m_num, m_find, m_dothrow, ctor_obj); \
} \
//!
#define BOOST_PP_LOCAL_LIMITS ( 1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS )
#include BOOST_PP_LOCAL_ITERATE()
////////////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2)
////////////////////////////////////////////////////////////////////////
//
// template <class P1, class P2>
// T *operator()(P1 &p1, P2 &p2) const
// {
// typedef Ctor2Arg
// <T, is_iterator, P1, P2>
// ctor_obj_t;
// ctor_obj_t ctor_obj(p1, p2);
//
// return mp_mngr->template generic_construct<T>
// (mp_name, m_num, m_find, m_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; }
};
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
}}} //namespace boost { namespace interprocess { namespace detail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP

View File

@@ -0,0 +1,506 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_OS_FILE_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <string>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <fcntl.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <errno.h>
# include <cstdio>
# include <dirent.h>
# else
# error Unknown platform
# endif
#endif
#include <cstring>
#include <cstdlib>
namespace boost {
namespace interprocess {
#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef void * file_handle_t;
typedef long long offset_t;
typedef struct mapping_handle_impl_t{
void * handle;
bool is_shm;
} mapping_handle_t;
typedef enum { read_only = winapi::generic_read
, read_write = winapi::generic_read | winapi::generic_write
, copy_on_write
, invalid_mode = 0xffff
} mode_t;
typedef enum { file_begin = winapi::file_begin
, file_end = winapi::file_end
, file_current = winapi::file_current
} file_pos_t;
namespace detail{
inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_shm = false;
return ret;
}
inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_shm = true;
return ret;
}
inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
{ return hnd.handle; }
inline bool create_directory(const char *path)
{ return winapi::create_directory(path, 0); }
inline const char *get_temporary_path()
{ return std::getenv("TMP"); }
inline file_handle_t create_new_file
(const char *name, mode_t mode = read_write, bool temporary = false)
{
unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
return winapi::create_file
(name, (unsigned int)mode, winapi::create_new, attr);
}
inline file_handle_t create_or_open_file
(const char *name, mode_t mode = read_write, bool temporary = false)
{
unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
return winapi::create_file
(name, (unsigned int)mode, winapi::open_always, attr);
}
inline file_handle_t open_existing_file
(const char *name, mode_t mode = read_write, bool temporary = false)
{
unsigned long attr = temporary ? winapi::file_attribute_temporary : 0;
return winapi::create_file
(name, (unsigned int)mode, winapi::open_existing, attr);
}
inline bool delete_file(const char *name)
{ return winapi::unlink_file(name); }
inline bool truncate_file (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 bool get_file_size(file_handle_t hnd, offset_t &size)
{ return winapi::get_file_size(hnd, size); }
inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos)
{ return winapi::set_file_pointer_ex(hnd, off, 0, (unsigned long) pos); }
inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
{ return winapi::set_file_pointer_ex(hnd, 0, &off, winapi::file_current); }
inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
{
unsigned long written;
return 0 != winapi::write_file(hnd, data, (unsigned long)numdata, &written, 0);
}
inline file_handle_t invalid_file()
{ return winapi::invalid_handle_value; }
inline bool close_file(file_handle_t hnd)
{ return 0 != winapi::close_handle(hnd); }
inline bool acquire_file_lock(file_handle_t hnd)
{
static winapi::interprocess_overlapped overlapped;
const unsigned long len = 0xffffffff;
// winapi::interprocess_overlapped overlapped;
// std::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(file_handle_t hnd, bool &acquired)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
std::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 release_file_lock(file_handle_t hnd)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
std::memset(&overlapped, 0, sizeof(overlapped));
return winapi::unlock_file_ex(hnd, 0, len, len, &overlapped);
}
inline bool acquire_file_lock_sharable(file_handle_t hnd)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
std::memset(&overlapped, 0, sizeof(overlapped));
return winapi::lock_file_ex(hnd, 0, 0, len, len, &overlapped);
}
inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired)
{
const unsigned long len = 0xffffffff;
winapi::interprocess_overlapped overlapped;
std::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 release_file_lock_sharable(file_handle_t hnd)
{ return release_file_lock(hnd); }
inline bool delete_subdirectories_recursive
(const std::string &refcstrRootDirectory, const char *dont_delete_this, unsigned int count)
{
bool bSubdirectory = false; // Flag, indicating whether
// subdirectories have been found
void * hFile; // Handle to directory
std::string strFilePath; // Filepath
std::string strPattern; // Pattern
winapi::win32_find_data_t FileInformation; // File information
//Find all files and directories
strPattern = refcstrRootDirectory + "\\*.*";
hFile = winapi::find_first_file(strPattern.c_str(), &FileInformation);
if(hFile != winapi::invalid_handle_value){
do{
//If it's not "." or ".." or the pointed root_level dont_delete_this erase it
if(FileInformation.cFileName[0] != '.' &&
!(dont_delete_this && count == 0 && std::strcmp(dont_delete_this, FileInformation.cFileName) == 0)){
strFilePath.erase();
strFilePath = refcstrRootDirectory + "\\" + FileInformation.cFileName;
//If it's a directory, go recursive
if(FileInformation.dwFileAttributes & winapi::file_attribute_directory){
// Delete subdirectory
if(!delete_subdirectories_recursive(strFilePath, dont_delete_this, count+1))
return false;
}
//If it's a file, just delete it
else{
// Set file attributes
//if(::SetFileAttributes(strFilePath.c_str(), winapi::file_attribute_normal) == 0)
//return winapi::get_last_error();
// Delete file
if(winapi::delete_file(strFilePath.c_str()) == 0)
return false;
}
}
//Go to the next file
} while(winapi::find_next_file(hFile, &FileInformation) == 1);
// Close handle
winapi::find_close(hFile);
//See if the loop has ended with an error or just because we've traversed all the files
if(winapi::get_last_error() != winapi::error_no_more_files){
return false;
}
else
{
//Erase empty subdirectories or original refcstrRootDirectory
if(!bSubdirectory && count)
{
// Set directory attributes
//if(::SetFileAttributes(refcstrRootDirectory.c_str(), FILE_ATTRIBUTE_NORMAL) == 0)
//return ::GetLastError();
// Delete directory
if(winapi::remove_directory(refcstrRootDirectory.c_str()) == 0)
return false;
}
}
}
return true;
}
//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this"
inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this, 0u);
}
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef int file_handle_t;
typedef off_t offset_t;
typedef struct mapping_handle_impl_t
{
file_handle_t handle;
bool is_xsi;
} mapping_handle_t;
typedef enum { read_only = O_RDONLY
, read_write = O_RDWR
, copy_on_write
, invalid_mode = 0xffff
} mode_t;
typedef enum { file_begin = SEEK_SET
, file_end = SEEK_END
, file_current = SEEK_CUR
} file_pos_t;
namespace detail{
inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd)
{
mapping_handle_t ret;
ret.handle = hnd;
ret.is_xsi = false;
return ret;
}
inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
{ return hnd.handle; }
inline bool create_directory(const char *path)
{ return ::mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0; }
inline const char *get_temporary_path()
{
const char *dir = std::getenv("TMPDIR");
if(!dir){
dir = std::getenv("TMP");
if(!dir){
dir = std::getenv("TEMP");
if(!dir){
dir = "/tmp";
}
}
}
return dir;
}
inline file_handle_t create_new_file
(const char *name, mode_t mode = read_write, bool temporary = false)
{
(void)temporary;
return ::open(name, ((int)mode) | O_EXCL | O_CREAT, S_IRWXG | S_IRWXO | S_IRWXU);
}
inline file_handle_t create_or_open_file
(const char *name, mode_t mode = read_write, bool temporary = false)
{
(void)temporary;
return ::open(name, ((int)mode) | O_CREAT, S_IRWXG | S_IRWXO | S_IRWXU);
}
inline file_handle_t open_existing_file
(const char *name, mode_t mode = read_write, bool temporary = false)
{
(void)temporary;
return ::open(name, (int)mode, S_IRWXG | S_IRWXO | S_IRWXU);
}
inline bool delete_file(const char *name)
{ return ::unlink(name) == 0; }
inline bool truncate_file (file_handle_t hnd, std::size_t size)
{ return 0 == ::ftruncate(hnd, size); }
inline bool get_file_size(file_handle_t hnd, offset_t &size)
{
struct stat data;
bool ret = 0 == ::fstat(hnd, &data);
if(ret){
size = data.st_size;
}
return ret;
}
inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos)
{ return off == ::lseek(hnd, off, (int)pos); }
inline bool get_file_pointer(file_handle_t hnd, offset_t &off)
{
off = ::lseek(hnd, 0, SEEK_CUR);
return off != ((off_t)-1);
}
inline bool write_file(file_handle_t hnd, const void *data, std::size_t numdata)
{ return (ssize_t(numdata)) == ::write(hnd, data, numdata); }
inline file_handle_t invalid_file()
{ return -1; }
inline bool close_file(file_handle_t hnd)
{ return ::close(hnd) == 0; }
inline bool acquire_file_lock(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(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 release_file_lock(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(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(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 release_file_lock_sharable(file_handle_t hnd)
{ return release_file_lock(hnd); }
inline bool delete_subdirectories_recursive
(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
DIR *d = opendir(refcstrRootDirectory.c_str());
if(!d) {
return false;
}
struct dir_close
{
DIR *d_;
dir_close(DIR *d) : d_(d) {}
~dir_close() { ::closedir(d_); }
} dc(d); (void)dc;
struct ::dirent *de;
struct ::stat st;
std::string fn;
while((de=::readdir(d))) {
if( de->d_name[0] == '.' && ( de->d_name[1] == '\0'
|| (de->d_name[1] == '.' && de->d_name[2] == '\0' )) ){
continue;
}
if(dont_delete_this && std::strcmp(dont_delete_this, de->d_name) == 0){
continue;
}
fn = refcstrRootDirectory;
fn += '/';
fn += de->d_name;
if(std::remove(fn.c_str())) {
if(::stat(fn.c_str(), & st)) {
return false;
}
if(S_ISDIR(st.st_mode)) {
if(!delete_subdirectories_recursive(fn, 0) ){
return false;
}
} else {
return false;
}
}
}
return std::remove(refcstrRootDirectory.c_str()) ? false : true;
}
//This function erases all the subdirectories of a directory except the one pointed by "dont_delete_this"
inline bool delete_subdirectories(const std::string &refcstrRootDirectory, const char *dont_delete_this)
{
return delete_subdirectories_recursive(refcstrRootDirectory, dont_delete_this );
}
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
} //namespace detail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_FILE_FUNCTIONS_HPP

View File

@@ -0,0 +1,171 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_OS_THREAD_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <pthread.h>
# include <unistd.h>
# include <sched.h>
# else
# error Unknown platform
# endif
#endif
namespace boost {
namespace interprocess {
namespace detail{
#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef unsigned long OS_process_id_t;
typedef unsigned long OS_thread_id_t;
typedef OS_thread_id_t OS_systemwide_thread_id_t;
//process
inline OS_process_id_t get_current_process_id()
{ return winapi::get_current_process_id(); }
inline OS_process_id_t get_invalid_process_id()
{ return OS_process_id_t(0); }
//thread
inline OS_thread_id_t get_current_thread_id()
{ return winapi::get_current_thread_id(); }
inline OS_thread_id_t get_invalid_thread_id()
{ return OS_thread_id_t(0xffffffff); }
inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
{ return id1 == id2; }
inline void thread_yield()
{ winapi::sched_yield(); }
//systemwide thread
inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
{
return get_current_thread_id();
}
inline void systemwide_thread_id_copy
(const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
{
to = from;
}
inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
{
return equal_thread_id(id1, id2);
}
inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
{
return get_invalid_thread_id();
}
#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
typedef pthread_t OS_thread_id_t;
typedef pid_t OS_process_id_t;
struct OS_systemwide_thread_id_t
{
OS_systemwide_thread_id_t()
: pid(), tid()
{}
OS_systemwide_thread_id_t(pid_t p, pthread_t t)
: pid(p), tid(t)
{}
OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x)
: pid(x.pid), tid(x.tid)
{}
OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x)
: pid(x.pid), tid(x.tid)
{}
OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x)
{ pid = x.pid; tid = x.tid; return *this; }
OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x)
{ pid = x.pid; tid = x.tid; return *this; }
void operator=(const OS_systemwide_thread_id_t &x) volatile
{ pid = x.pid; tid = x.tid; }
pid_t pid;
pthread_t tid;
};
inline void systemwide_thread_id_copy
(const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to)
{
to.pid = from.pid;
to.tid = from.tid;
}
//process
inline OS_process_id_t get_current_process_id()
{ return ::getpid(); }
inline OS_process_id_t get_invalid_process_id()
{ return pid_t(0); }
//thread
inline OS_thread_id_t get_current_thread_id()
{ return ::pthread_self(); }
inline OS_thread_id_t get_invalid_thread_id()
{
static pthread_t invalid_id;
return invalid_id;
}
inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2)
{ return 0 != ::pthread_equal(id1, id2); }
inline void thread_yield()
{ ::sched_yield(); }
//systemwide thread
inline OS_systemwide_thread_id_t get_current_systemwide_thread_id()
{
return OS_systemwide_thread_id_t(::getpid(), ::pthread_self());
}
inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2)
{
return (0 != ::pthread_equal(id1.tid, id2.tid)) && (id1.pid == id2.pid);
}
inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id()
{
return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id());
}
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
} //namespace detail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_OS_THREAD_FUNCTIONS_HPP

View File

@@ -0,0 +1,74 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_POINTER_TYPE_HPP
#define BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_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/type_traits.hpp>
namespace boost {
namespace interprocess {
namespace detail {
struct two {char _[2];};
namespace pointer_type_imp {
template <class U> static two test(...);
template <class U> static char test(typename U::pointer* = 0);
} //namespace pointer_type_imp {
template <class T>
struct has_pointer_type
{
static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1;
};
namespace pointer_type_imp {
template <class T, class D, bool = has_pointer_type<D>::value>
struct pointer_type
{
typedef typename D::pointer type;
};
template <class T, class D>
struct pointer_type<T, D, false>
{
typedef T* type;
};
} //namespace pointer_type_imp {
template <class T, class D>
struct pointer_type
{
typedef typename pointer_type_imp::pointer_type<T,
typename detail::remove_reference<D>::type>::type type;
};
} //namespace detail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POINTER_TYPE_HPP

View File

@@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_POSIX_TIMES_WRK_HPP
#define BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP
//workaround to avoid winsock redefines when using date-time
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifndef WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
//#include <boost/date_time/posix_time/ptime.hpp>
//#include <boost/date_time/microsec_time_clock.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
namespace boost {
namespace interprocess {
typedef boost::date_time::microsec_clock<boost::posix_time::ptime> microsec_clock;
}
}
#ifdef _WIN32
#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#endif //#ifndef BOOST_INTERPROCESS_POSIX_TIMES_WRK_HPP

View File

@@ -0,0 +1,101 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-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_DETAIL_PREPROCESSOR_HPP
#define BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#error "This file is not needed when perfect forwarding is available"
#endif
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#define BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS 10
//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
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \
//!
#else
#define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \
const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \
//!
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_INTERPROCESS_PARAM(U, u) \
U && u \
//!
#else
#define BOOST_INTERPROCESS_PARAM(U, u) \
const U & u \
//!
#endif
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \
//!
#else
#define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \
BOOST_PP_CAT(m_p, n) (const_cast<BOOST_PP_CAT(P, n) &>(BOOST_PP_CAT(p, n))) \
//!
#endif
#define BOOST_INTERPROCESS_AUX_PARAM_INC(z, n, data) \
BOOST_PP_CAT(++m_p, n) \
//!
#ifdef BOOST_HAS_RVALUE_REFS
#define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \
//!
#else
#define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \
BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \
//!
#endif
#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \
boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \
//!
#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \
//!
#define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \
BOOST_PP_CAT(*m_p, n) \
//!
#include <boost/interprocess/detail/config_end.hpp>
#else
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#error "This file is not needed when perfect forwarding is available"
#endif
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_PREPROCESSOR_HPP

View File

@@ -0,0 +1,33 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_PTIME_WRK_HPP
#define BOOST_INTERPROCESS_PTIME_WRK_HPP
//workaround to avoid winsock redefines when using date-time
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifndef WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#include <boost/date_time/posix_time/ptime.hpp>
#ifdef _WIN32
#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef BOOST_INTERPROCESS_WIN32_LEAN_AND_MEAN
#endif //#ifdef _WIN32
#endif //#ifndef BOOST_INTERPROCESS_PTIME_WRK_HPP

View File

@@ -0,0 +1,504 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/pointer_to_other.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
#include <cassert> //assert
#include <functional> //unary_function
#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 alloc_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)alloc_type << 5u) |
((unsigned char)sizeof_char & 0x1F) )
{};
template<class T>
block_header &operator= (const T& )
{ return *this; }
std::size_t total_size() const
{
if(alloc_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 alloc_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 const_cast<CharType*>(reinterpret_cast<const CharType*>
(reinterpret_cast<const char*>(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 const_cast<char*>((reinterpret_cast<const char*>(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 =
const_cast<block_header*>
(reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(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*>(reinterpret_cast<char*>(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*>(reinterpret_cast<char*>(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 const_cast<block_header*>
(reinterpret_cast<const block_header *>(reinterpret_cast<const char*>(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 reinterpret_cast<intrusive_value_type_impl *>(reinterpret_cast<char*>(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(static_cast<CharType*>(0))
{}
char_ptr_holder(const detail::unique_instance_t *)
: m_name(reinterpret_cast<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 boost::
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 static_cast<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 {
//These pointers are the ones the user will use to
//indicate previous allocation types
static const detail::anonymous_instance_t * anonymous_instance = 0;
static const detail::unique_instance_t * unique_instance = 0;
namespace detail_really_deep_namespace {
//Otherwise, gcc issues a warning of previously defined
//anonymous_instance and unique_instance
struct dummy
{
dummy()
{
(void)anonymous_instance;
(void)unique_instance;
}
};
} //detail_really_deep_namespace
}} //namespace boost { namespace interprocess
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP

View File

@@ -0,0 +1,166 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP
#define BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/errors.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <string>
#if defined(BOOST_INTERPROCESS_WINDOWS)
#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME
#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
#include <boost/interprocess/detail/win32_api.hpp>
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
#include <sys/sysctl.h>
#if defined(CTL_KERN) && defined (KERN_BOOTTIME)
#define BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME
#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
#endif
#endif
namespace boost {
namespace interprocess {
namespace detail {
#if defined (BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME)
inline void get_bootstamp(std::string &s, bool add = false)
{
char bootstamp[winapi::BootstampLength*2+1];
std::size_t bootstamp_length = winapi::BootstampLength*2;
winapi::get_boot_time_str(bootstamp, bootstamp_length);
bootstamp[winapi::BootstampLength*2] = 0;
if(add){
s += bootstamp;
}
else{
s = bootstamp;
}
}
#elif defined(BOOST_INTERPROCESS_HAS_BSD_KERNEL_BOOTTIME)
inline void get_bootstamp(std::string &s, bool add = false)
{
// FreeBSD specific: sysctl "kern.boottime"
int request[2] = { CTL_KERN, KERN_BOOTTIME };
struct ::timeval result;
size_t result_len = sizeof result;
if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0)
return;
char bootstamp_str[256];
const char Characters [] =
{ '0', '1', '2', '3', '4', '5', '6', '7'
, '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
std::size_t char_counter = 0;
long fields[2] = { result.tv_sec, result.tv_usec };
for(std::size_t field = 0; field != 2; ++field){
for(std::size_t i = 0; i != sizeof(long); ++i){
const char *ptr = (const char *)&fields[field];
bootstamp_str[char_counter++] = Characters[(ptr[i]&0xF0)>>4];
bootstamp_str[char_counter++] = Characters[(ptr[i]&0x0F)];
}
}
bootstamp_str[char_counter] = 0;
if(add){
s += bootstamp_str;
}
else{
s = bootstamp_str;
}
}
#endif
inline void tmp_filename(const char *filename, std::string &tmp_name)
{
const char *tmp_dir = get_temporary_path();
if(!tmp_dir){
error_info err = system_error_code();
throw interprocess_exception(err);
}
tmp_name = tmp_dir;
//Remove final null.
tmp_name += "/boost_interprocess/";
#ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
get_bootstamp(tmp_name, true);
tmp_name += '/';
#endif
tmp_name += filename;
}
inline void create_tmp_dir_and_get_filename(const char *filename, std::string &tmp_name)
{
//First get the temp directory
const char *tmp_path = get_temporary_path();
if(!tmp_path){
error_info err = system_error_code();
throw interprocess_exception(err);
}
//Create Boost.Interprocess dir
tmp_name = tmp_path;
tmp_name += "/boost_interprocess";
//If fails, check that it's because already exists
if(!create_directory(tmp_name.c_str())){
error_info info(system_error_code());
if(info.get_error_code() != already_exists_error){
throw interprocess_exception(info);
}
}
#ifdef BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
//Create a new subdirectory with the bootstamp
std::string root_tmp_name = tmp_name;
tmp_name += '/';
//Obtain bootstamp string
std::string bootstamp;
get_bootstamp(bootstamp);
tmp_name += bootstamp;
//If fails, check that it's because already exists
if(!create_directory(tmp_name.c_str())){
error_info info(system_error_code());
if(info.get_error_code() != already_exists_error){
throw interprocess_exception(info);
}
}
//Now erase all old directories created in the previous boot sessions
delete_subdirectories(root_tmp_name, bootstamp.c_str());
#endif
//Add filename
tmp_name += '/';
tmp_name += filename;
}
inline void add_leading_slash(const char *name, std::string &new_name)
{
if(name[0] != '/'){
new_name = '/';
}
new_name += name;
}
} //namespace boost{
} //namespace interprocess {
} //namespace detail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //ifndef BOOST_INTERPROCESS_DETAIL_TMP_DIR_HELPERS_HPP

View File

@@ -0,0 +1,180 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_TRANSFORM_ITERATORS_HPP
#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_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 <iterator>
#include <boost/interprocess/detail/type_traits.hpp>
namespace boost {
namespace interprocess {
template <class PseudoReference>
struct operator_arrow_proxy
{
operator_arrow_proxy(const PseudoReference &px)
: m_value(px)
{}
PseudoReference* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable PseudoReference m_value;
};
template <class T>
struct operator_arrow_proxy<T&>
{
operator_arrow_proxy(T &px)
: m_value(px)
{}
T* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable T &m_value;
};
template <class Iterator, class UnaryFunction>
class transform_iterator
: public UnaryFunction
, public std::iterator
< typename Iterator::iterator_category
, typename detail::remove_reference<typename UnaryFunction::result_type>::type
, typename Iterator::difference_type
, operator_arrow_proxy<typename UnaryFunction::result_type>
, typename UnaryFunction::result_type>
{
public:
explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
: UnaryFunction(f), m_it(it)
{}
explicit transform_iterator()
: UnaryFunction(), m_it()
{}
//Constructors
transform_iterator& operator++()
{ increment(); return *this; }
transform_iterator operator++(int)
{
transform_iterator result (*this);
increment();
return result;
}
friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i == i2); }
/*
friend bool operator> (const transform_iterator& i, const transform_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i < i2); }
*/
friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(typename Iterator::difference_type off)
{ this->advance(off); return *this; }
transform_iterator operator+(typename Iterator::difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
{ return right + off; }
transform_iterator& operator-=(typename Iterator::difference_type off)
{ this->advance(-off); return *this; }
transform_iterator operator-(typename Iterator::difference_type off) const
{ return *this + (-off); }
typename UnaryFunction::result_type operator*() const
{ return dereference(); }
operator_arrow_proxy<typename UnaryFunction::result_type>
operator->() const
{ return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
Iterator & base()
{ return m_it; }
const Iterator & base() const
{ return m_it; }
private:
Iterator m_it;
void increment()
{ ++m_it; }
void decrement()
{ --m_it; }
bool equal(const transform_iterator &other) const
{ return m_it == other.m_it; }
bool less(const transform_iterator &other) const
{ return other.m_it < m_it; }
typename UnaryFunction::result_type dereference() const
{ return UnaryFunction::operator()(*m_it); }
void advance(typename Iterator::difference_type n)
{ std::advance(m_it, n); }
typename Iterator::difference_type distance_to(const transform_iterator &other)const
{ return std::distance(other.m_it, m_it); }
};
template <class Iterator, class UnaryFunc>
transform_iterator<Iterator, UnaryFunc>
make_transform_iterator(Iterator it, UnaryFunc fun)
{
return transform_iterator<Iterator, UnaryFunc>(it, fun);
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP

View File

@@ -0,0 +1,166 @@
//////////////////////////////////////////////////////////////////////////////
// (C) Copyright John Maddock 2000.
// (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.
//
// The alignment_of implementation comes from John Maddock's boost::alignment_of code
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#define BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
namespace boost {
namespace interprocess {
namespace detail {
struct nat{};
//boost::alignment_of yields to 10K lines of preprocessed code, so we
//need an alternative
template <typename T> struct alignment_of;
template <typename T>
struct alignment_of_hack
{
char c;
T t;
alignment_of_hack();
};
template <unsigned A, unsigned S>
struct alignment_logic
{
enum{ value = A < S ? A : S };
};
template< typename T >
struct alignment_of
{
enum{ value = alignment_logic
< sizeof(alignment_of_hack<T>) - sizeof(T)
, sizeof(T)>::value };
};
//This is not standard, but should work with all compilers
union max_align
{
char char_;
short short_;
int int_;
long long_;
#ifdef BOOST_HAS_LONG_LONG
long long long_long_;
#endif
float float_;
double double_;
long double long_double_;
void * void_ptr_;
};
template<class T>
struct remove_reference
{
typedef T type;
};
template<class T>
struct remove_reference<T&>
{
typedef T type;
};
template<class T>
struct is_reference
{
enum { value = false };
};
template<class T>
struct is_reference<T&>
{
enum { value = true };
};
template<class T>
struct is_pointer
{
enum { value = false };
};
template<class T>
struct is_pointer<T*>
{
enum { value = true };
};
template <typename T>
struct add_reference
{
typedef T& type;
};
template<class T>
struct add_reference<T&>
{
typedef T& type;
};
template<>
struct add_reference<void>
{
typedef nat &type;
};
template<>
struct add_reference<const void>
{
typedef const nat &type;
};
template <class T>
struct add_const_reference
{ typedef const T &type; };
template <class T>
struct add_const_reference<T&>
{ typedef T& type; };
template <typename T, typename U>
struct is_same
{
typedef char yes_type;
struct no_type
{
char padding[8];
};
template <typename V>
static yes_type is_same_tester(V*, V*);
static no_type is_same_tester(...);
static T *t;
static U *u;
static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u));
};
} // namespace detail
} //namespace interprocess {
} //namespace boost {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TYPE_TRAITS_HPP
#include <boost/interprocess/detail/config_end.hpp>

View File

@@ -0,0 +1,170 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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/transform_iterator.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/detail/move.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);
}
//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 };
};
// 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;
};
} //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 <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

View File

@@ -0,0 +1,153 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-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_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_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/type_traits.hpp>
#include <cstddef> //std::size_t
namespace boost {
namespace interprocess {
namespace detail {
template<typename... Values>
class tuple;
template<> class tuple<>
{};
template<typename Head, typename... Tail>
class tuple<Head, Tail...>
: private tuple<Tail...>
{
typedef tuple<Tail...> inherited;
public:
tuple() { }
// implicit copy-constructor is okay
// Construct tuple from separate arguments.
tuple(typename add_const_reference<Head>::type v,
typename add_const_reference<Tail>::type... vtail)
: inherited(vtail...), m_head(v)
{}
// Construct tuple from another tuple.
template<typename... VValues>
tuple(const tuple<VValues...>& other)
: m_head(other.head()), inherited(other.tail())
{}
template<typename... VValues>
tuple& operator=(const tuple<VValues...>& other)
{
m_head = other.head();
tail() = other.tail();
return this;
}
typename add_reference<Head>::type head() { return m_head; }
typename add_reference<const Head>::type head() const { return m_head; }
inherited& tail() { return *this; }
const inherited& tail() const { return *this; }
protected:
Head m_head;
};
template<typename... Values>
tuple<Values&&...> tie_forward(Values&&... values)
{ return tuple<Values&&...>(values...); }
template<int I, typename Tuple>
struct tuple_element;
template<int I, typename Head, typename... Tail>
struct tuple_element<I, tuple<Head, Tail...> >
{
typedef typename tuple_element<I-1, tuple<Tail...> >::type type;
};
template<typename Head, typename... Tail>
struct tuple_element<0, tuple<Head, Tail...> >
{
typedef Head type;
};
template<int I, typename Tuple>
class get_impl;
template<int I, typename Head, typename... Values>
class get_impl<I, tuple<Head, Values...> >
{
typedef typename tuple_element<I-1, tuple<Values...> >::type Element;
typedef get_impl<I-1, tuple<Values...> > Next;
public:
typedef typename add_reference<Element>::type type;
typedef typename add_const_reference<Element>::type const_type;
static type get(tuple<Head, Values...>& t) { return Next::get(t.tail()); }
static const_type get(const tuple<Head, Values...>& t) { return Next::get(t.tail()); }
};
template<typename Head, typename... Values>
class get_impl<0, tuple<Head, Values...> >
{
public:
typedef typename add_reference<Head>::type type;
typedef typename add_const_reference<Head>::type const_type;
static type get(tuple<Head, Values...>& t) { return t.head(); }
static const_type get(const tuple<Head, Values...>& t){ return t.head(); }
};
template<int I, typename... Values>
typename get_impl<I, tuple<Values...> >::type get(tuple<Values...>& t)
{ return get_impl<I, tuple<Values...> >::get(t); }
template<int I, typename... Values>
typename get_impl<I, tuple<Values...> >::const_type get(const tuple<Values...>& t)
{ return get_impl<I, tuple<Values...> >::get(t); }
////////////////////////////////////////////////////
// Builds an index_tuple<0, 1, 2, ..., Num-1>, that will
// be used to "unpack" into comma-separated values
// in a function call.
////////////////////////////////////////////////////
template<int... Indexes>
struct index_tuple{};
template<std::size_t Num, typename Tuple = index_tuple<> >
struct build_number_seq;
template<std::size_t Num, int... Indexes>
struct build_number_seq<Num, index_tuple<Indexes...> >
: build_number_seq<Num - 1, index_tuple<Indexes..., sizeof...(Indexes)> >
{};
template<int... Indexes>
struct build_number_seq<0, index_tuple<Indexes...> >
{ typedef index_tuple<Indexes...> type; };
}}} //namespace boost { namespace interprocess { namespace detail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP

View File

@@ -0,0 +1,889 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_WIN32_SYNC_PRIMITIVES_HPP
#define BOOST_INTERPROCESS_WIN32_SYNC_PRIMITIVES_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <cstddef>
#include <cstring>
#include <memory>
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
# pragma comment( lib, "advapi32.lib" )
#endif
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <cstdarg>
# include <boost/detail/interlocked.hpp>
#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 error_no_more_files = 18u;
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 page_writecopy = 0x08;
static const unsigned long standard_rights_required = 0x000F0000L;
static const unsigned long section_query = 0x0001;
static const unsigned long section_map_write = 0x0002;
static const unsigned long section_map_read = 0x0004;
static const unsigned long section_map_execute = 0x0008;
static const unsigned long section_extend_size = 0x0010;
static const unsigned long section_all_access = standard_rights_required |
section_query |
section_map_write |
section_map_read |
section_map_execute |
section_extend_size;
static const unsigned long file_map_copy = section_query;
static const unsigned long file_map_write = section_map_write;
static const unsigned long file_map_read = section_map_read;
static const unsigned long file_map_all_access = section_all_access;
static const unsigned long delete_access = 0x00010000L;
static const unsigned long file_flag_backup_semantics = 0x02000000;
static const long file_flag_delete_on_close = 0x04000000;
//Native API constants
static const unsigned long file_open_for_backup_intent = 0x00004000;
static const int file_share_valid_flags = 0x00000007;
static const long file_delete_on_close = 0x00001000L;
static const long obj_case_insensitive = 0x00000040L;
static const unsigned long movefile_copy_allowed = 0x02;
static const unsigned long movefile_delay_until_reboot = 0x04;
static const unsigned long movefile_replace_existing = 0x01;
static const unsigned long movefile_write_through = 0x08;
static const unsigned long movefile_create_hardlink = 0x10;
static const unsigned long movefile_fail_if_not_trackable = 0x20;
static const unsigned long file_share_read = 0x00000001;
static const unsigned long file_share_write = 0x00000002;
static const unsigned long file_share_delete = 0x00000004;
static const unsigned long file_attribute_readonly = 0x00000001;
static const unsigned long file_attribute_hidden = 0x00000002;
static const unsigned long file_attribute_system = 0x00000004;
static const unsigned long file_attribute_directory = 0x00000010;
static const unsigned long file_attribute_archive = 0x00000020;
static const unsigned long file_attribute_device = 0x00000040;
static const unsigned long file_attribute_normal = 0x00000080;
static const unsigned long file_attribute_temporary = 0x00000100;
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 duplicate_close_source = (unsigned long)0x00000001;
static const unsigned long duplicate_same_access = (unsigned long)0x00000002;
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_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;
static const unsigned long security_descriptor_revision = 1;
//Own defines
static const long SystemTimeOfDayInfoLength = 48;
static const long BootAndSystemstampLength = 16;
static const long BootstampLength = 8;
static const unsigned long MaxPath = 260;
} //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;
}dummy;
void *pointer;
};
void *h_event;
};
struct interprocess_filetime
{
unsigned long dwLowDateTime;
unsigned long dwHighDateTime;
};
struct win32_find_data_t
{
unsigned long dwFileAttributes;
interprocess_filetime ftCreationTime;
interprocess_filetime ftLastAccessTime;
interprocess_filetime ftLastWriteTime;
unsigned long nFileSizeHigh;
unsigned long nFileSizeLow;
unsigned long dwReserved0;
unsigned long dwReserved1;
char cFileName[MaxPath];
char cAlternateFileName[14];
};
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;
} dummy;
};
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;
};
struct interprocess_memory_basic_information
{
void * BaseAddress;
void * AllocationBase;
unsigned long AllocationProtect;
unsigned long RegionSize;
unsigned long State;
unsigned long Protect;
unsigned long Type;
};
typedef struct _interprocess_acl
{
unsigned char AclRevision;
unsigned char Sbz1;
unsigned short AclSize;
unsigned short AceCount;
unsigned short Sbz2;
} interprocess_acl;
typedef struct _interprocess_security_descriptor
{
unsigned char Revision;
unsigned char Sbz1;
unsigned short Control;
void *Owner;
void *Group;
interprocess_acl *Sacl;
interprocess_acl *Dacl;
} interprocess_security_descriptor;
enum file_information_class_t {
file_directory_information = 1,
file_full_directory_information,
file_both_directory_information,
file_basic_information,
file_standard_information,
file_internal_information,
file_ea_information,
file_access_information,
file_name_information,
file_rename_information,
file_link_information,
file_names_information,
file_disposition_information,
file_position_information,
file_full_ea_information,
file_mode_information,
file_alignment_information,
file_all_information,
file_allocation_information,
file_end_of_file_information,
file_alternate_name_information,
file_stream_information,
file_pipe_information,
file_pipe_local_information,
file_pipe_remote_information,
file_mailslot_query_information,
file_mailslot_set_information,
file_compression_information,
file_copy_on_write_information,
file_completion_information,
file_move_cluster_information,
file_quota_information,
file_reparse_point_information,
file_network_open_information,
file_object_id_information,
file_tracking_information,
file_ole_directory_information,
file_content_index_information,
file_inherit_content_index_information,
file_ole_information,
file_maximum_information
};
struct file_name_information_t {
unsigned long FileNameLength;
wchar_t FileName[1];
};
struct file_rename_information_t {
int Replace;
void *RootDir;
unsigned long FileNameLength;
wchar_t FileName[1];
};
struct unicode_string_t {
unsigned short Length;
unsigned short MaximumLength;
wchar_t *Buffer;
};
struct object_attributes_t {
unsigned long Length;
void * RootDirectory;
unicode_string_t *ObjectName;
unsigned long Attributes;
void *SecurityDescriptor;
void *SecurityQualityOfService;
};
struct io_status_block_t {
union {
long Status;
void *Pointer;
};
unsigned long *Information;
};
union system_timeofday_information
{
struct data_t
{
__int64 liKeBootTime;
__int64 liKeSystemTime;
__int64 liExpTimeZoneBias;
unsigned long uCurrentTimeZoneId;
unsigned long dwReserved;
} data;
unsigned char Reserved1[SystemTimeOfDayInfoLength];
};
enum system_information_class {
system_basic_information = 0,
system_performance_information = 2,
system_time_of_day_information = 3,
system_process_information = 5,
system_processor_performance_information = 8,
system_interrupt_information = 23,
system_exception_information = 33,
system_registry_quota_information = 37,
system_lookaside_information = 45
};
enum object_information_class
{
object_basic_information,
object_name_information,
object_type_information,
object_all_information,
object_data_information
};
struct object_name_information_t
{
unicode_string_t Name;
wchar_t NameBuffer[1];
};
//Some windows API declarations
extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
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) void * __stdcall GetCurrentProcess();
extern "C" __declspec(dllimport) int __stdcall CloseHandle(void*);
extern "C" __declspec(dllimport) int __stdcall DuplicateHandle
( void *hSourceProcessHandle, void *hSourceHandle
, void *hTargetProcessHandle, void **lpTargetHandle
, unsigned long dwDesiredAccess, int bInheritHandle
, unsigned long dwOptions);
extern "C" __declspec(dllimport) void *__stdcall FindFirstFileA(const char *lpFileName, win32_find_data_t *lpFindFileData);
extern "C" __declspec(dllimport) int __stdcall FindNextFileA(void *hFindFile, win32_find_data_t *lpFindFileData);
extern "C" __declspec(dllimport) int __stdcall FindClose(void *hFindFile);
extern "C" __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(interprocess_filetime*);
extern "C" __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const interprocess_filetime *in, const interprocess_filetime *out);
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, std::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 interprocess_security_attributes*, unsigned long, unsigned long, void *);
extern "C" __declspec(dllimport) int __stdcall DeleteFileA (const char *);
extern "C" __declspec(dllimport) int __stdcall MoveFileExA (const char *, const char *, unsigned long);
extern "C" __declspec(dllimport) void __stdcall GetSystemInfo (struct system_info *);
extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::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,
std::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 RemoveDirectoryA(const char *lpPathName);
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) int __stdcall WriteFile(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped);
extern "C" __declspec(dllimport) int __stdcall InitializeSecurityDescriptor(interprocess_security_descriptor *pSecurityDescriptor, unsigned long dwRevision);
extern "C" __declspec(dllimport) int __stdcall SetSecurityDescriptorDacl(interprocess_security_descriptor *pSecurityDescriptor, int bDaclPresent, interprocess_acl *pDacl, int bDaclDefaulted);
extern "C" __declspec(dllimport) void *__stdcall LoadLibraryA(const char *);
extern "C" __declspec(dllimport) int __stdcall FreeLibrary(void *);
extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*);
extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*);
//API function typedefs
//Pointer to functions
typedef long (__stdcall *NtDeleteFile_t)(object_attributes_t *ObjectAttributes);
typedef long (__stdcall *NtSetInformationFile_t)(void *FileHandle, io_status_block_t *IoStatusBlock, void *FileInformation, unsigned long Length, int FileInformationClass );
typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int);
typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long);
typedef long (__stdcall *NtClose_t) (void*);
typedef long (__stdcall *RtlCreateUnicodeStringFromAsciiz_t)(unicode_string_t *, const char *);
typedef void (__stdcall *RtlFreeUnicodeString_t)(unicode_string_t *);
typedef void (__stdcall *RtlInitUnicodeString_t)( unicode_string_t *, const wchar_t * );
typedef long (__stdcall *RtlAppendUnicodeToString_t)(unicode_string_t *Destination, const wchar_t *Source);
typedef long (__stdcall * NtQuerySystemInformation_t)(int, void*, unsigned long, unsigned long *);
typedef long (__stdcall * NtQueryObject_t)(void*, object_information_class, void *, unsigned long, unsigned long *);
typedef unsigned long (__stdcall * GetMappedFileName_t)(void *, void *, wchar_t *, unsigned long);
} //namespace winapi {
} //namespace interprocess {
} //namespace boost {
#else
# include <windows.h>
#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, std::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 get_current_thread_id()
{ return GetCurrentThreadId(); }
static inline unsigned long get_current_process_id()
{ return GetCurrentProcessId(); }
static inline unsigned int close_handle(void* handle)
{ return CloseHandle(handle); }
static inline void * find_first_file(const char *lpFileName, win32_find_data_t *lpFindFileData)
{ return FindFirstFileA(lpFileName, lpFindFileData); }
static inline bool find_next_file(void *hFindFile, win32_find_data_t *lpFindFileData)
{ return FindNextFileA(hFindFile, lpFindFileData) != 0; }
static inline bool find_close(void *handle)
{ return FindClose(handle) != 0; }
static inline bool duplicate_current_process_handle
(void *hSourceHandle, void **lpTargetHandle)
{
return 0 != DuplicateHandle
( GetCurrentProcess(), hSourceHandle, GetCurrentProcess()
, lpTargetHandle, 0, 0
, duplicate_same_access);
}
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 bool file_time_to_local_file_time
(const interprocess_filetime *in, const interprocess_filetime *out)
{ return 0 != FileTimeToLocalFileTime(in, out); }
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)
{
interprocess_security_attributes sa;
interprocess_security_descriptor sd;
if(!InitializeSecurityDescriptor(&sd, security_descriptor_revision))
return 0;
if(!SetSecurityDescriptorDacl(&sd, true, 0, false))
return 0;
sa.lpSecurityDescriptor = &sd;
sa.nLength = sizeof(interprocess_security_attributes);
sa.bInheritHandle = false;
return CreateFileMappingA (handle, &sa, access, high_size, low_size, 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 | file_share_delete, 0, creation_flags, attributes, 0); }
static inline bool delete_file(const char *name)
{ return 0 != DeleteFileA(name); }
static inline bool move_file_ex(const char *source_filename, const char *destination_filename, unsigned long flags)
{ return 0 != MoveFileExA(source_filename, destination_filename, flags); }
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 bool remove_directory(const char *lpPathName)
{ return 0 != RemoveDirectoryA(lpPathName); }
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 bool write_file(void *hnd, const void *buffer, unsigned long bytes_to_write, unsigned long *bytes_written, interprocess_overlapped* overlapped)
{ return 0 != WriteFile(hnd, buffer, bytes_to_write, bytes_written, overlapped); }
static inline long interlocked_increment(long volatile *addr)
{ return BOOST_INTERLOCKED_INCREMENT(addr); }
static inline long interlocked_decrement(long volatile *addr)
{ return BOOST_INTERLOCKED_DECREMENT(addr); }
static inline long interlocked_compare_exchange(long volatile *addr, long val1, long val2)
{ return BOOST_INTERLOCKED_COMPARE_EXCHANGE(addr, val1, val2); }
static inline long interlocked_exchange_add(long volatile* addend, long value)
{ return BOOST_INTERLOCKED_EXCHANGE_ADD(const_cast<long*>(addend), value); }
static inline long interlocked_exchange(long volatile* addend, long value)
{ return BOOST_INTERLOCKED_EXCHANGE(const_cast<long*>(addend), value); }
//Forward functions
static inline void *load_library(const char *name)
{ return LoadLibraryA(name); }
static inline bool free_library(void *module)
{ return 0 != FreeLibrary(module); }
static inline void *get_proc_address(void *module, const char *name)
{ return GetProcAddress(module, name); }
static inline void *get_current_process()
{ return GetCurrentProcess(); }
static inline void *get_module_handle(const char *name)
{ return GetModuleHandleA(name); }
static inline void initialize_object_attributes
( object_attributes_t *pobject_attr, unicode_string_t *name
, unsigned long attr, void *rootdir, void *security_descr)
{
pobject_attr->Length = sizeof(object_attributes_t);
pobject_attr->RootDirectory = rootdir;
pobject_attr->Attributes = attr;
pobject_attr->ObjectName = name;
pobject_attr->SecurityDescriptor = security_descr;
pobject_attr->SecurityQualityOfService = 0;
}
static inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, unsigned short bufSize)
{
ucStr->Buffer = buf;
ucStr->Length = 0;
ucStr->MaximumLength = bufSize;
}
//Complex winapi based functions...
//pszFilename must have room for at least MaxPath+1 characters
static inline bool get_file_name_from_handle_function
(void * hFile, wchar_t *pszFilename, std::size_t length, std::size_t &out_length)
{
if(length <= MaxPath){
return false;
}
void *hiPSAPI = load_library("PSAPI.DLL");
if (0 == hiPSAPI)
return 0;
class library_unloader
{
void *lib_;
public:
library_unloader(void *module) : lib_(module){}
~library_unloader(){ free_library(lib_); }
} unloader(hiPSAPI);
// Pointer to function getMappedFileName() in PSAPI.DLL
GetMappedFileName_t pfGMFN =
(GetMappedFileName_t)get_proc_address(hiPSAPI, "GetMappedFileNameW");
if (! pfGMFN){
return 0; // Failed: unexpected error
}
bool bSuccess = false;
// Create a file mapping object.
void * hFileMap = create_file_mapping(hFile, page_readonly, 0, 1, 0);
if(hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = map_view_of_file_ex(hFileMap, file_map_read, 0, 0, 1, 0);
if (pMem){
out_length = pfGMFN(get_current_process(), pMem, pszFilename, MaxPath);
if(out_length){
bSuccess = true;
}
unmap_view_of_file(pMem);
}
close_handle(hFileMap);
}
return(bSuccess);
}
static inline bool get_system_time_of_day_information(system_timeofday_information &info)
{
NtQuerySystemInformation_t pNtQuerySystemInformation = (NtQuerySystemInformation_t)
get_proc_address(get_module_handle("ntdll.dll"), "NtQuerySystemInformation");
unsigned long res;
long status = pNtQuerySystemInformation(system_time_of_day_information, &info, sizeof(info), &res);
if(status){
return false;
}
return true;
}
static inline bool get_boot_time(unsigned char (&bootstamp) [BootstampLength])
{
system_timeofday_information info;
bool ret = get_system_time_of_day_information(info);
if(!ret){
return false;
}
std::memcpy(&bootstamp[0], &info.Reserved1, sizeof(bootstamp));
return true;
}
static inline bool get_boot_and_system_time(unsigned char (&bootsystemstamp) [BootAndSystemstampLength])
{
system_timeofday_information info;
bool ret = get_system_time_of_day_information(info);
if(!ret){
return false;
}
std::memcpy(&bootsystemstamp[0], &info.Reserved1, sizeof(bootsystemstamp));
return true;
}
static inline bool get_boot_time_str(char *bootstamp_str, std::size_t &s) //will write BootstampLength chars
{
if(s < (BootstampLength*2))
return false;
system_timeofday_information info;
bool ret = get_system_time_of_day_information(info);
if(!ret){
return false;
}
const char Characters [] =
{ '0', '1', '2', '3', '4', '5', '6', '7'
, '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
std::size_t char_counter = 0;
for(std::size_t i = 0; i != static_cast<std::size_t>(BootstampLength); ++i){
bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4];
bootstamp_str[char_counter++] = Characters[(info.Reserved1[i]&0x0F)];
}
s = BootstampLength*2;
return true;
}
static inline bool get_boot_and_system_time_wstr(wchar_t *bootsystemstamp, std::size_t &s) //will write BootAndSystemstampLength chars
{
if(s < (BootAndSystemstampLength*2))
return false;
system_timeofday_information info;
bool ret = get_system_time_of_day_information(info);
if(!ret){
return false;
}
const wchar_t Characters [] =
{ L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7'
, L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F' };
std::size_t char_counter = 0;
for(std::size_t i = 0; i != static_cast<std::size_t>(BootAndSystemstampLength); ++i){
bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4];
bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)];
}
s = BootAndSystemstampLength*2;
return true;
}
static inline bool unlink_file(const char *filename)
{
try{
NtSetInformationFile_t pNtSetInformationFile =
(NtSetInformationFile_t)get_proc_address(get_module_handle("ntdll.dll"), "NtSetInformationFile");
if(!pNtSetInformationFile){
return false;
}
NtQueryObject_t pNtQueryObject =
(NtQueryObject_t)get_proc_address(get_module_handle("ntdll.dll"), "NtQueryObject");
//First step: Obtain a handle to the file using Win32 rules. This resolves relative paths
void *fh = create_file(filename, generic_read | delete_access, open_existing,
file_flag_backup_semantics | file_flag_delete_on_close);
if(fh == invalid_handle_value){
return false;
}
class handle_closer
{
void *handle_;
public:
handle_closer(void *handle) : handle_(handle){}
~handle_closer(){ close_handle(handle_); }
} handle_closer(fh);
const std::size_t CharArraySize = 32767; //Max name length
union mem_t
{
object_name_information_t name;
struct ren_t
{
file_rename_information_t info;
wchar_t buf[CharArraySize];
} ren;
};
class auto_ptr
{
public:
explicit auto_ptr(mem_t *ptr) : ptr_(ptr){}
~auto_ptr(){ delete ptr_; }
mem_t *get() const{ return (ptr_); }
mem_t *operator->() const{ return this->get(); }
private:
mem_t *ptr_;
} pmem(new mem_t);
file_rename_information_t *pfri = (file_rename_information_t*)&pmem->ren.info;
const std::size_t RenMaxNumChars =
((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t);
//Obtain file name
unsigned long size;
if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(mem_t), &size)){
return false;
}
//Copy filename to the rename member
std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length);
std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t);
//Second step: obtain the complete native-nt filename
//if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){
//return 0;
//}
//Add trailing mark
if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){
return false;
}
//Search '\\' character to replace it
for(std::size_t i = filename_string_length; i != 0; --filename_string_length){
if(pmem->ren.info.FileName[--i] == L'\\')
break;
}
//Add random number
std::size_t s = RenMaxNumChars - filename_string_length;
if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){
return false;
}
filename_string_length += s;
//Fill rename information (FileNameLength is in bytes)
pfri->FileNameLength = static_cast<unsigned long>(sizeof(wchar_t)*(filename_string_length));
pfri->Replace = 1;
pfri->RootDir = 0;
//Final step: change the name of the in-use file:
io_status_block_t io;
if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(mem_t::ren_t), file_rename_information)){
return false;
}
return true;
}
catch(...){
return false;
}
}
} //namespace winapi
} //namespace interprocess
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifdef BOOST_INTERPROCESS_WIN32_SYNC_PRIMITIVES_HPP

View File

@@ -0,0 +1,132 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_DETAIL_WORKAROUND_HPP
#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
#define BOOST_INTERPROCESS_WINDOWS
/*
#if !defined(_MSC_EXTENSIONS)
#error "Turn on Microsoft language extensions (_MSC_EXTENSIONS) to be able to call Windows API functions"
#endif
*/
#endif
#if !(defined BOOST_INTERPROCESS_WINDOWS)
#include <unistd.h>
#if ((_POSIX_THREAD_PROCESS_SHARED - 0) > 0)
//Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not implement it.
//Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but does not seems to work.
# if !defined(__CYGWIN__) && !defined(__APPLE__)
# define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
# endif
#endif
#if ((_POSIX_BARRIERS - 0) > 0)
# define BOOST_INTERPROCESS_POSIX_BARRIERS
# endif
#if ((_POSIX_SEMAPHORES - 0) > 0)
# define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
# if defined(__CYGWIN__)
#define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK
# endif
//#elif defined(__APPLE__)
//# define BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
#endif
#if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\
((defined _V6_LP64_OFF64) &&(_V6_LP64_OFF64 - 0 > 0)) ||\
((defined _V6_LPBIG_OFFBIG) &&(_V6_LPBIG_OFFBIG - 0 > 0)) ||\
((defined _XBS5_ILP32_OFFBIG)&&(_XBS5_ILP32_OFFBIG - 0 > 0)) ||\
((defined _XBS5_LP64_OFF64) &&(_XBS5_LP64_OFF64 - 0 > 0)) ||\
((defined _XBS5_LPBIG_OFFBIG)&&(_XBS5_LPBIG_OFFBIG - 0 > 0)) ||\
((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))||\
((defined _FILE_OFFSET_BITS) &&(_FILE_OFFSET_BITS - 0 >= 64))
#define BOOST_INTERPROCESS_UNIX_64_BIT_OR_BIGGER_OFF_T
#else
#endif
#if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0)
# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
#else
//VMS and MACOS don't define it but the have shm_open/close interface
# if defined(__vms)
# if __CRTL_VER >= 70200000
# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
# endif
# define BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS
//Mac OS has some non-conformant features like names limited to SHM_NAME_MAX
//# elif defined (__APPLE__)
//# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
# endif
#endif
#if ((_POSIX_TIMEOUTS - 0) > 0)
# define BOOST_INTERPROCESS_POSIX_TIMEOUTS
#endif
//Some systems have filesystem-based resources, so the
//portable "/shmname" format does not work due to permission issues
//For those systems we need to form a path to a temporary directory:
// hp-ux tru64 vms freebsd
#if defined(__hpux) || defined(__osf__) || defined(__vms) || defined(__FreeBSD__)
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES
#endif
#ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
#if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES)
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
#endif
#endif
#ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES
#if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES)
#define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
#endif
#endif
#if ((_POSIX_VERSION + 0)>= 200112L || (_XOPEN_VERSION + 0)>= 500)
#define BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES
#endif
#endif
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\
&& !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL)
#define BOOST_INTERPROCESS_PERFECT_FORWARDING
#endif
//Now declare some Boost.Interprocess features depending on the implementation
#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK)
#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
#endif
#if defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK)
#define BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES
#endif
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP

View File

@@ -0,0 +1,233 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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.
//
// Parts of this code are taken from boost::filesystem library
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Beman Dawes
// Copyright (C) 2001 Dietmar Kuehl
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
// at http://www.boost.org/LICENSE_1_0.txt)
//
// See library home page at http://www.boost.org/libs/filesystem
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ERRORS_HPP
#define BOOST_INTERPROCESS_ERRORS_HPP
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <stdarg.h>
#include <string>
#if (defined BOOST_INTERPROCESS_WINDOWS)
# include <boost/interprocess/detail/win32_api.hpp>
#else
# ifdef BOOST_HAS_UNISTD_H
# include <errno.h> //Errors
# include <cstring> //strerror
# else //ifdef BOOST_HAS_UNISTD_H
# error Unknown platform
# endif //ifdef BOOST_HAS_UNISTD_H
#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
//!\file
//!Describes the error numbering of interprocess classes
namespace boost {
namespace interprocess {
/// @cond
static inline int system_error_code() // artifact of POSIX and WINDOWS error reporting
{
#if (defined BOOST_INTERPROCESS_WINDOWS)
return winapi::get_last_error();
#else
return errno; // GCC 3.1 won't accept ::errno
#endif
}
#if (defined BOOST_INTERPROCESS_WINDOWS)
inline 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
reinterpret_cast<char *>(&lpMsgBuf),
0,
0
);
str += static_cast<const char*>(lpMsgBuf);
winapi::local_free( lpMsgBuf ); // free the buffer
while ( str.size()
&& (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') )
str.erase( str.size()-1 );
}
# else
static inline void fill_system_message( int system_error, std::string &str)
{ str = std::strerror(system_error); }
# endif
/// @endcond
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,
corrupted_error,
not_such_file_or_directory,
invalid_argument
};
typedef int native_error_t;
/// @cond
struct ec_xlate
{
native_error_t sys_ec;
error_code_t ec;
};
static const ec_xlate ec_table[] =
{
#if (defined BOOST_INTERPROCESS_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 //#if (defined BOOST_INTERPROCESS_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 },
{ ENOENT, not_such_file_or_directory },
{ EINVAL, invalid_argument }
#endif //#if (defined BOOST_INTERPROCESS_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;
};
/// @endcond
} // namespace interprocess {
} // namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif // BOOST_INTERPROCESS_ERRORS_HPP

View File

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

View File

@@ -0,0 +1,188 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FILE_MAPPING_HPP
#define BOOST_INTERPROCESS_FILE_MAPPING_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/move.hpp>
#include <string> //std::string
//!\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
{
/// @cond
//Non-copyable and non-assignable
file_mapping(file_mapping &);
file_mapping &operator=(file_mapping &);
/// @endcond
public:
BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_mapping)
//!Constructs an empty file mapping.
//!Does not throw
file_mapping();
//!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 "read_only" or read-write "read_write"
//!modes. Throws interprocess_exception on error.
file_mapping(const char *filename, mode_t mode);
//!Moves the ownership of "moved"'s file mapping object to *this.
//!After the call, "moved" does not represent any file mapping object.
//!Does not throw
file_mapping(BOOST_INTERPROCESS_RV_REF(file_mapping) moved)
: m_handle(file_handle_t(detail::invalid_file()))
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file mapping to *this.
//!After the call, "moved" does not represent any file mapping.
//!Does not throw
file_mapping &operator=(BOOST_INTERPROCESS_RV_REF(file_mapping) moved)
{
file_mapping tmp(boost::interprocess::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps to file_mappings.
//!Does not throw.
void swap(file_mapping &other);
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Obtains the mapping handle
//!to be used with mapped_region
mapping_handle_t get_mapping_handle() const;
//!Destroys the file mapping. All mapped regions created from this are still
//!valid. Does not throw
~file_mapping();
//!Returns the name of the file
//!used in the constructor.
const char *get_name() const;
//!Removes the file named "filename" even if it's been memory mapped.
//!Returns true on success.
//!The function might fail in some operating systems if the file is
//!being used other processes and no deletion permission was shared.
static bool remove(const char *filename);
/// @cond
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
/// @endcond
};
inline file_mapping::file_mapping()
: m_handle(file_handle_t(detail::invalid_file()))
{}
inline file_mapping::~file_mapping()
{ this->priv_close(); }
inline const char *file_mapping::get_name() const
{ return m_filename.c_str(); }
inline void file_mapping::swap(file_mapping &other)
{
std::swap(m_handle, other.m_handle);
std::swap(m_mode, other.m_mode);
m_filename.swap(other.m_filename);
}
inline mapping_handle_t file_mapping::get_mapping_handle() const
{ return detail::mapping_handle_from_file_handle(m_handle); }
inline mode_t file_mapping::get_mode() const
{ return m_mode; }
inline file_mapping::file_mapping
(const char *filename, mode_t mode)
: m_filename(filename)
{
//Check accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
//Open file
m_handle = detail::open_existing_file(filename, mode);
//Check for error
if(m_handle == detail::invalid_file()){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
m_mode = mode;
}
inline bool file_mapping::remove(const char *filename)
{ return detail::delete_file(filename); }
///@cond
inline void file_mapping::priv_close()
{
if(m_handle != detail::invalid_file()){
detail::close_file(m_handle);
m_handle = detail::invalid_file();
}
}
///@endcond
//!A class that stores the name of a file
//!and tries to remove it in its destructor
//!Useful to remove temporary files in the presence
//!of exceptions
class remove_file_on_destroy
{
const char * m_name;
public:
remove_file_on_destroy(const char *name)
: m_name(name)
{}
~remove_file_on_destroy()
{ detail::delete_file(m_name); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP

View File

@@ -0,0 +1,78 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FLAT_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
//!\file
//!Describes index adaptor of boost::map container, to use it
//!as name/shared memory index
//[flat_map_index
namespace boost { namespace interprocess {
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct flat_map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef typename MapConfig::
segment_manager_base segment_manager_base;
typedef std::less<key_type> key_less;
typedef std::pair<key_type, mapped_type> value_type;
typedef allocator<value_type
,segment_manager_base> allocator_type;
typedef flat_map<key_type, mapped_type,
key_less, allocator_type> index_t;
};
//!Index type based in flat_map. Just derives from flat_map and
//!defines the interface needed by managed memory segments.
template <class MapConfig>
class flat_map_index
//Derive class from flat_map specialization
: public flat_map_index_aux<MapConfig>::index_t
{
/// @cond
typedef flat_map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename index_aux::
segment_manager_base segment_manager_base;
/// @endcond
public:
//!Constructor. Takes a pointer to the segment manager. Can throw
flat_map_index(segment_manager_base *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); }
//!This frees all unnecessary memory
void shrink_to_fit()
{ base_type::shrink_to_fit(); }
};
}} //namespace boost { namespace interprocess
//]
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FLAT_MAP_INDEX_HPP

View File

@@ -0,0 +1,150 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_ISET_INDEX_HPP
#define BOOST_INTERPROCESS_ISET_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <string>
#include <functional>
#include <utility>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/intrusive/set.hpp>
//!\file
//!Describes index adaptor of boost::intrusive::set container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
/// @cond
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct iset_index_aux
{
typedef typename
MapConfig::segment_manager_base segment_manager_base;
typedef typename
segment_manager_base::void_pointer void_pointer;
typedef typename bi::make_set_base_hook
< bi::void_pointer<void_pointer>
, bi::optimize_size<true>
>::type derivation_hook;
typedef typename MapConfig::template
intrusive_value_type<derivation_hook>::type value_type;
typedef std::less<value_type> value_compare;
typedef typename bi::make_set
< value_type
, bi::base_hook<derivation_hook>
>::type index_t;
};
/// @endcond
//!Index type based in boost::intrusive::set.
//!Just derives from boost::intrusive::set
//!and defines the interface needed by managed memory segments*/
template <class MapConfig>
class iset_index
//Derive class from map specialization
: public iset_index_aux<MapConfig>::index_t
{
/// @cond
typedef iset_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t index_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
typedef typename MapConfig::char_type char_type;
/// @endcond
public:
typedef typename index_type::iterator iterator;
typedef typename index_type::const_iterator const_iterator;
typedef typename index_type::insert_commit_data insert_commit_data;
typedef typename index_type::value_type value_type;
/// @cond
private:
struct intrusive_key_value_less
{
bool operator()(const intrusive_compare_key_type &i, const value_type &b) const
{
std::size_t blen = b.name_length();
return (i.m_len < blen) ||
(i.m_len == blen &&
std::char_traits<char_type>::compare
(i.mp_str, b.name(), i.m_len) < 0);
}
bool operator()(const value_type &b, const intrusive_compare_key_type &i) const
{
std::size_t blen = b.name_length();
return (blen < i.m_len) ||
(blen == i.m_len &&
std::char_traits<char_type>::compare
(b.name(), i.mp_str, i.m_len) < 0);
}
};
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
iset_index(typename MapConfig::segment_manager_base *)
: index_type(/*typename index_aux::value_compare()*/)
{}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(std::size_t)
{ /*Does nothing, map has not reserve or rehash*/ }
//!This frees all unnecessary memory
void shrink_to_fit()
{ /*Does nothing, this intrusive index does not allocate memory;*/ }
iterator find(const intrusive_compare_key_type &key)
{ return index_type::find(key, intrusive_key_value_less()); }
const_iterator find(const intrusive_compare_key_type &key) const
{ return index_type::find(key, intrusive_key_value_less()); }
std::pair<iterator, bool>insert_check
(const intrusive_compare_key_type &key, insert_commit_data &commit_data)
{ return index_type::insert_check(key, intrusive_key_value_less(), commit_data); }
};
/// @cond
//!Trait class to detect if an index is an intrusive
//!index.
template<class MapConfig>
struct is_intrusive_index
<boost::interprocess::iset_index<MapConfig> >
{
enum{ value = true };
};
/// @endcond
} //namespace interprocess {
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP

View File

@@ -0,0 +1,367 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_IUNORDERED_SET_INDEX_HPP
#define BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/get_pointer.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/intrusive/unordered_set.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
//!\file
//!Describes index adaptor of boost::intrusive::unordered_set container, to use it
//!as name/shared memory index
namespace boost { namespace interprocess {
/// @cond
//!Helper class to define typedefs
//!from IndexTraits
template <class MapConfig>
struct iunordered_set_index_aux
{
typedef typename
MapConfig::segment_manager_base segment_manager_base;
typedef typename
segment_manager_base::void_pointer void_pointer;
typedef typename bi::make_unordered_set_base_hook
< bi::void_pointer<void_pointer>
>::type derivation_hook;
typedef typename MapConfig::template
intrusive_value_type<derivation_hook>::type value_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
typedef std::equal_to<value_type> value_equal;
typedef typename MapConfig::char_type char_type;
struct equal_function
{
bool operator()(const intrusive_compare_key_type &i, const value_type &b) const
{
return (i.m_len == b.name_length()) &&
(std::char_traits<char_type>::compare
(i.mp_str, b.name(), i.m_len) == 0);
}
bool operator()(const value_type &b, const intrusive_compare_key_type &i) const
{
return (i.m_len == b.name_length()) &&
(std::char_traits<char_type>::compare
(i.mp_str, b.name(), i.m_len) == 0);
}
bool operator()(const value_type &b1, const value_type &b2) const
{
return (b1.name_length() == b2.name_length()) &&
(std::char_traits<char_type>::compare
(b1.name(), b2.name(), b1.name_length()) == 0);
}
};
struct hash_function
: std::unary_function<value_type, std::size_t>
{
std::size_t operator()(const value_type &val) const
{
const char_type *beg = detail::get_pointer(val.name()),
*end = beg + val.name_length();
return boost::hash_range(beg, end);
}
std::size_t operator()(const intrusive_compare_key_type &i) const
{
const char_type *beg = i.mp_str,
*end = beg + i.m_len;
return boost::hash_range(beg, end);
}
};
typedef typename bi::make_unordered_set
< value_type
, bi::hash<hash_function>
, bi::equal<equal_function>
>::type index_t;
typedef typename index_t::bucket_type bucket_type;
typedef allocator
<bucket_type, segment_manager_base> allocator_type;
struct allocator_holder
{
allocator_holder(segment_manager_base *mngr)
: alloc(mngr)
{}
allocator_type alloc;
bucket_type init_bucket;
};
};
/// @endcond
//!Index type based in boost::intrusive::set.
//!Just derives from boost::intrusive::set
//!and defines the interface needed by managed memory segments
template <class MapConfig>
class iunordered_set_index
//Derive class from map specialization
: private iunordered_set_index_aux<MapConfig>::allocator_holder
, public iunordered_set_index_aux<MapConfig>::index_t
{
/// @cond
typedef iunordered_set_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t index_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
typedef typename index_aux::equal_function equal_function;
typedef typename index_aux::hash_function hash_function;
typedef typename MapConfig::char_type char_type;
typedef typename
iunordered_set_index_aux<MapConfig>::allocator_type allocator_type;
typedef typename
iunordered_set_index_aux<MapConfig>::allocator_holder allocator_holder;
/// @endcond
public:
typedef typename index_type::iterator iterator;
typedef typename index_type::const_iterator const_iterator;
typedef typename index_type::insert_commit_data insert_commit_data;
typedef typename index_type::value_type value_type;
typedef typename index_type::bucket_ptr bucket_ptr;
typedef typename index_type::bucket_type bucket_type;
typedef typename index_type::bucket_traits bucket_traits;
typedef typename index_type::size_type size_type;
/// @cond
private:
typedef typename index_aux::
segment_manager_base segment_manager_base;
enum { InitBufferSize = 64};
static bucket_ptr create_buckets(allocator_type &alloc, std::size_t num)
{
num = index_type::suggested_upper_bucket_count(num);
bucket_ptr buckets = alloc.allocate(num);
bucket_ptr buckets_init = buckets;
for(std::size_t i = 0; i < num; ++i){
new(get_pointer(buckets_init++))bucket_type();
}
return buckets;
}
static std::size_t shrink_buckets
( bucket_ptr buckets, std::size_t old_size
, allocator_type &alloc, std::size_t new_size)
{
if(old_size <= new_size )
return old_size;
std::size_t received_size;
if(!alloc.allocation_command
(boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, new_size, received_size, buckets).first){
return old_size;
}
for( bucket_type *p = detail::get_pointer(buckets) + received_size
, *pend = detail::get_pointer(buckets) + old_size
; p != pend
; ++p){
p->~bucket_type();
}
bucket_ptr shunk_p = alloc.allocation_command
(boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, received_size, buckets).first;
BOOST_ASSERT(buckets == shunk_p);
bucket_ptr buckets_init = buckets + received_size;
for(std::size_t i = 0; i < (old_size - received_size); ++i){
get_pointer(buckets_init++)->~bucket_type();
}
return received_size;
}
static bucket_ptr expand_or_create_buckets
( bucket_ptr old_buckets, const std::size_t old_num
, allocator_type &alloc, const std::size_t new_num)
{
std::size_t received_size;
std::pair<bucket_ptr, bool> ret =
alloc.allocation_command
(boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, new_num, received_size, old_buckets);
if(ret.first == old_buckets){
bucket_ptr buckets_init = old_buckets + old_num;
for(std::size_t i = 0; i < (new_num - old_num); ++i){
new(get_pointer(buckets_init++))bucket_type();
}
}
else{
bucket_ptr buckets_init = ret.first;
for(std::size_t i = 0; i < new_num; ++i){
new(get_pointer(buckets_init++))bucket_type();
}
}
return ret.first;
}
static void destroy_buckets
(allocator_type &alloc, bucket_ptr buckets, std::size_t num)
{
bucket_ptr buckets_destroy = buckets;
for(std::size_t i = 0; i < num; ++i){
get_pointer(buckets_destroy++)->~bucket_type();
}
alloc.deallocate(buckets, num);
}
iunordered_set_index<MapConfig>* get_this_pointer()
{ return this; }
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
iunordered_set_index(segment_manager_base *mngr)
: allocator_holder(mngr)
, index_type(bucket_traits(&get_this_pointer()->init_bucket, 1))
{}
~iunordered_set_index()
{
index_type::clear();
if(index_type::bucket_pointer() != bucket_ptr(&this->init_bucket)){
destroy_buckets(this->alloc, index_type::bucket_pointer(), index_type::bucket_count());
}
}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(std::size_t new_n)
{
//Let's maintain a 1.0f load factor
size_type old_n = this->bucket_count();
if(new_n <= old_n)
return;
bucket_ptr old_p = this->bucket_pointer();
new_n = index_type::suggested_upper_bucket_count(new_n);
bucket_ptr new_p;
//This can throw
try{
if(old_p != bucket_ptr(&this->init_bucket))
new_p = expand_or_create_buckets(old_p, old_n, this->alloc, new_n);
else
new_p = create_buckets(this->alloc, new_n);
}
catch(...){
return;
}
//Rehashing does not throw, since neither the hash nor the
//comparison function can throw
this->rehash(bucket_traits(new_p, new_n));
if(new_p != old_p && old_p != bucket_ptr(&this->init_bucket)){
destroy_buckets(this->alloc, old_p, old_n);
}
}
//!This tries to free unused memory
//!previously allocated.
void shrink_to_fit()
{
size_type cur_size = this->size();
size_type cur_count = this->bucket_count();
bucket_ptr old_p = this->bucket_pointer();
if(!this->size() && old_p != bucket_ptr(&this->init_bucket)){
this->rehash(bucket_traits(bucket_ptr(&this->init_bucket), 1));
destroy_buckets(this->alloc, old_p, cur_count);
}
else{
size_type sug_count = 0; //gcc warning
sug_count = index_type::suggested_upper_bucket_count(cur_size);
if(sug_count >= cur_count)
return;
try{
shrink_buckets(old_p, cur_count, this->alloc, sug_count);
}
catch(...){
return;
}
//Rehashing does not throw, since neither the hash nor the
//comparison function can throw
this->rehash(bucket_traits(old_p, sug_count));
}
}
iterator find(const intrusive_compare_key_type &key)
{ return index_type::find(key, hash_function(), equal_function()); }
const_iterator find(const intrusive_compare_key_type &key) const
{ return index_type::find(key, hash_function(), equal_function()); }
std::pair<iterator, bool>insert_check
(const intrusive_compare_key_type &key, insert_commit_data &commit_data)
{ return index_type::insert_check(key, hash_function(), equal_function(), commit_data); }
iterator insert_commit(value_type &val, insert_commit_data &commit_data)
{
iterator it = index_type::insert_commit(val, commit_data);
size_type cur_size = this->size();
if(cur_size > this->bucket_count()){
try{
this->reserve(cur_size);
}
catch(...){
//Strong guarantee: if something goes wrong
//we should remove the insertion.
//
//We can use the iterator because the hash function
//can't throw and this means that "reserve" will
//throw only because of the memory allocation:
//the iterator has not been invalidated.
index_type::erase(it);
throw;
}
}
return it;
}
};
/// @cond
//!Trait class to detect if an index is an intrusive
//!index
template<class MapConfig>
struct is_intrusive_index
<boost::interprocess::iunordered_set_index<MapConfig> >
{
enum{ value = true };
};
/// @endcond
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_IUNORDERED_SET_INDEX_HPP

View File

@@ -0,0 +1,100 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/private_adaptive_pool.hpp>
//!\file
//!Describes index adaptor of boost::map container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
namespace detail{
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef std::less<key_type> key_less;
typedef std::pair<const key_type, mapped_type> value_type;
typedef private_adaptive_pool
<value_type,
typename MapConfig::
segment_manager_base> allocator_type;
typedef boost::interprocess::map
<key_type, mapped_type,
key_less, allocator_type> index_t;
};
} //namespace detail {
//!Index type based in boost::interprocess::map. Just derives from boost::interprocess::map
//!and defines the interface needed by managed memory segments
template <class MapConfig>
class map_index
//Derive class from map specialization
: public detail::map_index_aux<MapConfig>::index_t
{
/// @cond
typedef detail::map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename MapConfig::
segment_manager_base segment_manager_base;
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
map_index(segment_manager_base *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)
{ /*Does nothing, map has not reserve or rehash*/ }
//!This tries to free previously allocate
//!unused memory.
void shrink_to_fit()
{ base_type::get_stored_allocator().deallocate_free_blocks(); }
};
/// @cond
//!Trait class to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template<class MapConfig>
struct is_node_index
<boost::interprocess::map_index<MapConfig> >
{
enum { value = true };
};
/// @endcond
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MAP_INDEX_HPP

View File

@@ -0,0 +1,68 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_NULL_INDEX_HPP
#define BOOST_INTERPROCESS_NULL_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/offset_ptr.hpp>
//!\file
//!Describes a null index adaptor, so that if we don't want to construct
//!named objects, we can use this null index type to save resources.
namespace boost {
namespace interprocess {
//!Null index type
//!used to save compilation time when
//!named indexes are not needed.
template <class MapConfig>
class null_index
{
/// @cond
typedef typename MapConfig::
segment_manager_base segment_manager_base;
/// @endcond
public:
typedef void * iterator;
typedef const void * const_iterator;
//!begin() is equal
//!to end()
const_iterator begin() const
{ return const_iterator(0); }
//!begin() is equal
//!to end()
iterator begin()
{ return iterator(0); }
//!begin() is equal
//!to end()
const_iterator end() const
{ return const_iterator(0); }
//!begin() is equal
//!to end()
iterator end()
{ return iterator(0); }
//!Empty constructor
null_index(segment_manager_base *){}
};
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NULL_INDEX_HPP

View File

@@ -0,0 +1,113 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_UNORDERED_MAP_INDEX_HPP
#define BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <functional>
#include <utility>
#include <boost/unordered_map.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/allocators/private_adaptive_pool.hpp>
//!\file
//!Describes index adaptor of boost::unordered_map container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
///@cond
//!Helper class to define typedefs from
//!IndexTraits
template <class MapConfig>
struct unordered_map_index_aux
{
typedef typename MapConfig::key_type key_type;
typedef typename MapConfig::mapped_type mapped_type;
typedef std::equal_to<key_type> key_equal;
typedef std::pair<const key_type, mapped_type> value_type;
typedef private_adaptive_pool
<value_type,
typename MapConfig::
segment_manager_base> allocator_type;
struct hasher
: std::unary_function<key_type, std::size_t>
{
std::size_t operator()(const key_type &val) const
{
typedef typename key_type::char_type char_type;
const char_type *beg = detail::get_pointer(val.mp_str),
*end = beg + val.m_len;
return boost::hash_range(beg, end);
}
};
typedef unordered_map<key_type, mapped_type, hasher,
key_equal, allocator_type> index_t;
};
///@endcond
//!Index type based in unordered_map. Just derives from unordered_map and
//!defines the interface needed by managed memory segments
template <class MapConfig>
class unordered_map_index
//Derive class from unordered_map specialization
: public unordered_map_index_aux<MapConfig>::index_t
{
/// @cond
typedef unordered_map_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t base_type;
typedef typename
MapConfig::segment_manager_base segment_manager_base;
/// @endcond
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
unordered_map_index(segment_manager_base *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); }
//!This tries to free previously allocate
//!unused memory.
void shrink_to_fit()
{ base_type::rehash(base_type::size()); }
};
/// @cond
//!Trait class to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template<class MapConfig>
struct is_node_index
<boost::interprocess::unordered_map_index<MapConfig> >
{
enum { value = true };
};
/// @endcond
}} //namespace boost { namespace interprocess {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_UNORDERED_MAP_INDEX_HPP

View File

@@ -0,0 +1,415 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_FWD_HPP
#define BOOST_INTERPROCESS_FWD_HPP
#if defined (_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <cstddef>
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
/// @cond
namespace boost{
namespace intrusive{
}}
namespace boost{
namespace interprocess{
namespace bi = boost::intrusive;
}}
namespace std {
template <class T>
class allocator;
template <class T>
struct less;
template <class T1, class T2>
struct pair;
template <class CharType>
struct char_traits;
} //namespace std {
/// @endcond
namespace boost { namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
// shared_memory
//////////////////////////////////////////////////////////////////////////////
class shared_memory_object;
#if defined (BOOST_INTERPROCESS_WINDOWS)
class windows_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
//////////////////////////////////////////////////////////////////////////////
// mapped file/mapped region/mapped_file
//////////////////////////////////////////////////////////////////////////////
class file_mapping;
class mapped_region;
class mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Mutexes
//////////////////////////////////////////////////////////////////////////////
class null_mutex;
class interprocess_mutex;
class interprocess_recursive_mutex;
class named_mutex;
class named_recursive_mutex;
class interprocess_semaphore;
class named_semaphore;
//////////////////////////////////////////////////////////////////////////////
// Mutex families
//////////////////////////////////////////////////////////////////////////////
struct mutex_family;
struct null_mutex_family;
//////////////////////////////////////////////////////////////////////////////
// Other synchronization classes
//////////////////////////////////////////////////////////////////////////////
class barrier;
class interprocess_sharable_mutex;
class interprocess_condition;
//////////////////////////////////////////////////////////////////////////////
// Locks
//////////////////////////////////////////////////////////////////////////////
template <class Mutex>
class scoped_lock;
template <class SharableMutex>
class sharable_lock;
template <class UpgradableMutex>
class upgradable_lock;
//////////////////////////////////////////////////////////////////////////////
// STL compatible allocators
//////////////////////////////////////////////////////////////////////////////
template<class T, class SegmentManager>
class allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class private_node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64>
class cached_node_allocator;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class adaptive_pool;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class private_adaptive_pool;
template<class T, class SegmentManager, std::size_t NodesPerBlock = 64, std::size_t MaxFreeBlocks = 2
, unsigned char OverheadPercent = 5
>
class cached_adaptive_pool;
//////////////////////////////////////////////////////////////////////////////
// offset_ptr
//////////////////////////////////////////////////////////////////////////////
template <class T>
class offset_ptr;
//////////////////////////////////////////////////////////////////////////////
// Memory allocation algorithms
//////////////////////////////////////////////////////////////////////////////
//Single segment memory allocation algorithms
template<class MutexFamily, class VoidMutex = offset_ptr<void> >
class simple_seq_fit;
template<class MutexFamily, class VoidMutex = offset_ptr<void>, std::size_t MemAlignment = 0>
class rbtree_best_fit;
//////////////////////////////////////////////////////////////////////////////
// Index Types
//////////////////////////////////////////////////////////////////////////////
template<class IndexConfig> class flat_map_index;
template<class IndexConfig> class iset_index;
template<class IndexConfig> class iunordered_set_index;
template<class IndexConfig> class map_index;
template<class IndexConfig> class null_index;
template<class IndexConfig> class unordered_map_index;
//////////////////////////////////////////////////////////////////////////////
// Segment manager
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class segment_manager;
//////////////////////////////////////////////////////////////////////////////
// External buffer managed memory classes
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_external_buffer;
typedef basic_managed_external_buffer
<char
,rbtree_best_fit<null_mutex_family>
,iset_index>
managed_external_buffer;
typedef basic_managed_external_buffer
<wchar_t
,rbtree_best_fit<null_mutex_family>
,iset_index>
wmanaged_external_buffer;
//////////////////////////////////////////////////////////////////////////////
// managed memory classes
//////////////////////////////////////////////////////////////////////////////
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_shared_memory;
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Windows shared memory managed memory classes
//////////////////////////////////////////////////////////////////////////////
#if defined (BOOST_INTERPROCESS_WINDOWS)
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_windows_shared_memory;
typedef basic_managed_windows_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_windows_shared_memory;
typedef basic_managed_windows_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_windows_shared_memory;
#else
template <class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_xsi_shared_memory;
typedef basic_managed_xsi_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_xsi_shared_memory;
typedef basic_managed_xsi_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_xsi_shared_memory;
#endif //#if defined (BOOST_INTERPROCESS_WINDOWS)
//////////////////////////////////////////////////////////////////////////////
// Fixed address shared memory
//////////////////////////////////////////////////////////////////////////////
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family, void*>
,iset_index>
fixed_managed_shared_memory;
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family, void*>
,iset_index>
wfixed_managed_shared_memory;
//////////////////////////////////////////////////////////////////////////////
// Heap memory managed memory classes
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_heap_memory;
typedef basic_managed_heap_memory
<char
,rbtree_best_fit<null_mutex_family>
,iset_index>
managed_heap_memory;
typedef basic_managed_heap_memory
<wchar_t
,rbtree_best_fit<null_mutex_family>
,iset_index>
wmanaged_heap_memory;
//////////////////////////////////////////////////////////////////////////////
// Mapped file managed memory classes
//////////////////////////////////////////////////////////////////////////////
template
<class CharType
,class MemoryAlgorithm
,template<class IndexConfig> class IndexType>
class basic_managed_mapped_file;
typedef basic_managed_mapped_file
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_mapped_file;
typedef basic_managed_mapped_file
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_mapped_file;
//////////////////////////////////////////////////////////////////////////////
// Exceptions
//////////////////////////////////////////////////////////////////////////////
class interprocess_exception;
class lock_exception;
class bad_alloc;
//////////////////////////////////////////////////////////////////////////////
// Bufferstream
//////////////////////////////////////////////////////////////////////////////
//bufferstream
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferbuf;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_ibufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_obufferstream;
template <class CharT
,class CharTraits = std::char_traits<CharT> >
class basic_bufferstream;
//////////////////////////////////////////////////////////////////////////////
// Vectorstream
//////////////////////////////////////////////////////////////////////////////
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorbuf;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ivectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_ovectorstream;
template <class CharVector
,class CharTraits = std::char_traits<typename CharVector::value_type> >
class basic_vectorstream;
//////////////////////////////////////////////////////////////////////////////
// Smart pointers
//////////////////////////////////////////////////////////////////////////////
template<class T, class Deleter>
class scoped_ptr;
template<class T, class VoidPointer>
class intrusive_ptr;
template<class T, class VoidAllocator, class Deleter>
class shared_ptr;
template<class T, class VoidAllocator, class Deleter>
class weak_ptr;
//////////////////////////////////////////////////////////////////////////////
// IPC
//////////////////////////////////////////////////////////////////////////////
class message_queue;
}} //namespace boost { namespace interprocess {
//////////////////////////////////////////////////////////////////////////////
// CONTAINERS
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP

View File

@@ -0,0 +1,637 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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_MESSAGE_QUEUE_HPP
#define BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <algorithm> //std::lower_bound
#include <cstddef> //std::size_t
#include <cstring> //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
{
/// @cond
//Blocking modes
enum block_t { blocking, timed, non_blocking };
message_queue();
/// @endcond
public:
//!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". Throws on error and if the queue was previously created.
message_queue(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. Throws on error.
message_queue(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,
//!throws an error.
message_queue(open_only_t open_only,
const char *name);
//!Destroys *this and indicates that the calling process is finished using
//!the resource. All opened message queues are still
//!valid after destruction. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the message queue from the system
//!use remove().
~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. Throws interprocess_error on error.*/
void send (const void *buffer, std::size_t buffer_size,
unsigned int priority);
//!Sends a message stored in buffer "buffer" with size "buffer_size" through the
//!message queue with priority "priority". If the message queue is full
//!the sender is not blocked and returns false, otherwise returns true.
//!Throws interprocess_error on error.
bool 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 retries until time "abs_time" is reached. Returns true if
//!the message has been successfully sent. Returns false if timeout is reached.
//!Throws interprocess_error on error.
bool 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. Throws interprocess_error on error.
void 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 and returns false, otherwise returns true.
//!Throws interprocess_error on error.
bool 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 true if
//!the message has been successfully sent. Returns false if timeout is reached.
//!Throws interprocess_error on error.
bool 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_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;
//!Returns the number of messages currently stored.
//!Never throws
std::size_t get_num_msg();
//!Removes the message queue from the system.
//!Returns false on error. Never throws
static bool remove(const char *name);
/// @cond
private:
typedef boost::posix_time::ptime ptime;
bool do_receive(block_t block,
void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority,
const ptime &abs_time);
bool do_send(block_t block,
const void *buffer, std::size_t buffer_size,
unsigned int priority, const ptime &abs_time);
//!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);
detail::managed_open_or_create_impl<shared_memory_object> m_shmem;
/// @endcond
};
/// @cond
namespace detail {
//!This header is the prefix of each message in the queue
class 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 priority_functor
{
public:
bool operator()(const offset_ptr<msg_hdr_t> &msg1,
const offset_ptr<msg_hdr_t> &msg2) const
{ return msg1->priority < msg2->priority; }
};
//!This header is placed in the beginning of the shared memory and contains
//!the data to control the queue. This class initializes the shared memory
//!in the following way: in ascending memory address with proper alignment
//!fillings:
//!
//!-> mq_hdr_t:
//! Main control block that controls the rest of the elements
//!
//!-> offset_ptr<msg_hdr_t> index [max_num_msg]
//! An array of pointers with size "max_num_msg" called index. Each pointer
//! points to a preallocated message. The elements of this array are
//! reordered in runtime in the following way:
//!
//! When the current number of messages is "cur_num_msg", the first
//! "cur_num_msg" pointers point to inserted messages and the rest
//! point to free messages. The first "cur_num_msg" pointers are
//! ordered by the priority of the pointed message and by insertion order
//! if two messages have the same priority. So the next message to be
//! used in a "receive" is pointed by index [cur_num_msg-1] and the first free
//! message ready to be used in a "send" operation is index [cur_num_msg].
//! This transforms index in a fixed size priority queue with an embedded free
//! message queue.
//!
//!-> struct message_t
//! {
//! msg_hdr_t header;
//! char[max_msg_size] data;
//! } messages [max_num_msg];
//!
//! An array of buffers of preallocated messages, each one prefixed with the
//! msg_hdr_t structure. Each of this message is pointed by one pointer of
//! the index structure.
class mq_hdr_t
: public detail::priority_functor
{
typedef offset_ptr<msg_hdr_t> msg_hdr_ptr_t;
public:
//!Constructor. This object must be constructed in the beginning of the
//!shared memory of the size returned by the function "get_mem_size".
//!This constructor initializes the needed resources and creates
//!the internal structures like the priority index. This can throw.*/
mq_hdr_t(std::size_t max_num_msg, std::size_t max_msg_size)
: m_max_num_msg(max_num_msg),
m_max_msg_size(max_msg_size),
m_cur_num_msg(0)
{ this->initialize_memory(); }
//!Returns the inserted message with top priority
msg_hdr_t * top_msg()
{ return mp_index[m_cur_num_msg-1].get(); }
//!Returns true if the message queue is full
bool is_full() const
{ return m_cur_num_msg == m_max_num_msg; }
//!Returns true if the message queue is empty
bool is_empty() const
{ return !m_cur_num_msg; }
//!Frees the top priority message and saves it in the free message list
void free_top_msg()
{ --m_cur_num_msg; }
//!Returns the first free msg of the free message queue
msg_hdr_t * free_msg()
{ return mp_index[m_cur_num_msg].get(); }
//!Inserts the first free message in the priority queue
void queue_free_msg()
{
//Get free msg
msg_hdr_ptr_t free = mp_index[m_cur_num_msg];
//Get priority queue's range
msg_hdr_ptr_t *it = &mp_index[0], *it_end = &mp_index[m_cur_num_msg];
//Check where the free message should be placed
it = std::lower_bound(it, it_end, free, static_cast<priority_functor&>(*this));
//Make room in that position
std::copy_backward(it, it_end, it_end+1);
//Insert the free message in the 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 = detail::alignment_of<detail::msg_hdr_t>::value,
index_align = detail::alignment_of<msg_hdr_ptr_t>::value,
r_hdr_size = detail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
r_index_size = detail::get_rounded_size(sizeof(msg_hdr_ptr_t)*max_num_msg, msg_hdr_align),
r_max_msg_size = detail::get_rounded_size(max_msg_size, msg_hdr_align) + sizeof(detail::msg_hdr_t);
return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size) +
detail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset;
}
//!Initializes the memory structures to preallocate messages and constructs the
//!message index. Never throws.
void initialize_memory()
{
const std::size_t
msg_hdr_align = detail::alignment_of<detail::msg_hdr_t>::value,
index_align = detail::alignment_of<msg_hdr_ptr_t>::value,
r_hdr_size = detail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
r_index_size = detail::get_rounded_size(sizeof(msg_hdr_ptr_t)*m_max_num_msg, msg_hdr_align),
r_max_msg_size = detail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(detail::msg_hdr_t);
//Pointer to the index
msg_hdr_ptr_t *index = reinterpret_cast<msg_hdr_ptr_t*>
(reinterpret_cast<char*>(this)+r_hdr_size);
//Pointer to the first message header
detail::msg_hdr_t *msg_hdr = reinterpret_cast<detail::msg_hdr_t*>
(reinterpret_cast<char*>(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::msg_hdr_t*>
(reinterpret_cast<char*>(msg_hdr)+r_max_msg_size);
}
}
public:
//Pointer to the index
offset_ptr<msg_hdr_ptr_t> mp_index;
//Maximum number of messages of the queue
const std::size_t m_max_num_msg;
//Maximum size of messages of the queue
const std::size_t m_max_msg_size;
//Current number of messages
std::size_t m_cur_num_msg;
//Mutex to protect data structures
interprocess_mutex m_mutex;
//Condition block receivers when there are no messages
interprocess_condition m_cond_recv;
//Condition block senders when the queue is full
interprocess_condition m_cond_send;
};
//!This is the atomic functor to be executed when creating or opening
//!shared memory. Never throws
class 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()(void *address, std::size_t, bool created)
{
char *mptr;
if(created){
mptr = reinterpret_cast<char*>(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;
};
} //namespace detail {
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 detail::mq_hdr_t::get_mem_size(max_msg_size, max_num_msg); }
inline message_queue::message_queue(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),
read_write,
static_cast<void*>(0),
//Prepare initialization functor
detail::initialization_func_t (max_num_msg, max_msg_size))
{}
inline message_queue::message_queue(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),
read_write,
static_cast<void*>(0),
//Prepare initialization functor
detail::initialization_func_t (max_num_msg, max_msg_size))
{}
inline message_queue::message_queue(open_only_t open_only,
const char *name)
//Create shared memory and execute functor atomically
: m_shmem(open_only,
name,
read_write,
static_cast<void*>(0),
//Prepare initialization functor
detail::initialization_func_t ())
{}
inline void message_queue::send
(const void *buffer, std::size_t buffer_size, unsigned int priority)
{ this->do_send(blocking, buffer, buffer_size, priority, ptime()); }
inline bool message_queue::try_send
(const void *buffer, std::size_t buffer_size, unsigned int priority)
{ return this->do_send(non_blocking, buffer, buffer_size, priority, ptime()); }
inline bool message_queue::timed_send
(const void *buffer, std::size_t buffer_size
,unsigned int priority, const boost::posix_time::ptime &abs_time)
{
if(abs_time == boost::posix_time::pos_infin){
this->send(buffer, buffer_size, priority);
return true;
}
return this->do_send(timed, buffer, buffer_size, priority, abs_time);
}
inline bool message_queue::do_send(block_t block,
const void *buffer, std::size_t buffer_size,
unsigned int priority, const boost::posix_time::ptime &abs_time)
{
detail::mq_hdr_t *p_hdr = static_cast<detail::mq_hdr_t*>(m_shmem.get_user_address());
//Check if buffer is smaller than maximum allowed
if (buffer_size > p_hdr->m_max_msg_size) {
throw interprocess_exception(size_error);
}
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
{
//If the queue is full execute blocking logic
if (p_hdr->is_full()) {
switch(block){
case non_blocking :
return false;
break;
case blocking :
do{
p_hdr->m_cond_send.wait(lock);
}
while (p_hdr->is_full());
break;
case timed :
do{
if(!p_hdr->m_cond_send.timed_wait(lock, abs_time)){
if(p_hdr->is_full())
return false;
break;
}
}
while (p_hdr->is_full());
break;
default:
throw interprocess_exception();
}
}
//Get the first free message from free message queue
detail::msg_hdr_t *free_msg = p_hdr->free_msg();
if (free_msg == 0) {
throw interprocess_exception();
}
//Copy control data to the free message
free_msg->priority = priority;
free_msg->len = buffer_size;
//Copy user buffer to the message
std::memcpy(free_msg->data(), buffer, buffer_size);
// bool was_empty = p_hdr->is_empty();
//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 (was_empty){
p_hdr->m_cond_recv.notify_one();
// }
} // Lock end
return true;
}
inline void message_queue::receive(void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority)
{ this->do_receive(blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
inline bool
message_queue::try_receive(void *buffer, std::size_t buffer_size,
std::size_t &recvd_size, unsigned int &priority)
{ return this->do_receive(non_blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
inline bool
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)
{
if(abs_time == boost::posix_time::pos_infin){
this->receive(buffer, buffer_size, recvd_size, priority);
return true;
}
return this->do_receive(timed, buffer, buffer_size, recvd_size, priority, abs_time);
}
inline bool
message_queue::do_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)
{
detail::mq_hdr_t *p_hdr = static_cast<detail::mq_hdr_t*>(m_shmem.get_user_address());
//Check if buffer is big enough for any message
if (buffer_size < p_hdr->m_max_msg_size) {
throw interprocess_exception(size_error);
}
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
{
//If there are no messages execute blocking logic
if (p_hdr->is_empty()) {
switch(block){
case non_blocking :
return false;
break;
case blocking :
do{
p_hdr->m_cond_recv.wait(lock);
}
while (p_hdr->is_empty());
break;
case timed :
do{
if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time)){
if(p_hdr->is_empty())
return false;
break;
}
}
while (p_hdr->is_empty());
break;
//Paranoia check
default:
throw interprocess_exception();
}
}
//Thre is at least message ready to pick, get the top one
detail::msg_hdr_t *top_msg = p_hdr->top_msg();
//Paranoia check
if (top_msg == 0) {
throw interprocess_exception();
}
//Get data from the message
recvd_size = top_msg->len;
priority = top_msg->priority;
//Copy data to receiver's bufers
std::memcpy(buffer, top_msg->data(), recvd_size);
// bool was_full = p_hdr->is_full();
//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 (was_full){
p_hdr->m_cond_send.notify_one();
// }
} //Lock end
return true;
}
inline std::size_t message_queue::get_max_msg() const
{
detail::mq_hdr_t *p_hdr = static_cast<detail::mq_hdr_t*>(m_shmem.get_user_address());
return p_hdr ? p_hdr->m_max_num_msg : 0; }
inline std::size_t message_queue::get_max_msg_size() const
{
detail::mq_hdr_t *p_hdr = static_cast<detail::mq_hdr_t*>(m_shmem.get_user_address());
return p_hdr ? p_hdr->m_max_msg_size : 0;
}
inline std::size_t message_queue::get_num_msg()
{
detail::mq_hdr_t *p_hdr = static_cast<detail::mq_hdr_t*>(m_shmem.get_user_address());
if(p_hdr){
//---------------------------------------------
scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
//---------------------------------------------
return p_hdr->m_cur_num_msg;
}
return 0;
}
inline bool message_queue::remove(const char *name)
{ return shared_memory_object::remove(name); }
/// @endcond
}} //namespace boost{ namespace interprocess{
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP

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