825 lines
21 KiB
C++
Executable File
825 lines
21 KiB
C++
Executable File
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (C) Copyright Ion Gaztanaga 2005-2008.
|
|
// (C) Copyright Gennaro Prota 2003 - 2004.
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
// See http://www.boost.org/libs/interprocess for documentation.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
|
|
#define BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
|
|
|
|
#if (defined _MSC_VER) && (_MSC_VER >= 1200)
|
|
# pragma once
|
|
#endif
|
|
|
|
#include <boost/interprocess/detail/config_begin.hpp>
|
|
#include <boost/interprocess/detail/workaround.hpp>
|
|
|
|
#include <boost/interprocess/interprocess_fwd.hpp>
|
|
#include <boost/interprocess/detail/move.hpp>
|
|
#include <boost/type_traits/has_trivial_destructor.hpp>
|
|
#include <boost/interprocess/detail/min_max.hpp>
|
|
#include <boost/interprocess/detail/type_traits.hpp>
|
|
#include <boost/interprocess/detail/iterators.hpp>
|
|
#include <boost/interprocess/detail/version_type.hpp>
|
|
#include <utility>
|
|
#include <algorithm>
|
|
|
|
namespace boost {
|
|
namespace interprocess {
|
|
namespace detail {
|
|
|
|
template<class SmartPtr>
|
|
struct smart_ptr_type
|
|
{
|
|
typedef typename SmartPtr::value_type value_type;
|
|
typedef value_type *pointer;
|
|
static pointer get (const SmartPtr &smartptr)
|
|
{ return smartptr.get();}
|
|
};
|
|
|
|
template<class T>
|
|
struct smart_ptr_type<T*>
|
|
{
|
|
typedef T value_type;
|
|
typedef value_type *pointer;
|
|
static pointer get (pointer ptr)
|
|
{ return ptr;}
|
|
};
|
|
|
|
//!Overload for smart pointers to avoid ADL problems with get_pointer
|
|
template<class Ptr>
|
|
inline typename smart_ptr_type<Ptr>::pointer
|
|
get_pointer(const Ptr &ptr)
|
|
{ return smart_ptr_type<Ptr>::get(ptr); }
|
|
|
|
//!To avoid ADL problems with swap
|
|
template <class T>
|
|
inline void do_swap(T& x, T& y)
|
|
{
|
|
using std::swap;
|
|
swap(x, y);
|
|
}
|
|
|
|
//!A deleter for scoped_ptr that deallocates the memory
|
|
//!allocated for an object using a STL allocator.
|
|
template <class Allocator>
|
|
struct scoped_ptr_dealloc_functor
|
|
{
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef detail::integral_constant<unsigned,
|
|
boost::interprocess::detail::
|
|
version<Allocator>::value> alloc_version;
|
|
typedef detail::integral_constant<unsigned, 1> allocator_v1;
|
|
typedef detail::integral_constant<unsigned, 2> allocator_v2;
|
|
|
|
private:
|
|
void priv_deallocate(const typename Allocator::pointer &p, allocator_v1)
|
|
{ m_alloc.deallocate(p, 1); }
|
|
|
|
void priv_deallocate(const typename Allocator::pointer &p, allocator_v2)
|
|
{ m_alloc.deallocate_one(p); }
|
|
|
|
public:
|
|
Allocator& m_alloc;
|
|
|
|
scoped_ptr_dealloc_functor(Allocator& a)
|
|
: m_alloc(a) {}
|
|
|
|
void operator()(pointer ptr)
|
|
{ if (ptr) priv_deallocate(ptr, alloc_version()); }
|
|
};
|
|
|
|
//!A deleter for scoped_ptr that deallocates the memory
|
|
//!allocated for an object using a STL allocator.
|
|
template <class Allocator>
|
|
struct scoped_deallocator
|
|
{
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef detail::integral_constant<unsigned,
|
|
boost::interprocess::detail::
|
|
version<Allocator>::value> alloc_version;
|
|
typedef detail::integral_constant<unsigned, 1> allocator_v1;
|
|
typedef detail::integral_constant<unsigned, 2> allocator_v2;
|
|
|
|
private:
|
|
void priv_deallocate(allocator_v1)
|
|
{ m_alloc.deallocate(m_ptr, 1); }
|
|
|
|
void priv_deallocate(allocator_v2)
|
|
{ m_alloc.deallocate_one(m_ptr); }
|
|
|
|
public:
|
|
pointer m_ptr;
|
|
Allocator& m_alloc;
|
|
|
|
scoped_deallocator(pointer p, Allocator& a)
|
|
: m_ptr(p), m_alloc(a) {}
|
|
|
|
~scoped_deallocator()
|
|
{ if (m_ptr)priv_deallocate(alloc_version()); }
|
|
|
|
void release()
|
|
{ m_ptr = 0; }
|
|
};
|
|
|
|
//!A deleter for scoped_ptr that deallocates the memory
|
|
//!allocated for an array of objects using a STL allocator.
|
|
template <class Allocator>
|
|
struct scoped_array_deallocator
|
|
{
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef typename Allocator::size_type size_type;
|
|
|
|
scoped_array_deallocator(pointer p, Allocator& a, size_type length)
|
|
: m_ptr(p), m_alloc(a), m_length(length) {}
|
|
|
|
~scoped_array_deallocator()
|
|
{ if (m_ptr) m_alloc.deallocate(m_ptr, m_length); }
|
|
|
|
void release()
|
|
{ m_ptr = 0; }
|
|
|
|
private:
|
|
pointer m_ptr;
|
|
Allocator& m_alloc;
|
|
size_type m_length;
|
|
};
|
|
|
|
template <class Allocator>
|
|
struct null_scoped_array_deallocator
|
|
{
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef typename Allocator::size_type size_type;
|
|
|
|
null_scoped_array_deallocator(pointer, Allocator&, size_type)
|
|
{}
|
|
|
|
void release()
|
|
{}
|
|
};
|
|
|
|
//!A deleter for scoped_ptr that destroys
|
|
//!an object using a STL allocator.
|
|
template <class Allocator>
|
|
struct scoped_destructor_n
|
|
{
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef typename Allocator::value_type value_type;
|
|
typedef typename Allocator::size_type size_type;
|
|
|
|
pointer m_p;
|
|
size_type m_n;
|
|
|
|
scoped_destructor_n(pointer p, size_type n)
|
|
: m_p(p), m_n(n)
|
|
{}
|
|
|
|
void release()
|
|
{ m_p = 0; }
|
|
|
|
void increment_size(size_type inc)
|
|
{ m_n += inc; }
|
|
|
|
~scoped_destructor_n()
|
|
{
|
|
if(!m_p) return;
|
|
value_type *raw_ptr = detail::get_pointer(m_p);
|
|
for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr)
|
|
raw_ptr->~value_type();
|
|
}
|
|
};
|
|
|
|
//!A deleter for scoped_ptr that destroys
|
|
//!an object using a STL allocator.
|
|
template <class Allocator>
|
|
struct null_scoped_destructor_n
|
|
{
|
|
typedef typename Allocator::pointer pointer;
|
|
typedef typename Allocator::size_type size_type;
|
|
|
|
null_scoped_destructor_n(pointer, size_type)
|
|
{}
|
|
|
|
void increment_size(size_type)
|
|
{}
|
|
|
|
void release()
|
|
{}
|
|
};
|
|
|
|
template <class A>
|
|
class allocator_destroyer
|
|
{
|
|
typedef typename A::value_type value_type;
|
|
typedef detail::integral_constant<unsigned,
|
|
boost::interprocess::detail::
|
|
version<A>::value> alloc_version;
|
|
typedef detail::integral_constant<unsigned, 1> allocator_v1;
|
|
typedef detail::integral_constant<unsigned, 2> allocator_v2;
|
|
|
|
private:
|
|
A & a_;
|
|
|
|
private:
|
|
void priv_deallocate(const typename A::pointer &p, allocator_v1)
|
|
{ a_.deallocate(p, 1); }
|
|
|
|
void priv_deallocate(const typename A::pointer &p, allocator_v2)
|
|
{ a_.deallocate_one(p); }
|
|
|
|
public:
|
|
allocator_destroyer(A &a)
|
|
: a_(a)
|
|
{}
|
|
|
|
void operator()(const typename A::pointer &p)
|
|
{
|
|
detail::get_pointer(p)->~value_type();
|
|
priv_deallocate(p, alloc_version());
|
|
}
|
|
};
|
|
|
|
template <class A>
|
|
class allocator_destroyer_and_chain_builder
|
|
{
|
|
typedef typename A::value_type value_type;
|
|
typedef typename A::multiallocation_iterator multiallocation_iterator;
|
|
typedef typename A::multiallocation_chain multiallocation_chain;
|
|
|
|
A & a_;
|
|
multiallocation_chain &c_;
|
|
|
|
public:
|
|
allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c)
|
|
: a_(a), c_(c)
|
|
{}
|
|
|
|
void operator()(const typename A::pointer &p)
|
|
{
|
|
value_type *vp = detail::get_pointer(p);
|
|
vp->~value_type();
|
|
c_.push_back(vp);
|
|
}
|
|
};
|
|
|
|
template <class A>
|
|
class allocator_multialloc_chain_node_deallocator
|
|
{
|
|
typedef typename A::value_type value_type;
|
|
typedef typename A::multiallocation_iterator multiallocation_iterator;
|
|
typedef typename A::multiallocation_chain multiallocation_chain;
|
|
typedef allocator_destroyer_and_chain_builder<A> chain_builder;
|
|
|
|
A & a_;
|
|
multiallocation_chain c_;
|
|
|
|
public:
|
|
allocator_multialloc_chain_node_deallocator(A &a)
|
|
: a_(a), c_()
|
|
{}
|
|
|
|
chain_builder get_chain_builder()
|
|
{ return chain_builder(a_, c_); }
|
|
|
|
~allocator_multialloc_chain_node_deallocator()
|
|
{
|
|
multiallocation_iterator it(c_.get_it());
|
|
if(it != multiallocation_iterator())
|
|
a_.deallocate_individual(it);
|
|
}
|
|
};
|
|
|
|
template <class A>
|
|
class allocator_multialloc_chain_array_deallocator
|
|
{
|
|
typedef typename A::value_type value_type;
|
|
typedef typename A::multiallocation_iterator multiallocation_iterator;
|
|
typedef typename A::multiallocation_chain multiallocation_chain;
|
|
typedef allocator_destroyer_and_chain_builder<A> chain_builder;
|
|
|
|
A & a_;
|
|
multiallocation_chain c_;
|
|
|
|
public:
|
|
allocator_multialloc_chain_array_deallocator(A &a)
|
|
: a_(a), c_()
|
|
{}
|
|
|
|
chain_builder get_chain_builder()
|
|
{ return chain_builder(a_, c_); }
|
|
|
|
~allocator_multialloc_chain_array_deallocator()
|
|
{
|
|
multiallocation_iterator it(c_.get_it());
|
|
if(it != multiallocation_iterator())
|
|
a_.deallocate_many(it);
|
|
}
|
|
};
|
|
|
|
//!A class used for exception-safe multi-allocation + construction.
|
|
template <class Allocator>
|
|
struct multiallocation_destroy_dealloc
|
|
{
|
|
typedef typename Allocator::multiallocation_iterator multiallocation_iterator;
|
|
typedef typename Allocator::value_type value_type;
|
|
|
|
multiallocation_iterator m_itbeg;
|
|
Allocator& m_alloc;
|
|
|
|
multiallocation_destroy_dealloc(multiallocation_iterator itbeg, Allocator& a)
|
|
: m_itbeg(itbeg), m_alloc(a) {}
|
|
|
|
~multiallocation_destroy_dealloc()
|
|
{
|
|
multiallocation_iterator endit;
|
|
while(m_itbeg != endit){
|
|
detail::get_pointer(&*m_itbeg)->~value_type();
|
|
m_alloc.deallocate(&*m_itbeg, 1);
|
|
++m_itbeg;
|
|
}
|
|
}
|
|
|
|
void next()
|
|
{ ++m_itbeg; }
|
|
|
|
void release()
|
|
{ m_itbeg = multiallocation_iterator(); }
|
|
};
|
|
|
|
//!Forces a cast from any pointer to char *pointer
|
|
template<class T>
|
|
inline char* char_ptr_cast(T *ptr)
|
|
{
|
|
//This is nasty, but we like it a lot!
|
|
return (char*)(ptr);
|
|
}
|
|
|
|
inline char* char_ptr_cast()
|
|
{
|
|
//This is nasty, but we like it a lot!
|
|
return (char*)(0);
|
|
}
|
|
|
|
//Rounds "orig_size" by excess to round_to bytes
|
|
inline std::size_t get_rounded_size(std::size_t orig_size, std::size_t round_to)
|
|
{
|
|
return ((orig_size-1)/round_to+1)*round_to;
|
|
}
|
|
|
|
//Truncates "orig_size" to a multiple of "multiple" bytes.
|
|
inline std::size_t get_truncated_size(std::size_t orig_size, std::size_t multiple)
|
|
{
|
|
return orig_size/multiple*multiple;
|
|
}
|
|
|
|
//Rounds "orig_size" by excess to round_to bytes. round_to must be power of two
|
|
inline std::size_t get_rounded_size_po2(std::size_t orig_size, std::size_t round_to)
|
|
{
|
|
return ((orig_size-1)&(~(round_to-1))) + round_to;
|
|
}
|
|
|
|
//Truncates "orig_size" to a multiple of "multiple" bytes. multiple must be power of two
|
|
inline std::size_t get_truncated_size_po2(std::size_t orig_size, std::size_t multiple)
|
|
{
|
|
return (orig_size & (~(multiple-1)));
|
|
}
|
|
|
|
template <std::size_t OrigSize, std::size_t RoundTo>
|
|
struct ct_rounded_size
|
|
{
|
|
enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo };
|
|
};
|
|
|
|
template <std::size_t Value1, std::size_t Value2>
|
|
struct ct_min
|
|
{
|
|
enum { value = (Value1 < Value2)? Value1 : Value2 };
|
|
};
|
|
|
|
template <std::size_t Value1, std::size_t Value2>
|
|
struct ct_max
|
|
{
|
|
enum { value = (Value1 > Value2)? Value1 : Value2 };
|
|
};
|
|
|
|
// Gennaro Prota wrote this. Thanks!
|
|
template <int p, int n = 4>
|
|
struct ct_max_pow2_less
|
|
{
|
|
enum { c = 2*n < p };
|
|
|
|
static const std::size_t value =
|
|
c ? (ct_max_pow2_less< c*p, 2*c*n>::value) : n;
|
|
};
|
|
|
|
template <>
|
|
struct ct_max_pow2_less<0, 0>
|
|
{
|
|
static const std::size_t value = 0;
|
|
};
|
|
|
|
//!Obtains a generic pointer of the same type that
|
|
//!can point to other pointed type: Ptr<?> -> Ptr<NewValueType>
|
|
template<class T, class U>
|
|
struct pointer_to_other;
|
|
|
|
template<class T, class U,
|
|
template<class> class Sp>
|
|
struct pointer_to_other< Sp<T>, U >
|
|
{
|
|
typedef Sp<U> type;
|
|
};
|
|
|
|
template<class T, class T2, class U,
|
|
template<class, class> class Sp>
|
|
struct pointer_to_other< Sp<T, T2>, U >
|
|
{
|
|
typedef Sp<U, T2> type;
|
|
};
|
|
|
|
template<class T, class T2, class T3, class U,
|
|
template<class, class, class> class Sp>
|
|
struct pointer_to_other< Sp<T, T2, T3>, U >
|
|
{
|
|
typedef Sp<U, T2, T3> type;
|
|
};
|
|
|
|
template<class T, class U>
|
|
struct pointer_to_other< T*, U >
|
|
{
|
|
typedef U* type;
|
|
};
|
|
|
|
} //namespace detail {
|
|
|
|
//!Trait class to detect if an index is a node
|
|
//!index. This allows more efficient operations
|
|
//!when deallocating named objects.
|
|
template <class Index>
|
|
struct is_node_index
|
|
{
|
|
enum { value = false };
|
|
};
|
|
|
|
|
|
//!Trait class to detect if an index is an intrusive
|
|
//!index. This will embed the derivation hook in each
|
|
//!allocation header, to provide memory for the intrusive
|
|
//!container.
|
|
template <class Index>
|
|
struct is_intrusive_index
|
|
{
|
|
enum { value = false };
|
|
};
|
|
|
|
template <class SizeType>
|
|
SizeType
|
|
get_next_capacity(const SizeType max_size
|
|
,const SizeType capacity
|
|
,const SizeType n)
|
|
{
|
|
// if (n > max_size - capacity)
|
|
// throw std::length_error("get_next_capacity");
|
|
|
|
const SizeType m3 = max_size/3;
|
|
|
|
if (capacity < m3)
|
|
return capacity + max_value(3*(capacity+1)/5, n);
|
|
|
|
if (capacity < m3*2)
|
|
return capacity + max_value((capacity+1)/2, n);
|
|
|
|
return max_size;
|
|
}
|
|
|
|
namespace detail {
|
|
|
|
template <class T1, class T2>
|
|
struct pair
|
|
{
|
|
typedef T1 first_type;
|
|
typedef T2 second_type;
|
|
|
|
T1 first;
|
|
T2 second;
|
|
|
|
pair()
|
|
: first(), second()
|
|
{}
|
|
|
|
pair(const T1& x, const T2& y)
|
|
: first(x), second(y)
|
|
{}
|
|
|
|
template <class D, class S>
|
|
pair(const std::pair<D, S>& p)
|
|
: first(p.first), second(p.second)
|
|
{}
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
template <class D, class S>
|
|
pair(const detail::moved_object<std::pair<D, S> >& p)
|
|
: first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second))
|
|
{}
|
|
#else
|
|
template <class D, class S>
|
|
pair(std::pair<D, S> && p)
|
|
: first(detail::move_impl(p.first)), second(detail::move_impl(p.second))
|
|
{}
|
|
#endif
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
template <class D, class S>
|
|
pair(const detail::moved_object<pair<D, S> >& p)
|
|
: first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second))
|
|
{}
|
|
#else
|
|
template <class D, class S>
|
|
pair(pair<D, S> && p)
|
|
: first(detail::move_impl(p.first)), second(detail::move_impl(p.second))
|
|
{}
|
|
#endif
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
template <class U, class V>
|
|
pair(const detail::moved_object<U> &x, const detail::moved_object<V> &y)
|
|
: first(detail::move_impl(x.get())), second(detail::move_impl(y.get()))
|
|
{}
|
|
#else
|
|
template <class U, class V>
|
|
pair(U &&x, V &&y)
|
|
: first(detail::move_impl(x)), second(detail::move_impl(y))
|
|
{}
|
|
#endif
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
pair(const detail::moved_object<pair> &p)
|
|
: first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second))
|
|
{}
|
|
#else
|
|
pair(pair &&p)
|
|
: first(detail::move_impl(p.first)), second(detail::move_impl(p.second))
|
|
{}
|
|
#endif
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
pair& operator=(const detail::moved_object<pair> &p)
|
|
{
|
|
first = detail::move_impl(p.get().first);
|
|
second = detail::move_impl(p.get().second);
|
|
return *this;
|
|
}
|
|
#else
|
|
pair& operator=(pair &&p)
|
|
{
|
|
first = detail::move_impl(p.first);
|
|
second = detail::move_impl(p.second);
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
pair& operator=(const pair &p)
|
|
{
|
|
first = p.first;
|
|
second = p.second;
|
|
return *this;
|
|
}
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
template <class D, class S>
|
|
pair& operator=(const detail::moved_object<std::pair<D, S> > &p)
|
|
{
|
|
first = detail::move_impl(p.get().first);
|
|
second = detail::move_impl(p.get().second);
|
|
return *this;
|
|
}
|
|
#else
|
|
template <class D, class S>
|
|
pair& operator=(std::pair<D, S> &&p)
|
|
{
|
|
first = detail::move_impl(p.first);
|
|
second = detail::move_impl(p.second);
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
void swap(const detail::moved_object<pair> &p)
|
|
{ std::swap(*this, p.get()); }
|
|
|
|
void swap(pair& p)
|
|
{ std::swap(*this, p); }
|
|
|
|
#else
|
|
void swap(pair &&p)
|
|
{ std::swap(*this, p); }
|
|
#endif
|
|
};
|
|
|
|
template <class T1, class T2>
|
|
inline bool operator==(const pair<T1,T2>& x, const pair<T1,T2>& y)
|
|
{ return static_cast<bool>(x.first == y.first && x.second == y.second); }
|
|
|
|
template <class T1, class T2>
|
|
inline bool operator< (const pair<T1,T2>& x, const pair<T1,T2>& y)
|
|
{ return static_cast<bool>(x.first < y.first ||
|
|
(!(y.first < x.first) && x.second < y.second)); }
|
|
|
|
template <class T1, class T2>
|
|
inline bool operator!=(const pair<T1,T2>& x, const pair<T1,T2>& y)
|
|
{ return static_cast<bool>(!(x == y)); }
|
|
|
|
template <class T1, class T2>
|
|
inline bool operator> (const pair<T1,T2>& x, const pair<T1,T2>& y)
|
|
{ return y < x; }
|
|
|
|
template <class T1, class T2>
|
|
inline bool operator>=(const pair<T1,T2>& x, const pair<T1,T2>& y)
|
|
{ return static_cast<bool>(!(x < y)); }
|
|
|
|
template <class T1, class T2>
|
|
inline bool operator<=(const pair<T1,T2>& x, const pair<T1,T2>& y)
|
|
{ return static_cast<bool>(!(y < x)); }
|
|
|
|
template <class T1, class T2>
|
|
inline pair<T1, T2> make_pair(T1 x, T2 y)
|
|
{ return pair<T1, T2>(x, y); }
|
|
|
|
#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE
|
|
template <class T1, class T2>
|
|
inline void swap(const detail::moved_object<pair<T1, T2> > &x, pair<T1, T2>& y)
|
|
{
|
|
swap(x.get().first, y.first);
|
|
swap(x.get().second, y.second);
|
|
}
|
|
|
|
template <class T1, class T2>
|
|
inline void swap(pair<T1, T2>& x, const detail::moved_object<pair<T1, T2> > &y)
|
|
{
|
|
swap(x.first, y.get().first);
|
|
swap(x.second, y.get().second);
|
|
}
|
|
|
|
template <class T1, class T2>
|
|
inline void swap(pair<T1, T2>& x, pair<T1, T2>& y)
|
|
{
|
|
swap(x.first, y.first);
|
|
swap(x.second, y.second);
|
|
}
|
|
|
|
#else
|
|
template <class T1, class T2>
|
|
inline void swap(pair<T1, T2>&&x, pair<T1, T2>&&y)
|
|
{
|
|
swap(x.first, y.first);
|
|
swap(x.second, y.second);
|
|
}
|
|
#endif
|
|
|
|
template<class T>
|
|
struct cast_functor
|
|
{
|
|
typedef typename detail::add_reference<T>::type result_type;
|
|
result_type operator()(char &ptr) const
|
|
{ return *static_cast<T*>(static_cast<void*>(&ptr)); }
|
|
};
|
|
|
|
template<class MultiallocChain, class T>
|
|
class multiallocation_chain_adaptor
|
|
{
|
|
private:
|
|
MultiallocChain chain_;
|
|
|
|
multiallocation_chain_adaptor
|
|
(const multiallocation_chain_adaptor &);
|
|
multiallocation_chain_adaptor &operator=
|
|
(const multiallocation_chain_adaptor &);
|
|
|
|
public:
|
|
typedef transform_iterator
|
|
< typename MultiallocChain::
|
|
multiallocation_iterator
|
|
, detail::cast_functor <T> > multiallocation_iterator;
|
|
|
|
multiallocation_chain_adaptor()
|
|
: chain_()
|
|
{}
|
|
|
|
void push_back(T *mem)
|
|
{ chain_.push_back(mem); }
|
|
|
|
void push_front(T *mem)
|
|
{ chain_.push_front(mem); }
|
|
|
|
void swap(multiallocation_chain_adaptor &other_chain)
|
|
{ chain_.swap(other_chain.chain_); }
|
|
|
|
void splice_back(multiallocation_chain_adaptor &other_chain)
|
|
{ chain_.splice_back(other_chain.chain_); }
|
|
|
|
T *pop_front()
|
|
{ return static_cast<T*>(chain_.pop_front()); }
|
|
|
|
bool empty() const
|
|
{ return chain_.empty(); }
|
|
|
|
multiallocation_iterator get_it() const
|
|
{ return multiallocation_iterator(chain_.get_it()); }
|
|
|
|
std::size_t size() const
|
|
{ return chain_.size(); }
|
|
};
|
|
|
|
} //namespace detail {
|
|
|
|
//!The pair is movable if any of its members is movable
|
|
template <class T1, class T2>
|
|
struct is_movable<boost::interprocess::detail::pair<T1, T2> >
|
|
{
|
|
enum { value = is_movable<T1>::value || is_movable<T2>::value };
|
|
};
|
|
|
|
//!The pair is movable if any of its members is movable
|
|
template <class T1, class T2>
|
|
struct is_movable<std::pair<T1, T2> >
|
|
{
|
|
enum { value = is_movable<T1>::value || is_movable<T2>::value };
|
|
};
|
|
|
|
///has_trivial_destructor_after_move<> == true_type
|
|
///specialization for optimizations
|
|
template <class T>
|
|
struct has_trivial_destructor_after_move
|
|
: public boost::has_trivial_destructor<T>
|
|
{};
|
|
|
|
template <typename T> T*
|
|
addressof(T& v)
|
|
{
|
|
return reinterpret_cast<T*>(
|
|
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
|
|
}
|
|
|
|
//Anti-exception node eraser
|
|
template<class Cont>
|
|
class value_eraser
|
|
{
|
|
public:
|
|
value_eraser(Cont & cont, typename Cont::iterator it)
|
|
: m_cont(cont), m_index_it(it), m_erase(true){}
|
|
~value_eraser()
|
|
{ if(m_erase) m_cont.erase(m_index_it); }
|
|
|
|
void release() { m_erase = false; }
|
|
|
|
private:
|
|
Cont &m_cont;
|
|
typename Cont::iterator m_index_it;
|
|
bool m_erase;
|
|
};
|
|
|
|
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 interprocess {
|
|
} //namespace boost {
|
|
|
|
#include <boost/interprocess/detail/config_end.hpp>
|
|
|
|
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_UTILITIES_HPP
|
|
|