|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r51291 - in sandbox/boost/interprocess: . allocators allocators/detail containers containers/detail detail indexes ipc mem_algo mem_algo/detail smart_ptr smart_ptr/detail streams sync sync/emulation sync/posix
From: igaztanaga_at_[hidden]
Date: 2009-02-17 13:05:17
Author: igaztanaga
Date: 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
New Revision: 51291
URL: http://svn.boost.org/trac/boost/changeset/51291
Log:
Added move_semantics library
Added:
sandbox/boost/interprocess/
sandbox/boost/interprocess/allocators/
sandbox/boost/interprocess/allocators/adaptive_pool.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/allocation_type.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/allocator.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/cached_adaptive_pool.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/cached_node_allocator.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/detail/
sandbox/boost/interprocess/allocators/detail/adaptive_node_pool.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/detail/allocator_common.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/detail/node_pool.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/detail/node_tools.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/node_allocator.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/private_adaptive_pool.hpp (contents, props changed)
sandbox/boost/interprocess/allocators/private_node_allocator.hpp (contents, props changed)
sandbox/boost/interprocess/anonymous_shared_memory.hpp (contents, props changed)
sandbox/boost/interprocess/containers/
sandbox/boost/interprocess/containers/deque.hpp (contents, props changed)
sandbox/boost/interprocess/containers/detail/
sandbox/boost/interprocess/containers/detail/flat_tree.hpp (contents, props changed)
sandbox/boost/interprocess/containers/detail/node_alloc_holder.hpp (contents, props changed)
sandbox/boost/interprocess/containers/detail/tree.hpp (contents, props changed)
sandbox/boost/interprocess/containers/flat_map.hpp (contents, props changed)
sandbox/boost/interprocess/containers/flat_set.hpp (contents, props changed)
sandbox/boost/interprocess/containers/list.hpp (contents, props changed)
sandbox/boost/interprocess/containers/map.hpp (contents, props changed)
sandbox/boost/interprocess/containers/set.hpp (contents, props changed)
sandbox/boost/interprocess/containers/slist.hpp (contents, props changed)
sandbox/boost/interprocess/containers/stable_vector.hpp (contents, props changed)
sandbox/boost/interprocess/containers/string.hpp (contents, props changed)
sandbox/boost/interprocess/containers/vector.hpp (contents, props changed)
sandbox/boost/interprocess/creation_tags.hpp (contents, props changed)
sandbox/boost/interprocess/detail/
sandbox/boost/interprocess/detail/advanced_insert_int.hpp (contents, props changed)
sandbox/boost/interprocess/detail/algorithms.hpp (contents, props changed)
sandbox/boost/interprocess/detail/atomic.hpp (contents, props changed)
sandbox/boost/interprocess/detail/cast_tags.hpp (contents, props changed)
sandbox/boost/interprocess/detail/config_begin.hpp (contents, props changed)
sandbox/boost/interprocess/detail/config_end.hpp (contents, props changed)
sandbox/boost/interprocess/detail/file_wrapper.hpp (contents, props changed)
sandbox/boost/interprocess/detail/in_place_interface.hpp (contents, props changed)
sandbox/boost/interprocess/detail/interprocess_tester.hpp (contents, props changed)
sandbox/boost/interprocess/detail/intersegment_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/detail/iterators.hpp (contents, props changed)
sandbox/boost/interprocess/detail/managed_memory_impl.hpp (contents, props changed)
sandbox/boost/interprocess/detail/managed_multi_shared_memory.hpp (contents, props changed)
sandbox/boost/interprocess/detail/managed_open_or_create_impl.hpp (contents, props changed)
sandbox/boost/interprocess/detail/math_functions.hpp (contents, props changed)
sandbox/boost/interprocess/detail/min_max.hpp (contents, props changed)
sandbox/boost/interprocess/detail/mpl.hpp (contents, props changed)
sandbox/boost/interprocess/detail/multi_segment_services.hpp (contents, props changed)
sandbox/boost/interprocess/detail/named_proxy.hpp (contents, props changed)
sandbox/boost/interprocess/detail/os_file_functions.hpp (contents, props changed)
sandbox/boost/interprocess/detail/os_thread_functions.hpp (contents, props changed)
sandbox/boost/interprocess/detail/pointer_type.hpp (contents, props changed)
sandbox/boost/interprocess/detail/posix_time_types_wrk.hpp (contents, props changed)
sandbox/boost/interprocess/detail/preprocessor.hpp (contents, props changed)
sandbox/boost/interprocess/detail/ptime_wrk.hpp (contents, props changed)
sandbox/boost/interprocess/detail/segment_manager_helper.hpp (contents, props changed)
sandbox/boost/interprocess/detail/tmp_dir_helpers.hpp (contents, props changed)
sandbox/boost/interprocess/detail/type_traits.hpp (contents, props changed)
sandbox/boost/interprocess/detail/utilities.hpp (contents, props changed)
sandbox/boost/interprocess/detail/variadic_templates_tools.hpp (contents, props changed)
sandbox/boost/interprocess/detail/version_type.hpp (contents, props changed)
sandbox/boost/interprocess/detail/win32_api.hpp (contents, props changed)
sandbox/boost/interprocess/detail/workaround.hpp (contents, props changed)
sandbox/boost/interprocess/errors.hpp (contents, props changed)
sandbox/boost/interprocess/exceptions.hpp (contents, props changed)
sandbox/boost/interprocess/file_mapping.hpp (contents, props changed)
sandbox/boost/interprocess/indexes/
sandbox/boost/interprocess/indexes/flat_map_index.hpp (contents, props changed)
sandbox/boost/interprocess/indexes/iset_index.hpp (contents, props changed)
sandbox/boost/interprocess/indexes/iunordered_set_index.hpp (contents, props changed)
sandbox/boost/interprocess/indexes/map_index.hpp (contents, props changed)
sandbox/boost/interprocess/indexes/null_index.hpp (contents, props changed)
sandbox/boost/interprocess/indexes/unordered_map_index.hpp (contents, props changed)
sandbox/boost/interprocess/interprocess_fwd.hpp (contents, props changed)
sandbox/boost/interprocess/ipc/
sandbox/boost/interprocess/ipc/message_queue.hpp (contents, props changed)
sandbox/boost/interprocess/managed_external_buffer.hpp (contents, props changed)
sandbox/boost/interprocess/managed_heap_memory.hpp (contents, props changed)
sandbox/boost/interprocess/managed_mapped_file.hpp (contents, props changed)
sandbox/boost/interprocess/managed_shared_memory.hpp (contents, props changed)
sandbox/boost/interprocess/managed_windows_shared_memory.hpp (contents, props changed)
sandbox/boost/interprocess/mapped_region.hpp (contents, props changed)
sandbox/boost/interprocess/mem_algo/
sandbox/boost/interprocess/mem_algo/detail/
sandbox/boost/interprocess/mem_algo/detail/mem_algo_common.hpp (contents, props changed)
sandbox/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp (contents, props changed)
sandbox/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp (contents, props changed)
sandbox/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp (contents, props changed)
sandbox/boost/interprocess/mem_algo/rbtree_best_fit.hpp (contents, props changed)
sandbox/boost/interprocess/mem_algo/simple_seq_fit.hpp (contents, props changed)
sandbox/boost/interprocess/offset_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/segment_manager.hpp (contents, props changed)
sandbox/boost/interprocess/shared_memory_object.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/
sandbox/boost/interprocess/smart_ptr/deleter.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/detail/
sandbox/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/detail/shared_count.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/enable_shared_from_this.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/intrusive_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/scoped_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/shared_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/unique_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/smart_ptr/weak_ptr.hpp (contents, props changed)
sandbox/boost/interprocess/streams/
sandbox/boost/interprocess/streams/bufferstream.hpp (contents, props changed)
sandbox/boost/interprocess/streams/vectorstream.hpp (contents, props changed)
sandbox/boost/interprocess/sync/
sandbox/boost/interprocess/sync/emulation/
sandbox/boost/interprocess/sync/emulation/interprocess_barrier.hpp (contents, props changed)
sandbox/boost/interprocess/sync/emulation/interprocess_condition.hpp (contents, props changed)
sandbox/boost/interprocess/sync/emulation/interprocess_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/emulation/interprocess_semaphore.hpp (contents, props changed)
sandbox/boost/interprocess/sync/emulation/named_creation_functor.hpp (contents, props changed)
sandbox/boost/interprocess/sync/file_lock.hpp (contents, props changed)
sandbox/boost/interprocess/sync/interprocess_barrier.hpp (contents, props changed)
sandbox/boost/interprocess/sync/interprocess_condition.hpp (contents, props changed)
sandbox/boost/interprocess/sync/interprocess_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/interprocess_recursive_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/interprocess_semaphore.hpp (contents, props changed)
sandbox/boost/interprocess/sync/interprocess_upgradable_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/lock_options.hpp (contents, props changed)
sandbox/boost/interprocess/sync/mutex_family.hpp (contents, props changed)
sandbox/boost/interprocess/sync/named_condition.hpp (contents, props changed)
sandbox/boost/interprocess/sync/named_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/named_recursive_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/named_semaphore.hpp (contents, props changed)
sandbox/boost/interprocess/sync/named_upgradable_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/null_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/
sandbox/boost/interprocess/sync/posix/interprocess_barrier.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/interprocess_condition.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/interprocess_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/interprocess_semaphore.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/pthread_helpers.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/ptime_to_timespec.hpp (contents, props changed)
sandbox/boost/interprocess/sync/posix/semaphore_wrapper.hpp (contents, props changed)
sandbox/boost/interprocess/sync/scoped_lock.hpp (contents, props changed)
sandbox/boost/interprocess/sync/sharable_lock.hpp (contents, props changed)
sandbox/boost/interprocess/sync/upgradable_lock.hpp (contents, props changed)
sandbox/boost/interprocess/windows_shared_memory.hpp (contents, props changed)
Added: sandbox/boost/interprocess/allocators/adaptive_pool.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/adaptive_pool.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,463 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/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 detail::
+ pointer_to_other<void_pointer, T>::type pointer;
+ typedef typename detail::
+ pointer_to_other<void_pointer, const T>::type const_pointer;
+ typedef T value_type;
+ typedef typename 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::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 detail::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(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
+
Added: sandbox/boost/interprocess/allocators/allocation_type.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/allocation_type.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,55 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// (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_TYPE_COMMAND_HPP
+#define BOOST_INTERPROCESS_TYPE_COMMAND_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+namespace boost {
+namespace interprocess {
+
+/// @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 {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_TYPE_COMMAND_HPP
+
Added: sandbox/boost/interprocess/allocators/allocator.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/allocator.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,302 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// (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/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/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 <boost/interprocess/detail/iterators.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
+ detail::pointer_to_other
+ <aux_pointer_t, const void>::type cvoid_ptr;
+
+ //Pointer to the allocator
+ typedef typename detail::pointer_to_other
+ <cvoid_ptr, segment_manager>::type alloc_ptr_t;
+
+ //Not assignable from related allocator
+ template<class T2, class 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 detail::pointer_to_other
+ <cvoid_ptr, T>::type pointer;
+ typedef typename detail::
+ 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 detail::version_type<allocator, 2> version;
+
+ /// @cond
+
+ //Experimental. Don't use.
+ typedef 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(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::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
+
Added: sandbox/boost/interprocess/allocators/cached_adaptive_pool.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/cached_adaptive_pool.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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/detail/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 detail::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(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
+
Added: sandbox/boost/interprocess/allocators/cached_node_allocator.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/cached_node_allocator.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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/detail/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 detail::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(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
+
Added: sandbox/boost/interprocess/allocators/detail/adaptive_node_pool.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/detail/adaptive_node_pool.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,638 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/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::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 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
+
Added: sandbox/boost/interprocess/allocators/detail/allocator_common.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/detail/allocator_common.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,802 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_DETAIL_NODE_ALLOCATOR_COMMON_HPP
+#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/segment_manager.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/utilities.hpp> //pointer_to_other, 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/allocators/allocation_type.hpp> //allocation_type
+#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
+#include <algorithm> //std::swap
+
+
+namespace boost {
+namespace interprocess {
+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>(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>(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::move(chain);
+ }
+ BOOST_CATCH(...){
+ this->cached_deallocation(boost::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::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 detail::
+ pointer_to_other<void_pointer, T>::type pointer;
+ typedef typename detail::
+ pointer_to_other<void_pointer, const T>::type const_pointer;
+ typedef T value_type;
+ typedef typename 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(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::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 detail::
+ pointer_to_other<void_pointer, const void>::type cvoid_pointer;
+
+ public:
+ typedef typename detail::
+ pointer_to_other<void_pointer, T>::type pointer;
+ typedef typename detail::
+ pointer_to_other<void_pointer, const T>::type const_pointer;
+ typedef T value_type;
+ typedef typename 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 detail::
+ 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::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::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_DETAIL_NODE_ALLOCATOR_COMMON_HPP
Added: sandbox/boost/interprocess/allocators/detail/node_pool.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/detail/node_pool.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,407 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/intrusive/slist.hpp>
+#include <boost/math/common_factor_ct.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::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 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
Added: sandbox/boost/interprocess/allocators/detail/node_tools.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/detail/node_tools.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/allocators/node_allocator.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/node_allocator.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,447 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/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 detail::
+ pointer_to_other<void_pointer, T>::type pointer;
+ typedef typename detail::
+ pointer_to_other<void_pointer, const T>::type const_pointer;
+ typedef T value_type;
+ typedef typename 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::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 detail::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(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
Added: sandbox/boost/interprocess/allocators/private_adaptive_pool.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/private_adaptive_pool.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,463 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/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 detail::
+ pointer_to_other<void_pointer, T>::type pointer;
+ typedef typename detail::
+ pointer_to_other<void_pointer, const T>::type const_pointer;
+ typedef T value_type;
+ typedef typename 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::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 detail::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(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
+
Added: sandbox/boost/interprocess/allocators/private_node_allocator.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/allocators/private_node_allocator.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,439 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/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 detail::
+ pointer_to_other<void_pointer, T>::type pointer;
+ typedef typename detail::
+ pointer_to_other<void_pointer, const T>::type const_pointer;
+ typedef T value_type;
+ typedef typename 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::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 detail::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(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
+
Added: sandbox/boost/interprocess/anonymous_shared_memory.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/anonymous_shared_memory.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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/move_semantics/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
Added: sandbox/boost/interprocess/containers/deque.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/deque.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1524 @@
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2006. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's stl_deque.h and stl_uninitialized.h files.
+// Modified by Ion Gaztanaga 2005.
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_DEQUE_HPP
+#define BOOST_INTERPROCESS_DEQUE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/iterators.hpp>
+#include <boost/interprocess/detail/algorithms.hpp>
+#include <boost/interprocess/detail/min_max.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <cstddef>
+#include <iterator>
+#include <cassert>
+#include <memory>
+#include <algorithm>
+#include <stdexcept>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/type_traits/has_trivial_copy.hpp>
+#include <boost/type_traits/has_trivial_assign.hpp>
+#include <boost/type_traits/has_nothrow_copy.hpp>
+#include <boost/type_traits/has_nothrow_assign.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/advanced_insert_int.hpp>
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+template <class T, class Alloc>
+class deque;
+
+template <class T, class A>
+struct deque_value_traits
+{
+ typedef T value_type;
+ typedef A allocator_type;
+ static const bool trivial_dctr = boost::has_trivial_destructor<value_type>::value;
+ static const bool trivial_dctr_after_move =
+ has_trivial_destructor_after_move<value_type>::value || trivial_dctr;
+ static const bool trivial_copy = has_trivial_copy<value_type>::value;
+ static const bool nothrow_copy = has_nothrow_copy<value_type>::value;
+ static const bool trivial_assign = has_trivial_assign<value_type>::value;
+ static const bool nothrow_assign = has_nothrow_assign<value_type>::value;
+
+};
+
+// Note: this function is simply a kludge to work around several compilers'
+// bugs in handling constant expressions.
+inline std::size_t deque_buf_size(std::size_t size)
+ { return size < 512 ? std::size_t(512 / size) : std::size_t(1); }
+
+// Deque base class. It has two purposes. First, its constructor
+// and destructor allocate (but don't initialize) storage. This makes
+// exception safety easier.
+template <class T, class Alloc>
+class deque_base
+{
+ public:
+ typedef typename Alloc::value_type val_alloc_val;
+ typedef typename Alloc::pointer val_alloc_ptr;
+ typedef typename Alloc::const_pointer val_alloc_cptr;
+ typedef typename Alloc::reference val_alloc_ref;
+ typedef typename Alloc::const_reference val_alloc_cref;
+ typedef typename Alloc::value_type val_alloc_diff;
+ typedef typename Alloc::template rebind
+ <typename Alloc::pointer>::other ptr_alloc_t;
+ typedef typename ptr_alloc_t::value_type ptr_alloc_val;
+ typedef typename ptr_alloc_t::pointer ptr_alloc_ptr;
+ typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr;
+ typedef typename ptr_alloc_t::reference ptr_alloc_ref;
+ typedef typename ptr_alloc_t::const_reference ptr_alloc_cref;
+ typedef typename Alloc::template
+ rebind<T>::other allocator_type;
+ typedef allocator_type stored_allocator_type;
+
+ protected:
+
+ typedef deque_value_traits<T, Alloc> traits_t;
+ typedef typename Alloc::template
+ rebind<typename Alloc::pointer>::other map_allocator_type;
+
+ static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); }
+
+ val_alloc_ptr priv_allocate_node()
+ { return this->alloc().allocate(s_buffer_size()); }
+
+ void priv_deallocate_node(val_alloc_ptr p)
+ { this->alloc().deallocate(p, s_buffer_size()); }
+
+ ptr_alloc_ptr priv_allocate_map(std::size_t n)
+ { return this->ptr_alloc().allocate(n); }
+
+ void priv_deallocate_map(ptr_alloc_ptr p, std::size_t n)
+ { this->ptr_alloc().deallocate(p, n); }
+
+ public:
+ // Class invariants:
+ // For any nonsingular iterator i:
+ // i.node is the address of an element in the map array. The
+ // contents of i.node is a pointer to the beginning of a node.
+ // i.first == //(i.node)
+ // i.last == i.first + node_size
+ // i.cur is a pointer in the range [i.first, i.last). NOTE:
+ // the implication of this is that i.cur is always a dereferenceable
+ // pointer, even if i is a past-the-end iterator.
+ // Start and Finish are always nonsingular iterators. NOTE: this means
+ // that an empty deque must have one node, and that a deque
+ // with N elements, where N is the buffer size, must have two nodes.
+ // For every node other than start.node and finish.node, every element
+ // in the node is an initialized object. If start.node == finish.node,
+ // then [start.cur, finish.cur) are initialized objects, and
+ // the elements outside that range are uninitialized storage. Otherwise,
+ // [start.cur, start.last) and [finish.first, finish.cur) are initialized
+ // objects, and [start.first, start.cur) and [finish.cur, finish.last)
+ // are uninitialized storage.
+ // [map, map + map_size) is a valid, non-empty range.
+ // [start.node, finish.node] is a valid range contained within
+ // [map, map + map_size).
+ // A pointer in the range [map, map + map_size) points to an allocated node
+ // if and only if the pointer is in the range [start.node, finish.node].
+ class const_iterator
+ : public std::iterator<std::random_access_iterator_tag,
+ val_alloc_val, val_alloc_diff,
+ val_alloc_cptr, val_alloc_cref>
+ {
+ public:
+ static std::size_t s_buffer_size() { return deque_base<T, Alloc>::s_buffer_size(); }
+
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef val_alloc_val value_type;
+ typedef val_alloc_cptr pointer;
+ typedef val_alloc_cref reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ typedef ptr_alloc_ptr index_pointer;
+ typedef const_iterator self_t;
+
+ friend class deque<T, Alloc>;
+ friend class deque_base<T, Alloc>;
+
+ protected:
+ val_alloc_ptr m_cur;
+ val_alloc_ptr m_first;
+ val_alloc_ptr m_last;
+ index_pointer m_node;
+
+ public:
+ const_iterator(val_alloc_ptr x, index_pointer y)
+ : m_cur(x), m_first(*y),
+ m_last(*y + s_buffer_size()), m_node(y) {}
+
+ const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {}
+
+ const_iterator(const const_iterator& x)
+ : m_cur(x.m_cur), m_first(x.m_first),
+ m_last(x.m_last), m_node(x.m_node) {}
+
+ reference operator*() const
+ { return *this->m_cur; }
+
+ pointer operator->() const
+ { return this->m_cur; }
+
+ difference_type operator-(const self_t& x) const
+ {
+ if(!this->m_cur && !x.m_cur){
+ return 0;
+ }
+ return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) +
+ (this->m_cur - this->m_first) + (x.m_last - x.m_cur);
+ }
+
+ self_t& operator++()
+ {
+ ++this->m_cur;
+ if (this->m_cur == this->m_last) {
+ this->priv_set_node(this->m_node + 1);
+ this->m_cur = this->m_first;
+ }
+ return *this;
+ }
+
+ self_t operator++(int)
+ {
+ self_t tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ self_t& operator--()
+ {
+ if (this->m_cur == this->m_first) {
+ this->priv_set_node(this->m_node - 1);
+ this->m_cur = this->m_last;
+ }
+ --this->m_cur;
+ return *this;
+ }
+
+ self_t operator--(int)
+ {
+ self_t tmp = *this;
+ --*this;
+ return tmp;
+ }
+
+ self_t& operator+=(difference_type n)
+ {
+ difference_type offset = n + (this->m_cur - this->m_first);
+ if (offset >= 0 && offset < difference_type(this->s_buffer_size()))
+ this->m_cur += n;
+ else {
+ difference_type node_offset =
+ offset > 0 ? offset / difference_type(this->s_buffer_size())
+ : -difference_type((-offset - 1) / this->s_buffer_size()) - 1;
+ this->priv_set_node(this->m_node + node_offset);
+ this->m_cur = this->m_first +
+ (offset - node_offset * difference_type(this->s_buffer_size()));
+ }
+ return *this;
+ }
+
+ self_t operator+(difference_type n) const
+ { self_t tmp = *this; return tmp += n; }
+
+ self_t& operator-=(difference_type n)
+ { return *this += -n; }
+
+ self_t operator-(difference_type n) const
+ { self_t tmp = *this; return tmp -= n; }
+
+ reference operator[](difference_type n) const
+ { return *(*this + n); }
+
+ bool operator==(const self_t& x) const
+ { return this->m_cur == x.m_cur; }
+
+ bool operator!=(const self_t& x) const
+ { return !(*this == x); }
+
+ bool operator<(const self_t& x) const
+ {
+ return (this->m_node == x.m_node) ?
+ (this->m_cur < x.m_cur) : (this->m_node < x.m_node);
+ }
+
+ bool operator>(const self_t& x) const
+ { return x < *this; }
+
+ bool operator<=(const self_t& x) const
+ { return !(x < *this); }
+
+ bool operator>=(const self_t& x) const
+ { return !(*this < x); }
+
+ void priv_set_node(index_pointer new_node)
+ {
+ this->m_node = new_node;
+ this->m_first = *new_node;
+ this->m_last = this->m_first + difference_type(this->s_buffer_size());
+ }
+
+ friend const_iterator operator+(std::ptrdiff_t n, const const_iterator& x)
+ { return x + n; }
+ };
+
+ //Deque iterator
+ class iterator : public const_iterator
+ {
+ public:
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef val_alloc_val value_type;
+ typedef val_alloc_ptr pointer;
+ typedef val_alloc_ref reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef ptr_alloc_ptr index_pointer;
+ typedef const_iterator self_t;
+
+ friend class deque<T, Alloc>;
+ friend class deque_base<T, Alloc>;
+
+ private:
+ explicit iterator(const const_iterator& x) : const_iterator(x){}
+
+ public:
+ //Constructors
+ iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){}
+ iterator() : const_iterator(){}
+ //iterator(const const_iterator &cit) : const_iterator(cit){}
+ iterator(const iterator& x) : const_iterator(x){}
+
+ //Pointer like operators
+ reference operator*() const { return *this->m_cur; }
+ pointer operator->() const { return this->m_cur; }
+
+ reference operator[](difference_type n) const { return *(*this + n); }
+
+ //Increment / Decrement
+ iterator& operator++()
+ { this->const_iterator::operator++(); return *this; }
+
+ iterator operator++(int)
+ { iterator tmp = *this; ++*this; return tmp; }
+
+ iterator& operator--()
+ { this->const_iterator::operator--(); return *this; }
+
+ iterator operator--(int)
+ { iterator tmp = *this; --*this; return tmp; }
+
+ // Arithmetic
+ iterator& operator+=(difference_type off)
+ { this->const_iterator::operator+=(off); return *this; }
+
+ iterator operator+(difference_type off) const
+ { return iterator(this->const_iterator::operator+(off)); }
+
+ friend iterator operator+(difference_type off, const iterator& right)
+ { return iterator(off+static_cast<const const_iterator &>(right)); }
+
+ iterator& operator-=(difference_type off)
+ { this->const_iterator::operator-=(off); return *this; }
+
+ iterator operator-(difference_type off) const
+ { return iterator(this->const_iterator::operator-(off)); }
+
+ difference_type operator-(const const_iterator& right) const
+ { return static_cast<const const_iterator&>(*this) - right; }
+ };
+
+ deque_base(const allocator_type& a, std::size_t num_elements)
+ : members_(a)
+ { this->priv_initialize_map(num_elements); }
+
+ deque_base(const allocator_type& a)
+ : members_(a)
+ {}
+
+ ~deque_base()
+ {
+ if (this->members_.m_map) {
+ this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1);
+ this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size);
+ }
+ }
+
+ private:
+ deque_base(const deque_base&);
+
+ protected:
+
+ void priv_initialize_map(std::size_t num_elements)
+ {
+// if(num_elements){
+ std::size_t num_nodes = num_elements / s_buffer_size() + 1;
+
+ this->members_.m_map_size = max_value((std::size_t) InitialMapSize, num_nodes + 2);
+ this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size);
+
+ ptr_alloc_ptr nstart = this->members_.m_map + (this->members_.m_map_size - num_nodes) / 2;
+ ptr_alloc_ptr nfinish = nstart + num_nodes;
+
+ BOOST_TRY {
+ this->priv_create_nodes(nstart, nfinish);
+ }
+ BOOST_CATCH(...){
+ this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size);
+ this->members_.m_map = 0;
+ this->members_.m_map_size = 0;
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+
+ this->members_.m_start.priv_set_node(nstart);
+ this->members_.m_finish.priv_set_node(nfinish - 1);
+ this->members_.m_start.m_cur = this->members_.m_start.m_first;
+ this->members_.m_finish.m_cur = this->members_.m_finish.m_first +
+ num_elements % s_buffer_size();
+// }
+ }
+
+ void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish)
+ {
+ ptr_alloc_ptr cur;
+ BOOST_TRY {
+ for (cur = nstart; cur < nfinish; ++cur)
+ *cur = this->priv_allocate_node();
+ }
+ BOOST_CATCH(...){
+ this->priv_destroy_nodes(nstart, cur);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish)
+ {
+ for (ptr_alloc_ptr n = nstart; n < nfinish; ++n)
+ this->priv_deallocate_node(*n);
+ }
+
+ enum { InitialMapSize = 8 };
+
+ protected:
+ struct members_holder
+ : public ptr_alloc_t
+ , public allocator_type
+ {
+ members_holder(const allocator_type &a)
+ : map_allocator_type(a), allocator_type(a)
+ , m_map(0), m_map_size(0)
+ , m_start(), m_finish(m_start)
+ {}
+
+ ptr_alloc_ptr m_map;
+ std::size_t m_map_size;
+ iterator m_start;
+ iterator m_finish;
+ } members_;
+
+ ptr_alloc_t &ptr_alloc()
+ { return members_; }
+
+ const ptr_alloc_t &ptr_alloc() const
+ { return members_; }
+
+ allocator_type &alloc()
+ { return members_; }
+
+ const allocator_type &alloc() const
+ { return members_; }
+};
+/// @endcond
+
+//! Deque class
+//!
+template <class T, class Alloc>
+class deque : protected deque_base<T, Alloc>
+{
+ /// @cond
+ typedef deque_base<T, Alloc> Base;
+
+ public: // Basic types
+ typedef typename Alloc::value_type val_alloc_val;
+ typedef typename Alloc::pointer val_alloc_ptr;
+ typedef typename Alloc::const_pointer val_alloc_cptr;
+ typedef typename Alloc::reference val_alloc_ref;
+ typedef typename Alloc::const_reference val_alloc_cref;
+ typedef typename Alloc::template
+ rebind<val_alloc_ptr>::other ptr_alloc_t;
+ typedef typename ptr_alloc_t::value_type ptr_alloc_val;
+ typedef typename ptr_alloc_t::pointer ptr_alloc_ptr;
+ typedef typename ptr_alloc_t::const_pointer ptr_alloc_cptr;
+ typedef typename ptr_alloc_t::reference ptr_alloc_ref;
+ typedef typename ptr_alloc_t::const_reference ptr_alloc_cref;
+ /// @endcond
+
+ typedef T value_type;
+ typedef val_alloc_ptr pointer;
+ typedef val_alloc_cptr const_pointer;
+ typedef val_alloc_ref reference;
+ typedef val_alloc_cref const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ typedef typename Base::allocator_type allocator_type;
+
+ public: // Iterators
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ /// @cond
+ private: // Internal typedefs
+ typedef ptr_alloc_ptr index_pointer;
+ static std::size_t s_buffer_size()
+ { return Base::s_buffer_size(); }
+ typedef detail::advanced_insert_aux_int<value_type, iterator> advanced_insert_aux_int_t;
+ typedef repeat_iterator<T, difference_type> r_iterator;
+ typedef boost::move_iterator<r_iterator> move_it;
+
+ /// @endcond
+
+ allocator_type get_allocator() const { return Base::alloc(); }
+
+ public: // Basic accessors
+ BOOST_ENABLE_MOVE_EMULATION(deque)
+
+ iterator begin()
+ { return this->members_.m_start; }
+
+ iterator end()
+ { return this->members_.m_finish; }
+
+ const_iterator begin() const
+ { return this->members_.m_start; }
+
+ const_iterator end() const
+ { return this->members_.m_finish; }
+
+ reverse_iterator rbegin()
+ { return reverse_iterator(this->members_.m_finish); }
+
+ reverse_iterator rend()
+ { return reverse_iterator(this->members_.m_start); }
+
+ const_reverse_iterator rbegin() const
+ { return const_reverse_iterator(this->members_.m_finish); }
+
+ const_reverse_iterator rend() const
+ { return const_reverse_iterator(this->members_.m_start); }
+
+ const_iterator cbegin() const
+ { return this->members_.m_start; }
+
+ const_iterator cend() const
+ { return this->members_.m_finish; }
+
+ const_reverse_iterator crbegin() const
+ { return const_reverse_iterator(this->members_.m_finish); }
+
+ const_reverse_iterator crend() const
+ { return const_reverse_iterator(this->members_.m_start); }
+
+ reference operator[](size_type n)
+ { return this->members_.m_start[difference_type(n)]; }
+
+ const_reference operator[](size_type n) const
+ { return this->members_.m_start[difference_type(n)]; }
+
+ void priv_range_check(size_type n) const
+ { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); }
+
+ reference at(size_type n)
+ { this->priv_range_check(n); return (*this)[n]; }
+
+ const_reference at(size_type n) const
+ { this->priv_range_check(n); return (*this)[n]; }
+
+ reference front() { return *this->members_.m_start; }
+
+ reference back() { return *(end()-1); }
+
+ const_reference front() const
+ { return *this->members_.m_start; }
+
+ const_reference back() const { return *(cend()-1); }
+
+ size_type size() const
+ { return this->members_.m_finish - this->members_.m_start; }
+
+ size_type max_size() const
+ { return this->alloc().max_size(); }
+
+ bool empty() const
+ { return this->members_.m_finish == this->members_.m_start; }
+
+ explicit deque(const allocator_type& a = allocator_type())
+ : Base(a)
+ {}
+
+ deque(const deque& x)
+ : Base(x.alloc())
+ {
+ if(x.size()){
+ this->priv_initialize_map(x.size());
+ std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start);
+ }
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ deque(boost::rv<deque> &mx)
+ : Base(mx.get().alloc())
+ { this->swap(mx.get()); }
+ #else
+ deque(deque &&x)
+ : Base(x.alloc())
+ { this->swap(x); }
+ #endif
+
+ deque(size_type n, const value_type& value,
+ const allocator_type& a = allocator_type()) : Base(a, n)
+ { this->priv_fill_initialize(value); }
+
+ explicit deque(size_type n) : Base(allocator_type(), n)
+ { this->resize(n); }
+
+ // Check whether it's an integral type. If so, it's not an iterator.
+ template <class InpIt>
+ deque(InpIt first, InpIt last, const allocator_type& a = allocator_type())
+ : Base(a)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InpIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_initialize_dispatch(first, last, Result());
+ }
+
+ ~deque()
+ {
+ priv_destroy_range(this->members_.m_start, this->members_.m_finish);
+ }
+
+ deque& operator= (const deque& x)
+ {
+ const size_type len = size();
+ if (&x != this) {
+ if (len >= x.size())
+ this->erase(std::copy(x.begin(), x.end(), this->members_.m_start), this->members_.m_finish);
+ else {
+ const_iterator mid = x.begin() + difference_type(len);
+ std::copy(x.begin(), mid, this->members_.m_start);
+ this->insert(this->members_.m_finish, mid, x.end());
+ }
+ }
+ return *this;
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ deque& operator= (boost::rv<deque> &mx)
+ {
+ deque &x = mx.get();
+ #else
+ deque& operator= (deque &&x)
+ {
+ #endif
+ this->clear();
+ this->swap(x);
+ return *this;
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<deque> &x)
+ { this->swap(x.get()); }
+ void swap(deque& x)
+ #else
+ void swap(deque &&x)
+ #endif
+ {
+ std::swap(this->members_.m_start, x.members_.m_start);
+ std::swap(this->members_.m_finish, x.members_.m_finish);
+ std::swap(this->members_.m_map, x.members_.m_map);
+ std::swap(this->members_.m_map_size, x.members_.m_map_size);
+ }
+
+ void assign(size_type n, const T& val)
+ { this->priv_fill_assign(n, val); }
+
+ template <class InpIt>
+ void assign(InpIt first, InpIt last)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InpIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_assign_dispatch(first, last, Result());
+ }
+
+ void push_back(const value_type& t)
+ {
+ if(this->priv_push_back_simple_available()){
+ new(this->priv_push_back_simple_pos())value_type(t);
+ this->priv_push_back_simple_commit();
+ }
+ else{
+ this->priv_insert_aux(cend(), size_type(1), t);
+ }
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void push_back(boost::rv<value_type> &mt)
+ {
+ value_type &t = mt.get();
+ #else
+ void push_back(value_type &&t)
+ {
+ #endif
+ if(this->priv_push_back_simple_available()){
+ new(this->priv_push_back_simple_pos())value_type(boost::move(t));
+ this->priv_push_back_simple_commit();
+ }
+ else{
+ this->priv_insert_aux(cend(), move_it(r_iterator(t, 1)), move_it(r_iterator()));
+ }
+ }
+
+ void push_front(const value_type& t)
+ {
+ if(this->priv_push_front_simple_available()){
+ new(this->priv_push_front_simple_pos())value_type(t);
+ this->priv_push_front_simple_commit();
+ }
+ else{
+ this->priv_insert_aux(cbegin(), size_type(1), t);
+ }
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void push_front(boost::rv<value_type> &mt)
+ {
+ value_type &t = mt.get();
+ #else
+ void push_front(value_type &&t)
+ {
+ #endif
+ if(this->priv_push_front_simple_available()){
+ new(this->priv_push_front_simple_pos())value_type(boost::move(t));
+ this->priv_push_front_simple_commit();
+ }
+ else{
+ this->priv_insert_aux(cbegin(), move_it(r_iterator(t, 1)), move_it(r_iterator()));
+ }
+ }
+
+ void pop_back()
+ {
+ if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) {
+ --this->members_.m_finish.m_cur;
+ detail::get_pointer(this->members_.m_finish.m_cur)->~value_type();
+ }
+ else
+ this->priv_pop_back_aux();
+ }
+
+ void pop_front()
+ {
+ if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) {
+ detail::get_pointer(this->members_.m_start.m_cur)->~value_type();
+ ++this->members_.m_start.m_cur;
+ }
+ else
+ this->priv_pop_front_aux();
+ }
+
+ iterator insert(const_iterator position, const value_type& x)
+ {
+ if (position == cbegin()){
+ this->push_front(x);
+ return begin();
+ }
+ else if (position == cend()){
+ this->push_back(x);
+ return (end()-1);
+ }
+ else {
+ size_type n = position - cbegin();
+ this->priv_insert_aux(position, size_type(1), x);
+ return iterator(this->begin() + n);
+ }
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<value_type> &m)
+ {
+ value_type &mx = m.get();
+ #else
+ iterator insert(const_iterator position, value_type &&mx)
+ {
+ #endif
+ if (position == cbegin()) {
+ this->push_front(boost::move(mx));
+ return begin();
+ }
+ else if (position == cend()) {
+ this->push_back(boost::move(mx));
+ return(end()-1);
+ }
+ else {
+ //Just call more general insert(pos, size, value) and return iterator
+ size_type n = position - begin();
+ this->priv_insert_aux(position, move_it(r_iterator(mx, 1)), move_it(r_iterator()));
+ return iterator(this->begin() + n);
+ }
+ }
+
+ void insert(const_iterator pos, size_type n, const value_type& x)
+ { this->priv_fill_insert(pos, n, x); }
+
+ // Check whether it's an integral type. If so, it's not an iterator.
+ template <class InpIt>
+ void insert(const_iterator pos, InpIt first, InpIt last)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InpIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_insert_dispatch(pos, first, last, Result());
+ }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template <class... Args>
+ void emplace_back(Args&&... args)
+ {
+ if(this->priv_push_back_simple_available()){
+ new(this->priv_push_back_simple_pos())value_type(boost::forward_constructor<Args>(args)...);
+ this->priv_push_back_simple_commit();
+ }
+ else{
+ detail::advanced_insert_aux_emplace<T, iterator, Args...> proxy(boost::forward_constructor<Args>(args)...);
+ this->priv_insert_aux_impl(this->cend(), 1, proxy);
+ }
+ }
+
+ template <class... Args>
+ void emplace_front(Args&&... args)
+ {
+ if(this->priv_push_front_simple_available()){
+ new(this->priv_push_front_simple_pos())value_type(boost::forward_constructor<Args>(args)...);
+ this->priv_push_front_simple_commit();
+ }
+ else{
+ detail::advanced_insert_aux_emplace<T, iterator, Args...> proxy(boost::forward_constructor<Args>(args)...);
+ this->priv_insert_aux_impl(this->cbegin(), 1, proxy);
+ }
+ }
+
+ template <class... Args>
+ iterator emplace(const_iterator p, Args&&... args)
+ {
+ if(p == this->cbegin()){
+ this->emplace_front(boost::forward_constructor<Args>(args)...);
+ return this->begin();
+ }
+ else if(p == this->cend()){
+ this->emplace_back(boost::forward_constructor<Args>(args)...);
+ return (this->end()-1);
+ }
+ else{
+ size_type n = p - this->cbegin();
+ detail::advanced_insert_aux_emplace<T, iterator, Args...> proxy(boost::forward_constructor<Args>(args)...);
+ this->priv_insert_aux_impl(p, 1, proxy);
+ return iterator(this->begin() + n);
+ }
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //0 args
+ void emplace_back()
+ {
+ if(priv_push_front_simple_available()){
+ new(priv_push_front_simple_pos())value_type();
+ priv_push_front_simple_commit();
+ }
+ else{
+ detail::advanced_insert_aux_emplace<T, iterator> proxy;
+ priv_insert_aux_impl(cend(), 1, proxy);
+ }
+ }
+
+ void emplace_front()
+ {
+ if(priv_push_front_simple_available()){
+ new(priv_push_front_simple_pos())value_type();
+ priv_push_front_simple_commit();
+ }
+ else{
+ detail::advanced_insert_aux_emplace<T, iterator> proxy;
+ priv_insert_aux_impl(cbegin(), 1, proxy);
+ }
+ }
+
+ iterator emplace(const_iterator p)
+ {
+ if(p == cbegin()){
+ emplace_front();
+ return begin();
+ }
+ else if(p == cend()){
+ emplace_back();
+ return (end()-1);
+ }
+ else{
+ size_type n = p - cbegin();
+ detail::advanced_insert_aux_emplace<T, iterator> proxy;
+ priv_insert_aux_impl(p, 1, proxy);
+ return iterator(this->begin() + n);
+ }
+ }
+
+ //advanced_insert_int.hpp includes all necessary preprocessor machinery...
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ if(priv_push_back_simple_available()){ \
+ new(priv_push_back_simple_pos())value_type \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ priv_push_back_simple_commit(); \
+ } \
+ else{ \
+ detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
+ <value_type, iterator, BOOST_PP_ENUM_PARAMS(n, P)> \
+ proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ priv_insert_aux_impl(cend(), 1, proxy); \
+ } \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ if(priv_push_front_simple_available()){ \
+ new(priv_push_front_simple_pos())value_type \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ priv_push_front_simple_commit(); \
+ } \
+ else{ \
+ detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
+ <value_type, iterator, BOOST_PP_ENUM_PARAMS(n, P)> \
+ proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ priv_insert_aux_impl(cbegin(), 1, proxy); \
+ } \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ if(p == this->cbegin()){ \
+ this->emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ return this->begin(); \
+ } \
+ else if(p == cend()){ \
+ this->emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ return (this->end()-1); \
+ } \
+ else{ \
+ size_type pos_num = p - this->cbegin(); \
+ detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
+ <value_type, iterator, BOOST_PP_ENUM_PARAMS(n, P)> \
+ proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ this->priv_insert_aux_impl(p, 1, proxy); \
+ return iterator(this->begin() + pos_num); \
+ } \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ void resize(size_type new_size, const value_type& x)
+ {
+ const size_type len = size();
+ if (new_size < len)
+ this->erase(this->members_.m_start + new_size, this->members_.m_finish);
+ else
+ this->insert(this->members_.m_finish, new_size - len, x);
+ }
+
+ void resize(size_type new_size)
+ {
+ const size_type len = size();
+ if (new_size < len)
+ this->erase(this->members_.m_start + new_size, this->members_.m_finish);
+ else{
+ size_type n = new_size - this->size();
+ detail::default_construct_aux_proxy<T, iterator, size_type> proxy(n);
+ priv_insert_aux_impl(this->cend(), n, proxy);
+ }
+ }
+
+ iterator erase(const_iterator pos)
+ {
+ const_iterator next = pos;
+ ++next;
+ difference_type index = pos - this->members_.m_start;
+ if (size_type(index) < (this->size() >> 1)) {
+ boost::move_backward(begin(), iterator(pos), iterator(next));
+ pop_front();
+ }
+ else {
+ boost::move(iterator(next), end(), iterator(pos));
+ pop_back();
+ }
+ return this->members_.m_start + index;
+ }
+
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ if (first == this->members_.m_start && last == this->members_.m_finish) {
+ this->clear();
+ return this->members_.m_finish;
+ }
+ else {
+ difference_type n = last - first;
+ difference_type elems_before = first - this->members_.m_start;
+ if (elems_before < static_cast<difference_type>(this->size() - n) - elems_before) {
+ boost::move_backward(begin(), iterator(first), iterator(last));
+ iterator new_start = this->members_.m_start + n;
+ if(!Base::traits_t::trivial_dctr_after_move)
+ this->priv_destroy_range(this->members_.m_start, new_start);
+ this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node);
+ this->members_.m_start = new_start;
+ }
+ else {
+ boost::move(iterator(last), end(), iterator(first));
+ iterator new_finish = this->members_.m_finish - n;
+ if(!Base::traits_t::trivial_dctr_after_move)
+ this->priv_destroy_range(new_finish, this->members_.m_finish);
+ this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1);
+ this->members_.m_finish = new_finish;
+ }
+ return this->members_.m_start + elems_before;
+ }
+ }
+
+ void clear()
+ {
+ for (index_pointer node = this->members_.m_start.m_node + 1;
+ node < this->members_.m_finish.m_node;
+ ++node) {
+ this->priv_destroy_range(*node, *node + this->s_buffer_size());
+ this->priv_deallocate_node(*node);
+ }
+
+ if (this->members_.m_start.m_node != this->members_.m_finish.m_node) {
+ this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.m_last);
+ this->priv_destroy_range(this->members_.m_finish.m_first, this->members_.m_finish.m_cur);
+ this->priv_deallocate_node(this->members_.m_finish.m_first);
+ }
+ else
+ this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur);
+
+ this->members_.m_finish = this->members_.m_start;
+ }
+
+ /// @cond
+ private:
+
+ bool priv_push_back_simple_available() const
+ {
+ return this->members_.m_map &&
+ (this->members_.m_finish.m_cur != (this->members_.m_finish.m_last - 1));
+ }
+
+ void *priv_push_back_simple_pos() const
+ {
+ return static_cast<void*>(detail::get_pointer(this->members_.m_finish.m_cur));
+ }
+
+ void priv_push_back_simple_commit()
+ {
+ ++this->members_.m_finish.m_cur;
+ }
+
+ bool priv_push_front_simple_available() const
+ {
+ return this->members_.m_map &&
+ (this->members_.m_start.m_cur != this->members_.m_start.m_first);
+ }
+
+ void *priv_push_front_simple_pos() const
+ { return static_cast<void*>(detail::get_pointer(this->members_.m_start.m_cur) - 1); }
+
+ void priv_push_front_simple_commit()
+ { --this->members_.m_start.m_cur; }
+
+ template <class InpIt>
+ void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag)
+ {
+ for(;first != last; ++first){
+ this->insert(pos, boost::move(value_type(*first)));
+ }
+ }
+
+ template <class FwdIt>
+ void priv_insert_aux(const_iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag)
+ { this->priv_insert_aux(pos, first, last); }
+
+ // assign(), a generalized assignment member function. Two
+ // versions: one that takes a count, and one that takes a range.
+ // The range version is a member template, so we dispatch on whether
+ // or not the type is an integer.
+ void priv_fill_assign(size_type n, const T& val)
+ {
+ if (n > size()) {
+ std::fill(begin(), end(), val);
+ this->insert(cend(), n - size(), val);
+ }
+ else {
+ this->erase(cbegin() + n, cend());
+ std::fill(begin(), end(), val);
+ }
+ }
+
+ template <class Integer>
+ void priv_initialize_dispatch(Integer n, Integer x, detail::true_)
+ {
+ this->priv_initialize_map(n);
+ this->priv_fill_initialize(x);
+ }
+
+ template <class InpIt>
+ void priv_initialize_dispatch(InpIt first, InpIt last, detail::false_)
+ {
+ typedef typename std::iterator_traits<InpIt>::iterator_category ItCat;
+ this->priv_range_initialize(first, last, ItCat());
+ }
+
+ void priv_destroy_range(iterator p, iterator p2)
+ {
+ for(;p != p2; ++p)
+ detail::get_pointer(&*p)->~value_type();
+ }
+
+ void priv_destroy_range(pointer p, pointer p2)
+ {
+ for(;p != p2; ++p)
+ detail::get_pointer(&*p)->~value_type();
+ }
+
+ template <class Integer>
+ void priv_assign_dispatch(Integer n, Integer val, detail::true_)
+ { this->priv_fill_assign((size_type) n, (T) val); }
+
+ template <class InpIt>
+ void priv_assign_dispatch(InpIt first, InpIt last, detail::false_)
+ {
+ typedef typename std::iterator_traits<InpIt>::iterator_category ItCat;
+ this->priv_assign_aux(first, last, ItCat());
+ }
+
+ template <class InpIt>
+ void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag)
+ {
+ iterator cur = begin();
+ for ( ; first != last && cur != end(); ++cur, ++first)
+ *cur = *first;
+ if (first == last)
+ this->erase(cur, cend());
+ else
+ this->insert(cend(), first, last);
+ }
+
+ template <class FwdIt>
+ void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag)
+ {
+ size_type len = std::distance(first, last);
+ if (len > size()) {
+ FwdIt mid = first;
+ std::advance(mid, size());
+ std::copy(first, mid, begin());
+ this->insert(cend(), mid, last);
+ }
+ else
+ this->erase(std::copy(first, last, begin()), cend());
+ }
+
+ template <class Integer>
+ void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, detail::true_)
+ { this->priv_fill_insert(pos, (size_type) n, (value_type) x); }
+
+ template <class InpIt>
+ void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, detail::false_)
+ {
+ typedef typename std::iterator_traits<InpIt>::iterator_category ItCat;
+ this->priv_insert_aux(pos, first, last, ItCat());
+ }
+
+ void priv_insert_aux(const_iterator pos, size_type n, const value_type& x)
+ {
+ typedef constant_iterator<value_type, difference_type> c_it;
+ this->priv_insert_aux(pos, c_it(x, n), c_it());
+ }
+
+ //Just forward all operations to priv_insert_aux_impl
+ template <class FwdIt>
+ void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last)
+ {
+ detail::advanced_insert_aux_proxy<T, FwdIt, iterator> proxy(first, last);
+ priv_insert_aux_impl(p, (size_type)std::distance(first, last), proxy);
+ }
+
+ void priv_insert_aux_impl(const_iterator p, size_type n, advanced_insert_aux_int_t &interf)
+ {
+ iterator pos(p);
+ if(!this->members_.m_map){
+ this->priv_initialize_map(0);
+ pos = this->begin();
+ }
+
+ const difference_type elemsbefore = pos - this->members_.m_start;
+ size_type length = this->size();
+ if (elemsbefore < static_cast<difference_type>(length / 2)) {
+ iterator new_start = this->priv_reserve_elements_at_front(n);
+ iterator old_start = this->members_.m_start;
+ pos = this->members_.m_start + elemsbefore;
+ if (elemsbefore >= difference_type(n)) {
+ iterator start_n = this->members_.m_start + difference_type(n);
+ boost::uninitialized_move(this->members_.m_start, start_n, new_start);
+ this->members_.m_start = new_start;
+ boost::move(start_n, pos, old_start);
+ interf.copy_all_to(pos - difference_type(n));
+ }
+ else {
+ difference_type mid_count = (difference_type(n) - elemsbefore);
+ iterator mid_start = old_start - mid_count;
+ interf.uninitialized_copy_some_and_update(mid_start, mid_count, true);
+ this->members_.m_start = mid_start;
+ boost::uninitialized_move(old_start, pos, new_start);
+ this->members_.m_start = new_start;
+ interf.copy_all_to(old_start);
+ }
+ }
+ else {
+ iterator new_finish = this->priv_reserve_elements_at_back(n);
+ iterator old_finish = this->members_.m_finish;
+ const difference_type elemsafter =
+ difference_type(length) - elemsbefore;
+ pos = this->members_.m_finish - elemsafter;
+ if (elemsafter >= difference_type(n)) {
+ iterator finish_n = this->members_.m_finish - difference_type(n);
+ boost::uninitialized_move(finish_n, this->members_.m_finish, this->members_.m_finish);
+ this->members_.m_finish = new_finish;
+ boost::move_backward(pos, finish_n, old_finish);
+ interf.copy_all_to(pos);
+ }
+ else {
+ interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false);
+ this->members_.m_finish += n-elemsafter;
+ boost::uninitialized_move(pos, old_finish, this->members_.m_finish);
+ this->members_.m_finish = new_finish;
+ interf.copy_all_to(pos);
+ }
+ }
+ }
+
+ void priv_fill_insert(const_iterator pos, size_type n, const value_type& x)
+ {
+ typedef constant_iterator<value_type, difference_type> c_it;
+ this->insert(pos, c_it(x, n), c_it());
+ }
+
+ // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized,
+ // but none of the deque's elements have yet been constructed.
+ void priv_fill_initialize(const value_type& value)
+ {
+ index_pointer cur;
+ BOOST_TRY {
+ for (cur = this->members_.m_start.m_node; cur < this->members_.m_finish.m_node; ++cur){
+ std::uninitialized_fill(*cur, *cur + this->s_buffer_size(), value);
+ }
+ std::uninitialized_fill(this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value);
+ }
+ BOOST_CATCH(...){
+ this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ template <class InpIt>
+ void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag)
+ {
+ this->priv_initialize_map(0);
+ BOOST_TRY {
+ for ( ; first != last; ++first)
+ this->push_back(*first);
+ }
+ BOOST_CATCH(...){
+ this->clear();
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ template <class FwdIt>
+ void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag)
+ {
+ size_type n = 0;
+ n = std::distance(first, last);
+ this->priv_initialize_map(n);
+
+ index_pointer cur_node;
+ BOOST_TRY {
+ for (cur_node = this->members_.m_start.m_node;
+ cur_node < this->members_.m_finish.m_node;
+ ++cur_node) {
+ FwdIt mid = first;
+ std::advance(mid, this->s_buffer_size());
+ boost::uninitialized_copy_or_move(first, mid, *cur_node);
+ first = mid;
+ }
+ boost::uninitialized_copy_or_move(first, last, this->members_.m_finish.m_first);
+ }
+ BOOST_CATCH(...){
+ this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first.
+ void priv_pop_back_aux()
+ {
+ this->priv_deallocate_node(this->members_.m_finish.m_first);
+ this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node - 1);
+ this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1;
+ detail::get_pointer(this->members_.m_finish.m_cur)->~value_type();
+ }
+
+ // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_last - 1. Note that
+ // if the deque has at least one element (a precondition for this member
+ // function), and if this->members_.m_start.m_cur == this->members_.m_start.m_last, then the deque
+ // must have at least two nodes.
+ void priv_pop_front_aux()
+ {
+ detail::get_pointer(this->members_.m_start.m_cur)->~value_type();
+ this->priv_deallocate_node(this->members_.m_start.m_first);
+ this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1);
+ this->members_.m_start.m_cur = this->members_.m_start.m_first;
+ }
+
+ iterator priv_reserve_elements_at_front(size_type n)
+ {
+ size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first;
+ if (n > vacancies){
+ size_type new_elems = n-vacancies;
+ size_type new_nodes = (new_elems + this->s_buffer_size() - 1) /
+ this->s_buffer_size();
+ size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map);
+ if (new_nodes > s){
+ this->priv_reallocate_map(new_nodes, true);
+ }
+ size_type i = 1;
+ BOOST_TRY {
+ for (; i <= new_nodes; ++i)
+ *(this->members_.m_start.m_node - i) = this->priv_allocate_node();
+ }
+ BOOST_CATCH(...) {
+ for (size_type j = 1; j < i; ++j)
+ this->priv_deallocate_node(*(this->members_.m_start.m_node - j));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+ return this->members_.m_start - difference_type(n);
+ }
+
+ iterator priv_reserve_elements_at_back(size_type n)
+ {
+ size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1;
+ if (n > vacancies){
+ size_type new_elems = n - vacancies;
+ size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size();
+ size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map));
+ if (new_nodes + 1 > s){
+ this->priv_reallocate_map(new_nodes, false);
+ }
+ size_type i;
+ BOOST_TRY {
+ for (i = 1; i <= new_nodes; ++i)
+ *(this->members_.m_finish.m_node + i) = this->priv_allocate_node();
+ }
+ BOOST_CATCH(...) {
+ for (size_type j = 1; j < i; ++j)
+ this->priv_deallocate_node(*(this->members_.m_finish.m_node + j));
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+ return this->members_.m_finish + difference_type(n);
+ }
+
+ void priv_reallocate_map(size_type nodes_to_add, bool add_at_front)
+ {
+ size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1;
+ size_type new_num_nodes = old_num_nodes + nodes_to_add;
+
+ index_pointer new_nstart;
+ if (this->members_.m_map_size > 2 * new_num_nodes) {
+ new_nstart = this->members_.m_map + (this->members_.m_map_size - new_num_nodes) / 2
+ + (add_at_front ? nodes_to_add : 0);
+ if (new_nstart < this->members_.m_start.m_node)
+ boost::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart);
+ else
+ boost::move_backward
+ (this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart + old_num_nodes);
+ }
+ else {
+ size_type new_map_size =
+ this->members_.m_map_size + max_value(this->members_.m_map_size, nodes_to_add) + 2;
+
+ index_pointer new_map = this->priv_allocate_map(new_map_size);
+ new_nstart = new_map + (new_map_size - new_num_nodes) / 2
+ + (add_at_front ? nodes_to_add : 0);
+ boost::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart);
+ this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size);
+
+ this->members_.m_map = new_map;
+ this->members_.m_map_size = new_map_size;
+ }
+
+ this->members_.m_start.priv_set_node(new_nstart);
+ this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1);
+ }
+ /// @endcond
+};
+
+// Nonmember functions.
+template <class T, class Alloc>
+inline bool operator==(const deque<T, Alloc>& x,
+ const deque<T, Alloc>& y)
+{
+ return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
+}
+
+template <class T, class Alloc>
+inline bool operator<(const deque<T, Alloc>& x,
+ const deque<T, Alloc>& y)
+{
+ return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+}
+
+template <class T, class Alloc>
+inline bool operator!=(const deque<T, Alloc>& x,
+ const deque<T, Alloc>& y)
+ { return !(x == y); }
+
+template <class T, class Alloc>
+inline bool operator>(const deque<T, Alloc>& x,
+ const deque<T, Alloc>& y)
+ { return y < x; }
+
+template <class T, class Alloc>
+inline bool operator<=(const deque<T, Alloc>& x,
+ const deque<T, Alloc>& y)
+ { return !(y < x); }
+
+template <class T, class Alloc>
+inline bool operator>=(const deque<T, Alloc>& x,
+ const deque<T, Alloc>& y)
+ { return !(x < y); }
+
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class A>
+inline void swap(deque<T, A>& x, deque<T, A>& y)
+{ x.swap(y); }
+
+template <class T, class A>
+inline void swap(boost::rv<deque<T, A> > x, deque<T, A>& y)
+{ x.get().swap(y); }
+
+template <class T, class A>
+inline void swap(deque<T, A> &x, boost::rv<deque<T, A> > &y)
+{ x.swap(y.get()); }
+#else
+template <class T, class A>
+inline void swap(deque<T, A>&&x, deque<T, A>&&y)
+{ x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class A>
+struct has_trivial_destructor_after_move<deque<T, A> >
+{
+ enum { value = has_trivial_destructor<A>::value };
+};
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_DEQUE_HPP
+
Added: sandbox/boost/interprocess/containers/detail/flat_tree.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/detail/flat_tree.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,890 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// (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 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_INTERPROCESS_FLAT_TREE_HPP
+#define BOOST_INTERPROCESS_FLAT_TREE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/containers/vector.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+namespace boost {
+
+namespace interprocess {
+
+namespace detail {
+
+template <class Key, class Value, class KeyOfValue,
+ class Compare, class Alloc>
+class flat_tree
+{
+ typedef boost::interprocess::vector<Value, Alloc> vector_t;
+ typedef 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_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)
+ { }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ flat_tree(boost::rv<flat_tree> &x)
+ : m_data(boost::move(x.get().m_data))
+ { }
+ #else
+ flat_tree(flat_tree &&x)
+ : m_data(boost::move(x.m_data))
+ { }
+ #endif
+
+ ~flat_tree()
+ { }
+
+ flat_tree& operator=(const flat_tree& x)
+ { m_data = x.m_data; return *this; }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ flat_tree& operator=(boost::rv<flat_tree> &mx)
+ { m_data = boost::move(mx.get().m_data); return *this; }
+ #else
+ flat_tree& operator=(flat_tree &&mx)
+ { m_data = boost::move(mx.m_data); return *this; }
+ #endif
+
+ 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;
+ detail::do_swap(mycomp, othercomp);
+ vector_t & myvect = this->m_data.m_vect;
+ vector_t & othervect = other.m_data.m_vect;
+ myvect.swap(othervect);
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ void swap(boost::rv<flat_tree> &other)
+ { this->swap(other.get()); }
+ #else
+ void swap(flat_tree &&other)
+ { this->swap(other); }
+ #endif
+
+ 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;
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ std::pair<iterator,bool> insert_unique(boost::rv<value_type> &mval)
+ {
+ value_type &val = mval.get();
+ #else
+ std::pair<iterator,bool> insert_unique(value_type && val)
+ {
+ #endif
+ 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::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;
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ iterator insert_equal(boost::rv<value_type> &mval)
+ {
+ iterator i = this->upper_bound(KeyOfValue()(mval.get()));
+ i = this->m_data.m_vect.insert(i, mval);
+ return i;
+ }
+ #else
+ iterator insert_equal(value_type && mval)
+ {
+ iterator i = this->upper_bound(KeyOfValue()(mval));
+ i = this->m_data.m_vect.insert(i, boost::move(mval));
+ return i;
+ }
+ #endif
+
+ 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;
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ iterator insert_unique(const_iterator pos, boost::rv<value_type> &mval)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret = priv_insert_unique_prepare(pos, mval.get(), data);
+ if(ret.second){
+ ret.first = priv_insert_commit(data, mval);
+ }
+ return ret.first;
+ }
+ #else
+ iterator insert_unique(const_iterator pos, 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::move(mval));
+ }
+ return ret.first;
+ }
+ #endif
+
+ 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);
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ iterator insert_equal(const_iterator pos, boost::rv<value_type> &mval)
+ {
+ insert_commit_data data;
+ priv_insert_equal_prepare(pos, mval.get(), data);
+ return priv_insert_commit(data, mval);
+ }
+ #else
+ iterator insert_equal(const_iterator pos, value_type && mval)
+ {
+ insert_commit_data data;
+ priv_insert_equal_prepare(pos, mval, data);
+ return priv_insert_commit(data, boost::move(mval));
+ }
+ #endif
+
+ 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_INTERPROCESS_PERFECT_FORWARDING
+
+ template <class... Args>
+ iterator emplace_unique(Args&&... args)
+ {
+ value_type val(boost::forward_constructor<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::move<value_type>(val));
+ }
+ return ret.first;
+ }
+
+ template <class... Args>
+ iterator emplace_hint_unique(const_iterator hint, Args&&... args)
+ {
+ value_type val(boost::forward_constructor<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::move<value_type>(val));
+ }
+ return ret.first;
+ }
+
+ template <class... Args>
+ iterator emplace_equal(Args&&... args)
+ {
+ value_type val(boost::forward_constructor<Args>(args)...);
+ iterator i = this->upper_bound(KeyOfValue()(val));
+ i = this->m_data.m_vect.insert(i, boost::move<value_type>(val));
+ return i;
+ }
+
+ template <class... Args>
+ iterator emplace_hint_equal(const_iterator hint, Args&&... args)
+ {
+ value_type val(boost::forward_constructor<Args>(args)...);
+ insert_commit_data data;
+ priv_insert_equal_prepare(hint, val, data);
+ return priv_insert_commit(data, boost::move<value_type>(val));
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace_unique()
+ {
+ 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::move<value_type>(val));
+ }
+ return ret.first;
+ }
+
+ iterator emplace_hint_unique(const_iterator hint)
+ {
+ 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::move<value_type>(val));
+ }
+ return ret.first;
+ }
+
+ iterator emplace_equal()
+ {
+ 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::move<value_type>(val));
+ return i;
+ }
+
+ iterator emplace_hint_equal(const_iterator hint)
+ {
+ 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::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_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_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::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_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_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::move<value_type>(val)); \
+ } \
+ return ret.first; \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ iterator i = this->upper_bound(KeyOfValue()(val)); \
+ i = this->m_data.m_vect.insert(i, boost::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_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ insert_commit_data data; \
+ priv_insert_equal_prepare(hint, val, data); \
+ return priv_insert_commit(data, boost::move<value_type>(val)); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_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>
+ #ifndef BOOST_HAS_RVALUE_REFS
+ iterator priv_insert_commit
+ (insert_commit_data &commit_data, const Convertible &convertible)
+ #else
+ iterator priv_insert_commit
+ (insert_commit_data &commit_data, Convertible &&convertible)
+ #endif
+ {
+ return this->m_data.m_vect.insert
+ ( commit_data.position
+ , boost::forward_constructor<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 detail {
+
+//!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<detail::flat_tree<K, V, KOV, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_FLAT_TREE_HPP
Added: sandbox/boost/interprocess/containers/detail/node_alloc_holder.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/detail/node_alloc_holder.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,431 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_ALLOC_HPP_
+#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_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/version_type.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/algorithms.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/intrusive/options.hpp>
+
+#include <utility>
+#include <functional>
+
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+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 detail::scoped_deallocator<NodeAlloc> Deallocator;
+ typedef typename NodeAlloc::size_type size_type;
+ typedef typename NodeAlloc::difference_type difference_type;
+ typedef detail::integral_constant<unsigned, 1> allocator_v1;
+ typedef detail::integral_constant<unsigned, 2> allocator_v2;
+ typedef detail::integral_constant<unsigned,
+ boost::interprocess::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_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())
+ {}
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ node_alloc_holder(boost::rv<node_alloc_holder> &other)
+ : members_(boost::move(other.get().node_alloc()))
+ { this->swap(other.get()); }
+ #else
+ node_alloc_holder(node_alloc_holder &&other)
+ : members_(boost::move(other.node_alloc()))
+ { this->swap(other); }
+ #endif
+
+ template<class Pred>
+ node_alloc_holder(const ValAlloc &a, const Pred &c)
+ : members_(a, typename ICont::value_compare(c))
+ {}
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class Pred>
+ node_alloc_holder(boost::rv<ValAlloc> &a, const Pred &c)
+ : members_(a.get(), typename ICont::value_compare(c))
+ {}
+ #else
+ template<class Pred>
+ node_alloc_holder(ValAlloc &&a, const Pred &c)
+ : members_(a, typename ICont::value_compare(c))
+ {}
+ #endif
+
+ 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); }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class Convertible1, class Convertible2>
+ static void construct(const NodePtr &ptr, boost::rv<std::pair<Convertible1, Convertible2> > &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 = 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::move(value.get().first));
+ BOOST_TRY{
+ new((void*)&valueptr->second) second_type(boost::move(value.get().second));
+ }
+ BOOST_CATCH(...){
+ valueptr->first.~first_type();
+ static_cast<hook_type*>(nodeptr)->~hook_type();
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+ #else
+ template<class Convertible1, class Convertible2>
+ static void construct(const NodePtr &ptr, std::pair<Convertible1, Convertible2> &&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 = 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::move(value.first));
+ BOOST_TRY{
+ new((void*)&valueptr->second) second_type(boost::move(value.second));
+ }
+ BOOST_CATCH(...){
+ valueptr->first.~first_type();
+ static_cast<hook_type*>(nodeptr)->~hook_type();
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+ #endif
+
+ static void destroy(const NodePtr &ptr)
+ { detail::get_pointer(ptr)->~Node(); }
+
+ Deallocator create_node_and_deallocator()
+ {
+ return Deallocator(this->allocate_one(), this->node_alloc());
+ }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template<class ...Args>
+ static void construct(const NodePtr &ptr, Args &&...args)
+ { new((void*)detail::get_pointer(ptr)) Node(boost::forward_constructor<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::forward_constructor<Args>(args)...);
+ node_deallocator.release();
+ return (p);
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ static void construct(const NodePtr &ptr)
+ { new((void*)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_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ new((void*)detail::get_pointer(ptr)) \
+ Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_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_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ NodePtr p = this->allocate_one(); \
+ Deallocator node_deallocator(p, this->node_alloc()); \
+ self_t::construct(p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ node_deallocator.release(); \
+ return (p); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_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::construct_in_place(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){
+ 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 = detail::get_pointer(mem.front());
+ mem.pop_front();
+ //This can throw
+ constructed = 0;
+ boost::interprocess::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::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::is_movable<typename NodeAlloc::multiallocation_chain>::value == true));
+ if(!chain.empty())
+ this->node_alloc().deallocate_individual(boost::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 detail {
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_
Added: sandbox/boost/interprocess/containers/detail/tree.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/detail/tree.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1092 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's stl_tree file. Modified by Ion Gaztanaga 2005.
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+#ifndef BOOST_INTERPROCESS_TREE_HPP
+#define BOOST_INTERPROCESS_TREE_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/algorithms.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/containers/detail/node_alloc_holder.hpp>
+#include <boost/intrusive/rbtree.hpp>
+#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+#include <boost/interprocess/detail/preprocessor.hpp>
+#endif
+
+#include <utility> //std::pair
+#include <iterator>
+#include <algorithm>
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+template<class Key, class Value, class KeyCompare, class KeyOfValue>
+struct value_compare_impl
+ : public KeyCompare
+{
+ typedef Value value_type;
+ typedef KeyCompare key_compare;
+ typedef KeyOfValue key_of_value;
+ typedef Key key_type;
+
+ value_compare_impl(key_compare kcomp)
+ : key_compare(kcomp)
+ {}
+
+ const key_compare &key_comp() const
+ { return static_cast<const key_compare &>(*this); }
+
+ key_compare &key_comp()
+ { return static_cast<key_compare &>(*this); }
+
+ template<class A, class B>
+ bool operator()(const A &a, const B &b) const
+ { return key_compare::operator()(KeyOfValue()(a), KeyOfValue()(b)); }
+};
+
+template<class VoidPointer>
+struct rbtree_hook
+{
+ typedef typename bi::make_set_base_hook
+ < bi::void_pointer<VoidPointer>
+ , bi::link_mode<bi::normal_link>
+ , bi::optimize_size<true>
+ >::type type;
+};
+
+template<class T>
+struct rbtree_type
+{
+ typedef T type;
+};
+
+template<class T1, class T2>
+struct rbtree_type< std::pair<T1, T2> >
+{
+ typedef pair<T1, T2> type;
+};
+
+template <class T, class VoidPointer>
+struct rbtree_node
+ : public rbtree_hook<VoidPointer>::type
+{
+ typedef typename rbtree_hook<VoidPointer>::type hook_type;
+
+ typedef T value_type;
+ typedef typename rbtree_type<T>::type internal_type;
+
+ typedef rbtree_node<T, VoidPointer> node_type;
+
+ #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ rbtree_node()
+ : m_data()
+ {}
+
+ rbtree_node(const rbtree_node &other)
+ : m_data(other.m_data)
+ {}
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ rbtree_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \
+ {} \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template<class ...Args>
+ rbtree_node(Args &&...args)
+ : m_data(boost::forward_constructor<Args>(args)...)
+ {}
+ #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ rbtree_node &operator=(const rbtree_node &other)
+ { do_assign(other.m_data); return *this; }
+
+ T &get_data()
+ {
+ T* ptr = reinterpret_cast<T*>(&this->m_data);
+ return *ptr;
+ }
+
+ const T &get_data() const
+ {
+ const T* ptr = reinterpret_cast<const T*>(&this->m_data);
+ return *ptr;
+ }
+
+ private:
+ internal_type m_data;
+
+ template<class A, class B>
+ void do_assign(const std::pair<const A, B> &p)
+ {
+ const_cast<A&>(m_data.first) = p.first;
+ m_data.second = p.second;
+ }
+
+ template<class A, class B>
+ void do_assign(const pair<const A, B> &p)
+ {
+ const_cast<A&>(m_data.first) = p.first;
+ m_data.second = p.second;
+ }
+
+ template<class V>
+ void do_assign(const V &v)
+ { m_data = v; }
+
+ public:
+ template<class Convertible>
+ #if !defined(BOOST_HAS_RVALUE_REFS)
+ static void construct(node_type *ptr, const Convertible &convertible)
+ #else
+ static void construct(node_type *ptr, Convertible &&convertible)
+ #endif
+ { new(ptr) node_type(boost::forward_constructor<Convertible>(convertible)); }
+};
+
+}//namespace detail {
+#if !defined(BOOST_HAS_RVALUE_REFS) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR)
+template<class T, class VoidPointer>
+struct has_own_construct_from_it
+ < boost::interprocess::detail::rbtree_node<T, VoidPointer> >
+{
+ static const bool value = true;
+};
+#endif
+namespace detail {
+
+template<class A, class ValueCompare>
+struct intrusive_rbtree_type
+{
+ typedef typename A::value_type value_type;
+ typedef typename detail::pointer_to_other
+ <typename A::pointer, void>::type void_pointer;
+ typedef typename detail::rbtree_node
+ <value_type, void_pointer> node_type;
+ typedef node_compare<ValueCompare, node_type> node_compare_type;
+ typedef typename bi::make_rbtree
+ <node_type
+ ,bi::compare<node_compare_type>
+ ,bi::base_hook<typename rbtree_hook<void_pointer>::type>
+ ,bi::constant_time_size<true>
+ ,bi::size_type<typename A::size_type>
+ >::type container_type;
+ typedef container_type type ;
+};
+
+} //namespace detail {
+
+namespace detail {
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+class rbtree
+ : protected detail::node_alloc_holder
+ <A, typename detail::intrusive_rbtree_type
+ <A, value_compare_impl<Key, Value, KeyCompare, KeyOfValue>
+ >::type
+ >
+{
+ typedef typename detail::intrusive_rbtree_type
+ <A, value_compare_impl
+ <Key, Value, KeyCompare, KeyOfValue>
+ >::type Icont;
+ typedef detail::node_alloc_holder<A, Icont> AllocHolder;
+ typedef typename AllocHolder::NodePtr NodePtr;
+ typedef rbtree < Key, Value, KeyOfValue
+ , KeyCompare, A> ThisType;
+ typedef typename AllocHolder::NodeAlloc NodeAlloc;
+ typedef typename AllocHolder::ValAlloc ValAlloc;
+ typedef typename AllocHolder::Node Node;
+ typedef typename Icont::iterator iiterator;
+ typedef typename Icont::const_iterator iconst_iterator;
+ typedef detail::allocator_destroyer<NodeAlloc> Destroyer;
+ typedef typename AllocHolder::allocator_v1 allocator_v1;
+ typedef typename AllocHolder::allocator_v2 allocator_v2;
+ typedef typename AllocHolder::alloc_version alloc_version;
+
+ class RecyclingCloner;
+ friend class RecyclingCloner;
+
+ class RecyclingCloner
+ {
+ public:
+ RecyclingCloner(AllocHolder &holder, Icont &irbtree)
+ : m_holder(holder), m_icont(irbtree)
+ {}
+
+ NodePtr operator()(const Node &other) const
+ {
+// if(!m_icont.empty()){
+ if(NodePtr p = m_icont.unlink_leftmost_without_rebalance()){
+ //First recycle a node (this can't throw)
+ //NodePtr p = m_icont.unlink_leftmost_without_rebalance();
+ try{
+ //This can throw
+ *p = other;
+ return p;
+ }
+ catch(...){
+ //If there is an exception destroy the whole source
+ m_holder.destroy_node(p);
+ while((p = m_icont.unlink_leftmost_without_rebalance())){
+ m_holder.destroy_node(p);
+ }
+ throw;
+ }
+ }
+ else{
+ return m_holder.create_node(other);
+ }
+ }
+
+ AllocHolder &m_holder;
+ Icont &m_icont;
+ };
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(rbtree)
+
+ typedef Key key_type;
+ typedef Value value_type;
+ typedef A allocator_type;
+ typedef KeyCompare key_compare;
+ typedef value_compare_impl< Key, Value
+ , KeyCompare, KeyOfValue> value_compare;
+ typedef typename A::pointer pointer;
+ typedef typename A::const_pointer const_pointer;
+ typedef typename A::reference reference;
+ typedef typename A::const_reference const_reference;
+ typedef typename A::size_type size_type;
+ typedef typename A::difference_type difference_type;
+ typedef difference_type rbtree_difference_type;
+ typedef pointer rbtree_pointer;
+ typedef const_pointer rbtree_const_pointer;
+ typedef reference rbtree_reference;
+ typedef const_reference rbtree_const_reference;
+ typedef NodeAlloc stored_allocator_type;
+
+ private:
+
+ template<class KeyValueCompare>
+ struct key_node_compare
+ : private KeyValueCompare
+ {
+ key_node_compare(KeyValueCompare comp)
+ : KeyValueCompare(comp)
+ {}
+
+ template<class KeyType>
+ bool operator()(const Node &n, const KeyType &k) const
+ { return KeyValueCompare::operator()(n.get_data(), k); }
+
+ template<class KeyType>
+ bool operator()(const KeyType &k, const Node &n) const
+ { return KeyValueCompare::operator()(k, n.get_data()); }
+ };
+
+ typedef key_node_compare<value_compare> KeyNodeCompare;
+
+ public:
+ //rbtree const_iterator
+ class const_iterator
+ : public std::iterator
+ < std::bidirectional_iterator_tag
+ , value_type , rbtree_difference_type
+ , rbtree_const_pointer , rbtree_const_reference>
+ {
+ protected:
+ typedef typename Icont::iterator iiterator;
+ iiterator m_it;
+ explicit const_iterator(iiterator it) : m_it(it){}
+ void prot_incr() { ++m_it; }
+ void prot_decr() { --m_it; }
+
+ private:
+ iiterator get()
+ { return this->m_it; }
+
+ public:
+ friend class rbtree <Key, Value, KeyOfValue, KeyCompare, A>;
+ typedef rbtree_difference_type difference_type;
+
+ //Constructors
+ const_iterator()
+ : m_it()
+ {}
+
+ //Pointer like operators
+ const_reference operator*() const
+ { return m_it->get_data(); }
+
+ const_pointer operator->() const
+ { return const_pointer(&m_it->get_data()); }
+
+ //Increment / Decrement
+ const_iterator& operator++()
+ { prot_incr(); return *this; }
+
+ const_iterator operator++(int)
+ { iiterator tmp = m_it; ++*this; return const_iterator(tmp); }
+
+ const_iterator& operator--()
+ { prot_decr(); return *this; }
+
+ const_iterator operator--(int)
+ { iiterator tmp = m_it; --*this; return const_iterator(tmp); }
+
+ //Comparison operators
+ bool operator== (const const_iterator& r) const
+ { return m_it == r.m_it; }
+
+ bool operator!= (const const_iterator& r) const
+ { return m_it != r.m_it; }
+ };
+
+ //rbtree iterator
+ class iterator : public const_iterator
+ {
+ private:
+ explicit iterator(iiterator it)
+ : const_iterator(it)
+ {}
+
+ iiterator get()
+ { return this->m_it; }
+
+ public:
+ friend class rbtree <Key, Value, KeyOfValue, KeyCompare, A>;
+ typedef rbtree_pointer pointer;
+ typedef rbtree_reference reference;
+
+ //Constructors
+ iterator(){}
+
+ //Pointer like operators
+ reference operator*() const { return this->m_it->get_data(); }
+ pointer operator->() const { return pointer(&this->m_it->get_data()); }
+
+ //Increment / Decrement
+ iterator& operator++()
+ { this->prot_incr(); return *this; }
+
+ iterator operator++(int)
+ { iiterator tmp = this->m_it; ++*this; return iterator(tmp); }
+
+ iterator& operator--()
+ { this->prot_decr(); return *this; }
+
+ iterator operator--(int)
+ { iterator tmp = *this; --*this; return tmp; }
+ };
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ rbtree(const key_compare& comp = key_compare(),
+ const allocator_type& a = allocator_type())
+ : AllocHolder(a, comp)
+ {}
+
+ template <class InputIterator>
+ rbtree(InputIterator first, InputIterator last, const key_compare& comp,
+ const allocator_type& a, bool unique_insertion)
+ : AllocHolder(a, comp)
+ {
+ typedef typename std::iterator_traits<InputIterator>::iterator_category ItCat;
+ priv_create_and_insert_nodes(first, last, unique_insertion, alloc_version(), ItCat());
+ }
+
+ rbtree(const rbtree& x)
+ : AllocHolder(x, x.key_comp())
+ {
+ this->icont().clone_from
+ (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc()));
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ rbtree(boost::rv<rbtree> &x)
+ : AllocHolder(x.get(), x.get().key_comp())
+ { this->swap(x.get()); }
+ #else
+ rbtree(rbtree &&x)
+ : AllocHolder(x, x.key_comp())
+ { this->swap(x); }
+ #endif
+
+ ~rbtree()
+ {} //AllocHolder clears the tree
+
+ rbtree& operator=(const rbtree& x)
+ {
+ if (this != &x) {
+ //Transfer all the nodes to a temporary tree
+ //If anything goes wrong, all the nodes will be destroyed
+ //automatically
+ Icont other_tree(this->icont().value_comp());
+ other_tree.swap(this->icont());
+
+ //Now recreate the source tree reusing nodes stored by other_tree
+ this->icont().clone_from
+ (x.icont()
+ , RecyclingCloner(*this, other_tree)
+ //, AllocHolder::cloner(*this)
+ , Destroyer(this->node_alloc()));
+
+ //If there are remaining nodes, destroy them
+ NodePtr p;
+ while((p = other_tree.unlink_leftmost_without_rebalance())){
+ AllocHolder::destroy_node(p);
+ }
+ }
+ return *this;
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ rbtree& operator=(boost::rv<rbtree> &mx)
+ { this->clear(); this->swap(mx.get()); return *this; }
+ #else
+ rbtree& operator=(rbtree &&mx)
+ { this->clear(); this->swap(mx); return *this; }
+ #endif
+
+ public:
+ // accessors:
+ value_compare value_comp() const
+ { return this->icont().value_comp().value_comp(); }
+
+ key_compare key_comp() const
+ { return this->icont().value_comp().value_comp().key_comp(); }
+
+ allocator_type get_allocator() const
+ { return allocator_type(this->node_alloc()); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return this->node_alloc(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return this->node_alloc(); }
+
+ iterator begin()
+ { return iterator(this->icont().begin()); }
+
+ const_iterator begin() const
+ { return this->cbegin(); }
+
+ iterator end()
+ { return iterator(this->icont().end()); }
+
+ const_iterator end() const
+ { return this->cend(); }
+
+ reverse_iterator rbegin()
+ { return reverse_iterator(end()); }
+
+ const_reverse_iterator rbegin() const
+ { return this->crbegin(); }
+
+ reverse_iterator rend()
+ { return reverse_iterator(begin()); }
+
+ const_reverse_iterator rend() const
+ { return this->crend(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return const_iterator(this->non_const_icont().begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return const_iterator(this->non_const_icont().end()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return const_reverse_iterator(cend()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return const_reverse_iterator(cbegin()); }
+
+ bool empty() const
+ { return !this->size(); }
+
+ size_type size() const
+ { return this->icont().size(); }
+
+ size_type max_size() const
+ { return AllocHolder::max_size(); }
+
+ void swap(ThisType& x)
+ { AllocHolder::swap(x); }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ void swap(boost::rv<rbtree> &mt)
+ { this->swap(mt.get()); }
+ #else
+ void swap(rbtree &&mt)
+ { this->swap(mt); }
+ #endif
+
+ public:
+
+ typedef typename Icont::insert_commit_data insert_commit_data;
+
+ // insert/erase
+ std::pair<iterator,bool> insert_unique_check
+ (const key_type& key, insert_commit_data &data)
+ {
+ std::pair<iiterator, bool> ret =
+ this->icont().insert_unique_check(key, KeyNodeCompare(value_comp()), data);
+ return std::pair<iterator, bool>(iterator(ret.first), ret.second);
+ }
+
+ std::pair<iterator,bool> insert_unique_check
+ (const_iterator hint, const key_type& key, insert_commit_data &data)
+ {
+ std::pair<iiterator, bool> ret =
+ this->icont().insert_unique_check(hint.get(), key, KeyNodeCompare(value_comp()), data);
+ return std::pair<iterator, bool>(iterator(ret.first), ret.second);
+ }
+
+ iterator insert_unique_commit(const value_type& v, insert_commit_data &data)
+ {
+ NodePtr tmp = AllocHolder::create_node(v);
+ iiterator it(this->icont().insert_unique_commit(*tmp, data));
+ return iterator(it);
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class MovableConvertible>
+ iterator insert_unique_commit
+ (boost::rv<MovableConvertible> &mv, insert_commit_data &data)
+ {
+ NodePtr tmp = AllocHolder::create_node(mv);
+ iiterator it(this->icont().insert_unique_commit(*tmp, data));
+ return iterator(it);
+ }
+ #else
+ template<class MovableConvertible>
+ iterator insert_unique_commit
+ (MovableConvertible && mv, insert_commit_data &data)
+ {
+ NodePtr tmp = AllocHolder::create_node(boost::forward_constructor<MovableConvertible>(mv));
+ iiterator it(this->icont().insert_unique_commit(*tmp, data));
+ return iterator(it);
+ }
+ #endif
+
+ std::pair<iterator,bool> insert_unique(const value_type& v)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(KeyOfValue()(v), data);
+ if(!ret.second)
+ return ret;
+ return std::pair<iterator,bool>
+ (this->insert_unique_commit(v, data), true);
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class MovableConvertible>
+ std::pair<iterator,bool> insert_unique(boost::rv<MovableConvertible> &mv)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(KeyOfValue()(mv.get()), data);
+ if(!ret.second)
+ return ret;
+ return std::pair<iterator,bool>
+ (this->insert_unique_commit(mv, data), true);
+ }
+ #else
+ template<class MovableConvertible>
+ std::pair<iterator,bool> insert_unique(MovableConvertible &&mv)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(KeyOfValue()(mv), data);
+ if(!ret.second)
+ return ret;
+ return std::pair<iterator,bool>
+ (this->insert_unique_commit(boost::forward_constructor<MovableConvertible>(mv), data), true);
+ }
+ #endif
+
+ private:
+ iterator emplace_unique_impl(NodePtr p)
+ {
+ value_type &v = p->get_data();
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(KeyOfValue()(v), data);
+ if(!ret.second){
+ Destroyer(this->node_alloc())(p);
+ return ret.first;
+ }
+ return iterator(iiterator(this->icont().insert_unique_commit(*p, data)));
+ }
+
+ iterator emplace_unique_hint_impl(const_iterator hint, NodePtr p)
+ {
+ value_type &v = p->get_data();
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(hint, KeyOfValue()(v), data);
+ if(!ret.second){
+ Destroyer(this->node_alloc())(p);
+ return ret.first;
+ }
+ return iterator(iiterator(this->icont().insert_unique_commit(*p, data)));
+ }
+
+ public:
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template <class... Args>
+ iterator emplace_unique(Args&&... args)
+ { return this->emplace_unique_impl(AllocHolder::create_node(boost::forward_constructor<Args>(args)...)); }
+
+ template <class... Args>
+ iterator emplace_hint_unique(const_iterator hint, Args&&... args)
+ { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::forward_constructor<Args>(args)...)); }
+
+ template <class... Args>
+ iterator emplace_equal(Args&&... args)
+ {
+ NodePtr p(AllocHolder::create_node(boost::forward_constructor<Args>(args)...));
+ return iterator(this->icont().insert_equal(this->icont().end(), *p));
+ }
+
+ template <class... Args>
+ iterator emplace_hint_equal(const_iterator hint, Args&&... args)
+ {
+ NodePtr p(AllocHolder::create_node(boost::forward_constructor<Args>(args)...));
+ return iterator(this->icont().insert_equal(hint.get(), *p));
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace_unique()
+ { return this->emplace_unique_impl(AllocHolder::create_node()); }
+
+ iterator emplace_hint_unique(const_iterator hint)
+ { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node()); }
+
+ iterator emplace_equal()
+ {
+ NodePtr p(AllocHolder::create_node());
+ return iterator(this->icont().insert_equal(this->icont().end(), *p));
+ }
+
+ iterator emplace_hint_equal(const_iterator hint)
+ {
+ NodePtr p(AllocHolder::create_node());
+ return iterator(this->icont().insert_equal(hint.get(), *p));
+ }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return this->emplace_unique_impl \
+ (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return this->emplace_unique_hint_impl \
+ (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ return iterator(this->icont().insert_equal(this->icont().end(), *p)); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ return iterator(this->icont().insert_equal(hint.get(), *p)); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator insert_unique(const_iterator hint, const value_type& v)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(hint, KeyOfValue()(v), data);
+ if(!ret.second)
+ return ret.first;
+ return this->insert_unique_commit(v, data);
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class MovableConvertible>
+ iterator insert_unique(const_iterator hint, boost::rv<MovableConvertible> &mv)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(hint, KeyOfValue()(mv.get()), data);
+ if(!ret.second)
+ return ret.first;
+ return this->insert_unique_commit(mv, data);
+ }
+ #else
+ template<class MovableConvertible>
+ iterator insert_unique
+ (const_iterator hint, MovableConvertible &&mv)
+ {
+ insert_commit_data data;
+ std::pair<iterator,bool> ret =
+ this->insert_unique_check(hint, KeyOfValue()(mv), data);
+ if(!ret.second)
+ return ret.first;
+ return this->insert_unique_commit(boost::forward_constructor<MovableConvertible>(mv), data);
+ }
+ #endif
+
+ template <class InputIterator>
+ void insert_unique(InputIterator first, InputIterator last)
+ {
+ if(this->empty()){
+ //Insert with end hint, to achieve linear
+ //complexity if [first, last) is ordered
+ const_iterator end(this->end());
+ for( ; first != last; ++first)
+ this->insert_unique(end, *first);
+ }
+ else{
+ for( ; first != last; ++first)
+ this->insert_unique(*first);
+ }
+ }
+
+ iterator insert_equal(const value_type& v)
+ {
+ NodePtr p(AllocHolder::create_node(v));
+ return iterator(this->icont().insert_equal(this->icont().end(), *p));
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class MovableConvertible>
+ iterator insert_equal(boost::rv<MovableConvertible> &mv)
+ {
+ NodePtr p(AllocHolder::create_node(mv));
+ return iterator(this->icont().insert_equal(this->icont().end(), *p));
+ }
+ #else
+ template<class MovableConvertible>
+ iterator insert_equal(MovableConvertible &&mv)
+ {
+ NodePtr p(AllocHolder::create_node(boost::forward_constructor<MovableConvertible>(mv)));
+ return iterator(this->icont().insert_equal(this->icont().end(), *p));
+ }
+ #endif
+
+ iterator insert_equal(const_iterator hint, const value_type& v)
+ {
+ NodePtr p(AllocHolder::create_node(v));
+ return iterator(this->icont().insert_equal(hint.get(), *p));
+ }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template<class MovableConvertible>
+ iterator insert_equal(const_iterator hint, boost::rv<MovableConvertible> &mv)
+ {
+ NodePtr p(AllocHolder::create_node(mv));
+ return iterator(this->icont().insert_equal(hint.get(), *p));
+ }
+ #else
+ template<class MovableConvertible>
+ iterator insert_equal(const_iterator hint, MovableConvertible &&mv)
+ {
+ NodePtr p(AllocHolder::create_node(boost::move(mv)));
+ return iterator(this->icont().insert_equal(hint.get(), *p));
+ }
+ #endif
+
+ template <class InputIterator>
+ void insert_equal(InputIterator first, InputIterator last)
+ {
+ //Insert with end hint, to achieve linear
+ //complexity if [first, last) is ordered
+ const_iterator end(this->cend());
+ for( ; first != last; ++first)
+ this->insert_equal(end, *first);
+ }
+
+ iterator erase(const_iterator position)
+ { return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc()))); }
+
+ size_type erase(const key_type& k)
+ { return AllocHolder::erase_key(k, KeyNodeCompare(value_comp()), alloc_version()); }
+
+ iterator erase(const_iterator first, const_iterator last)
+ { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); }
+
+ void clear()
+ { AllocHolder::clear(alloc_version()); }
+
+ // set operations:
+ iterator find(const key_type& k)
+ { return iterator(this->icont().find(k, KeyNodeCompare(value_comp()))); }
+
+ const_iterator find(const key_type& k) const
+ { return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(value_comp()))); }
+
+ size_type count(const key_type& k) const
+ { return size_type(this->icont().count(k, KeyNodeCompare(value_comp()))); }
+
+ iterator lower_bound(const key_type& k)
+ { return iterator(this->icont().lower_bound(k, KeyNodeCompare(value_comp()))); }
+
+ const_iterator lower_bound(const key_type& k) const
+ { return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(value_comp()))); }
+
+ iterator upper_bound(const key_type& k)
+ { return iterator(this->icont().upper_bound(k, KeyNodeCompare(value_comp()))); }
+
+ const_iterator upper_bound(const key_type& k) const
+ { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(value_comp()))); }
+
+ std::pair<iterator,iterator> equal_range(const key_type& k)
+ {
+ std::pair<iiterator, iiterator> ret =
+ this->icont().equal_range(k, KeyNodeCompare(value_comp()));
+ return std::pair<iterator,iterator>(iterator(ret.first), iterator(ret.second));
+ }
+
+ std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const
+ {
+ std::pair<iiterator, iiterator> ret =
+ this->non_const_icont().equal_range(k, KeyNodeCompare(value_comp()));
+ return std::pair<const_iterator,const_iterator>
+ (const_iterator(ret.first), const_iterator(ret.second));
+ }
+
+ private:
+ //Iterator range version
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (InpIterator beg, InpIterator end, bool unique)
+ {
+ typedef typename std::iterator_traits<InpIterator>::iterator_category ItCat;
+ priv_create_and_insert_nodes(beg, end, unique, alloc_version(), ItCat());
+ }
+
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (InpIterator beg, InpIterator end, bool unique, allocator_v1, std::input_iterator_tag)
+ {
+ if(unique){
+ for (; beg != end; ++beg){
+ this->insert_unique(*beg);
+ }
+ }
+ else{
+ for (; beg != end; ++beg){
+ this->insert_equal(*beg);
+ }
+ }
+ }
+
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (InpIterator beg, InpIterator end, bool unique, allocator_v2, std::input_iterator_tag)
+ { //Just forward to the default one
+ priv_create_and_insert_nodes(beg, end, unique, allocator_v1(), std::input_iterator_tag());
+ }
+
+ class insertion_functor;
+ friend class insertion_functor;
+
+ class insertion_functor
+ {
+ Icont &icont_;
+
+ public:
+ insertion_functor(Icont &icont)
+ : icont_(icont)
+ {}
+
+ void operator()(Node &n)
+ { this->icont_.insert_equal(this->icont_.cend(), n); }
+ };
+
+
+ template<class FwdIterator>
+ void priv_create_and_insert_nodes
+ (FwdIterator beg, FwdIterator end, bool unique, allocator_v2, std::forward_iterator_tag)
+ {
+ if(beg != end){
+ if(unique){
+ priv_create_and_insert_nodes(beg, end, unique, allocator_v2(), std::input_iterator_tag());
+ }
+ else{
+ //Optimized allocation and construction
+ this->allocate_many_and_construct
+ (beg, std::distance(beg, end), insertion_functor(this->icont()));
+ }
+ }
+ }
+};
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline bool
+operator==(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y)
+{
+ return x.size() == y.size() &&
+ std::equal(x.begin(), x.end(), y.begin());
+}
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline bool
+operator<(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y)
+{
+ return std::lexicographical_compare(x.begin(), x.end(),
+ y.begin(), y.end());
+}
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline bool
+operator!=(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) {
+ return !(x == y);
+}
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline bool
+operator>(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) {
+ return y < x;
+}
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline bool
+operator<=(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) {
+ return !(y < x);
+}
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline bool
+operator>=(const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ const rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y) {
+ return !(x < y);
+}
+
+
+template <class Key, class Value, class KeyOfValue,
+ class KeyCompare, class A>
+inline void
+swap(rbtree<Key,Value,KeyOfValue,KeyCompare,A>& x,
+ rbtree<Key,Value,KeyOfValue,KeyCompare,A>& y)
+{
+ x.swap(y);
+}
+
+} //namespace detail {
+
+//!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<detail::rbtree<K, V, KOV, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_TREE_HPP
Added: sandbox/boost/interprocess/containers/flat_map.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/flat_map.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1506 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_HPP
+#define BOOST_INTERPROCESS_FLAT_MAP_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <utility>
+#include <functional>
+#include <memory>
+#include <stdexcept>
+#include <boost/interprocess/containers/detail/flat_tree.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/move_semantics/move.hpp>
+
+namespace boost { namespace interprocess {
+
+/// @cond
+// Forward declarations of operators == and <, needed for friend declarations.
+template <class Key, class T, class Pred, class Alloc>
+class flat_map;
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y);
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y);
+/// @endcond
+
+//! A flat_map is a kind of associative container that supports unique keys (contains at
+//! most one of each key value) and provides for fast retrieval of values of another
+//! type T based on the keys. The flat_map class supports random-access iterators.
+//!
+//! A flat_map satisfies all of the requirements of a container and of a reversible
+//! container and of an associative container. A flat_map also provides
+//! most operations described for unique keys. For a
+//! flat_map<Key,T> the key_type is Key and the value_type is std::pair<Key,T>
+//! (unlike std::map<Key, T> which value_type is std::pair<<b>const</b> Key, T>).
+//!
+//! Pred is the ordering function for Keys (e.g. <i>std::less<Key></i>).
+//!
+//! Alloc is the allocator to allocate the value_types
+//! (e.g. <i>boost::interprocess:allocator< std::pair<Key, T></i>).
+//!
+//! flat_map is similar to std::map but it's implemented like an ordered vector.
+//! This means that inserting a new element into a flat_map invalidates
+//! previous iterators and references
+//!
+//! Erasing an element of a flat_map invalidates iterators and references
+//! pointing to elements that come after (their keys are bigger) the erased element.
+template <class Key, class T, class Pred, class Alloc>
+class flat_map
+{
+ /// @cond
+ private:
+ //This is the tree that we should store if pair was movable
+ typedef detail::flat_tree<Key,
+ std::pair<Key, T>,
+ detail::select1st< std::pair<Key, T> >,
+ Pred,
+ Alloc> tree_t;
+
+ //#ifndef BOOST_HAS_RVALUE_REFS
+ //This is the real tree stored here. It's based on a movable pair
+ typedef detail::flat_tree<Key,
+ pair<Key, T>,
+ detail::select1st< pair<Key, T> >,
+ Pred,
+ typename Alloc::template
+ rebind<pair<Key, T> >::other> impl_tree_t;
+/*
+ #else
+ typedef tree_t impl_tree_t;
+ #endif
+*/
+ impl_tree_t m_flat_tree; // flat tree representing flat_map
+
+ typedef typename impl_tree_t::value_type impl_value_type;
+ typedef typename impl_tree_t::pointer impl_pointer;
+ typedef typename impl_tree_t::const_pointer impl_const_pointer;
+ typedef typename impl_tree_t::reference impl_reference;
+ typedef typename impl_tree_t::const_reference impl_const_reference;
+ typedef typename impl_tree_t::value_compare impl_value_compare;
+ typedef typename impl_tree_t::iterator impl_iterator;
+ typedef typename impl_tree_t::const_iterator impl_const_iterator;
+ typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator;
+ typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator;
+ typedef typename impl_tree_t::allocator_type impl_allocator_type;
+ #ifndef BOOST_HAS_RVALUE_REFS
+ typedef boost::rv<impl_value_type> impl_moved_value_type;
+ #endif
+
+ //#ifndef BOOST_HAS_RVALUE_REFS
+ template<class D, class S>
+ static D &force(const S &s)
+ { return *const_cast<D*>(reinterpret_cast<const D*>(&s)); }
+
+ template<class D, class S>
+ static D force_copy(S s)
+ {
+ value_type *vp = reinterpret_cast<value_type *>(&*s);
+ return D(vp);
+ }
+
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(flat_map)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef typename tree_t::value_compare value_compare;
+ typedef T mapped_type;
+ typedef typename tree_t::key_compare key_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ //! <b>Effects</b>: Constructs an empty flat_map using the specified
+ //! comparison object and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, force<impl_allocator_type>(a)) {}
+
+ //! <b>Effects</b>: Constructs an empty flat_map using the specified comparison object and
+ //! allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, force<impl_allocator_type>(a))
+ { m_flat_tree.insert_unique(first, last); }
+
+ //! <b>Effects</b>: Copy constructs a flat_map.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ flat_map(const flat_map<Key,T,Pred,Alloc>& x)
+ : m_flat_tree(x.m_flat_tree) {}
+
+ //! <b>Effects</b>: Move constructs a flat_map.
+ //! Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_map(boost::rv<flat_map<Key,T,Pred,Alloc> > &x)
+ : m_flat_tree(boost::move(x.get().m_flat_tree)) {}
+
+ #else
+ flat_map(flat_map<Key,T,Pred,Alloc> && x)
+ : m_flat_tree(boost::move(x.m_flat_tree)) {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ flat_map<Key,T,Pred,Alloc>& operator=(const flat_map<Key, T, Pred, Alloc>& x)
+ { m_flat_tree = x.m_flat_tree; return *this; }
+
+ //! <b>Effects</b>: Move constructs a flat_map.
+ //! Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_map<Key,T,Pred,Alloc>& operator=(boost::rv<flat_map<Key, T, Pred, Alloc> > &mx)
+ { m_flat_tree = boost::move(mx.get().m_flat_tree); return *this; }
+ #else
+ flat_map<Key,T,Pred,Alloc>& operator=(flat_map<Key, T, Pred, Alloc> && mx)
+ { m_flat_tree = boost::move(mx.m_flat_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return force<key_compare>(m_flat_tree.key_comp()); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return value_compare(force<key_compare>(m_flat_tree.key_comp())); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return force<allocator_type>(m_flat_tree.get_allocator()); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return force<stored_allocator_type>(m_flat_tree.get_stored_allocator()); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return force<stored_allocator_type>(m_flat_tree.get_stored_allocator()); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return force_copy<iterator>(m_flat_tree.begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return force<const_iterator>(m_flat_tree.begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return force<const_iterator>(m_flat_tree.cbegin()); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return force_copy<iterator>(m_flat_tree.end()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return force<const_iterator>(m_flat_tree.end()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return force<const_iterator>(m_flat_tree.cend()); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return force<reverse_iterator>(m_flat_tree.rbegin()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return force<const_reverse_iterator>(m_flat_tree.rbegin()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return force<const_reverse_iterator>(m_flat_tree.crbegin()); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return force<reverse_iterator>(m_flat_tree.rend()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return force<const_reverse_iterator>(m_flat_tree.rend()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return force<const_reverse_iterator>(m_flat_tree.crend()); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_flat_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_flat_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_flat_tree.max_size(); }
+
+ //! Effects: If there is no key equivalent to x in the flat_map, inserts
+ //! value_type(x, T()) into the flat_map.
+ //!
+ //! Returns: A reference to the mapped_type corresponding to x in *this.
+ //!
+ //! Complexity: Logarithmic.
+ T &operator[](const key_type& k)
+ {
+ iterator i = lower_bound(k);
+ // i->first is greater than or equivalent to k.
+ if (i == end() || key_comp()(k, (*i).first))
+ i = insert(i, value_type(k, T()));
+ return (*i).second;
+ }
+
+ //! Effects: If there is no key equivalent to x in the flat_map, inserts
+ //! value_type(move(x), T()) into the flat_map (the key is move-constructed)
+ //!
+ //! Returns: A reference to the mapped_type corresponding to x in *this.
+ //!
+ //! Complexity: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ T &operator[](boost::rv<key_type> &mk)
+ {
+ key_type &k = mk.get();
+ iterator i = lower_bound(k);
+ // i->first is greater than or equivalent to k.
+ if (i == end() || key_comp()(k, (*i).first))
+ i = insert(i, value_type(k, boost::move(T())));
+ return (*i).second;
+ }
+ #else
+ T &operator[](key_type &&mk)
+ {
+ key_type &k = mk;
+ iterator i = lower_bound(k);
+ // i->first is greater than or equivalent to k.
+ if (i == end() || key_comp()(k, (*i).first))
+ i = insert(i, value_type(boost::forward_constructor<key_type>(k), boost::move(T())));
+ return (*i).second;
+ }
+ #endif
+
+ //! Returns: A reference to the element whose key is equivalent to x.
+ //! Throws: An exception object of type out_of_range if no such element is present.
+ //! Complexity: logarithmic.
+ T& at(const key_type& k)
+ {
+ iterator i = this->find(k);
+ if(i == this->end()){
+ throw std::out_of_range("key not found");
+ }
+ return i->second;
+ }
+
+ //! Returns: A reference to the element whose key is equivalent to x.
+ //! Throws: An exception object of type out_of_range if no such element is present.
+ //! Complexity: logarithmic.
+ const T& at(const key_type& k) const
+ {
+ const_iterator i = this->find(k);
+ if(i == this->end()){
+ throw std::out_of_range("key not found");
+ }
+ return i->second;
+ }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<flat_map> &x)
+ { this->swap(x.get()); }
+ void swap(flat_map& x)
+ #else
+ void swap(flat_map &&x)
+ #endif
+ { m_flat_tree.swap(x.m_flat_tree); }
+
+ //! <b>Effects</b>: Inserts x if and only if there is no element in the container
+ //! with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ std::pair<iterator,bool> insert(const value_type& x)
+ { return force<std::pair<iterator,bool> >(
+ m_flat_tree.insert_unique(force<impl_value_type>(x))); }
+
+ //! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
+ //! only if there is no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<value_type> &x)
+ { return force<std::pair<iterator,bool> >(
+ m_flat_tree.insert_unique(force<impl_moved_value_type>(x))); }
+ #else
+ std::pair<iterator,bool> insert(value_type &&x)
+ { return force<std::pair<iterator,bool> >(
+ m_flat_tree.insert_unique(boost::move(force<impl_value_type>(x)))); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
+ //! only if there is no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<impl_value_type> &x)
+ { return force<std::pair<iterator,bool> >(
+ m_flat_tree.insert_unique(x)); }
+ #else
+ std::pair<iterator,bool> insert(impl_value_type &&x)
+ { return force<std::pair<iterator,bool> >
+ (m_flat_tree.insert_unique(boost::move(x)));
+ }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ iterator insert(const_iterator position, const value_type& x)
+ { return force_copy<iterator>(
+ m_flat_tree.insert_unique(force<impl_const_iterator>(position), force<impl_value_type>(x))); }
+
+ //! <b>Effects</b>: Inserts an element move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<value_type> &x)
+ { return force_copy<iterator>(
+ m_flat_tree.insert_unique(force<impl_const_iterator>(position), force<impl_moved_value_type>(x))); }
+ #else
+ iterator insert(const_iterator position, value_type &&x)
+ { return force_copy<iterator>(
+ m_flat_tree.insert_unique(force<impl_const_iterator>(position), boost::move(force<impl_value_type>(x)))); }
+ #endif
+
+ //! <b>Effects</b>: Inserts an element move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<impl_value_type> &x)
+ { return force_copy<iterator>(
+ m_flat_tree.insert_unique(force<impl_const_iterator>(position), x)); }
+ #else
+ iterator insert(const_iterator position, impl_value_type &&x)
+ { return force_copy<iterator>(
+ m_flat_tree.insert_unique(force<impl_const_iterator>(position), boost::move(x))); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) if and only
+ //! if there is no element with key equivalent to the key of that element.
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ //! search time plus N*size() insertion time.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_flat_tree.insert_unique(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... if and only if there is no element in the container
+ //! with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return force_copy<iterator>(m_flat_tree.emplace_unique(boost::forward_constructor<Args>(args)...)); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return force_copy<iterator>(m_flat_tree.emplace_hint_unique(force<impl_const_iterator>(hint), boost::forward_constructor<Args>(args)...)); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return force_copy<iterator>(m_flat_tree.emplace_unique()); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return force_copy<iterator>(m_flat_tree.emplace_hint_unique(force<impl_const_iterator>(hint))); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return force_copy<iterator>(m_flat_tree.emplace_unique \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return force_copy<iterator>(m_flat_tree.emplace_hint_unique \
+ (force<impl_const_iterator>(hint), \
+ BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by position.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Linear to the elements with keys bigger than position
+ //!
+ //! <b>Note</b>: Invalidates elements with keys
+ //! not less than the erased element.
+ iterator erase(const_iterator position)
+ { return force_copy<iterator>(m_flat_tree.erase(force<impl_const_iterator>(position))); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ size_type erase(const key_type& x)
+ { return m_flat_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: size()*N where N is the distance from first to last.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ iterator erase(const_iterator first, const_iterator last)
+ { return force_copy<iterator>(m_flat_tree.erase(force<impl_const_iterator>(first), force<impl_const_iterator>(last))); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_flat_tree.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()
+ { m_flat_tree.shrink_to_fit(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return force_copy<iterator>(m_flat_tree.find(x)); }
+
+ //! <b>Returns</b>: A const_iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.s
+ const_iterator find(const key_type& x) const
+ { return force<const_iterator>(m_flat_tree.find(x)); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ { return force_copy<iterator>(m_flat_tree.lower_bound(x)); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return force<const_iterator>(m_flat_tree.lower_bound(x)); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return force_copy<iterator>(m_flat_tree.upper_bound(x)); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return force<const_iterator>(m_flat_tree.upper_bound(x)); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator> equal_range(const key_type& x)
+ { return force<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
+ { return force<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); }
+
+ //! <b>Effects</b>: Number of elements for which memory has been allocated.
+ //! capacity() is always greater than or equal to size().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type capacity() const
+ { return m_flat_tree.capacity(); }
+
+ //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
+ //! effect. Otherwise, it is a request for allocation of additional memory.
+ //! If the request is successful, then capacity() is greater than or equal to
+ //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
+ //!
+ //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Note</b>: If capacity() is less than "count", iterators and references to
+ //! to values might be invalidated.
+ void reserve(size_type count)
+ { m_flat_tree.reserve(count); }
+
+ /// @cond
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator== (const flat_map<K1, T1, C1, A1>&,
+ const flat_map<K1, T1, C1, A1>&);
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator< (const flat_map<K1, T1, C1, A1>&,
+ const flat_map<K1, T1, C1, A1>&);
+ /// @endcond
+};
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y)
+ { return x.m_flat_tree == y.m_flat_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y)
+ { return x.m_flat_tree < y.m_flat_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator!=(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y)
+ { return !(x == y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y)
+ { return y < x; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<=(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y)
+ { return !(y < x); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>=(const flat_map<Key,T,Pred,Alloc>& x,
+ const flat_map<Key,T,Pred,Alloc>& y)
+ { return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(flat_map<Key,T,Pred,Alloc>& x,
+ flat_map<Key,T,Pred,Alloc>& y)
+ { x.swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(boost::rv<flat_map<Key,T,Pred,Alloc> > &x,
+ flat_map<Key,T,Pred,Alloc>& y)
+ { x.get().swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(flat_map<Key,T,Pred,Alloc>& x,
+ boost::rv<flat_map<Key,T,Pred,Alloc> > &y)
+ { x.swap(y.get()); }
+#else
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(flat_map<Key,T,Pred,Alloc>&&x,
+ flat_map<Key,T,Pred,Alloc>&&y)
+ { x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class K, class T, class C, class A>
+struct has_trivial_destructor_after_move<flat_map<K, T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+
+// Forward declaration of operators < and ==, needed for friend declaration.
+template <class Key, class T,
+ class Pred,
+ class Alloc>
+class flat_multimap;
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y);
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y);
+/// @endcond
+
+//! A flat_multimap is a kind of associative container that supports equivalent keys
+//! (possibly containing multiple copies of the same key value) and provides for
+//! fast retrieval of values of another type T based on the keys. The flat_multimap
+//! class supports random-access iterators.
+//!
+//! A flat_multimap satisfies all of the requirements of a container and of a reversible
+//! container and of an associative container. For a
+//! flat_multimap<Key,T> the key_type is Key and the value_type is std::pair<Key,T>
+//! (unlike std::multimap<Key, T> which value_type is std::pair<<b>const</b> Key, T>).
+//!
+//! Pred is the ordering function for Keys (e.g. <i>std::less<Key></i>).
+//!
+//! Alloc is the allocator to allocate the value_types
+//! (e.g. <i>boost::interprocess:allocator< std::pair<Key, T></i>).
+template <class Key, class T, class Pred, class Alloc>
+class flat_multimap
+{
+ /// @cond
+ private:
+ typedef detail::flat_tree<Key,
+ std::pair<Key, T>,
+ detail::select1st< std::pair<Key, T> >,
+ Pred,
+ Alloc> tree_t;
+ //#ifndef BOOST_HAS_RVALUE_REFS
+ //This is the real tree stored here. It's based on a movable pair
+ typedef detail::flat_tree<Key,
+ pair<Key, T>,
+ detail::select1st< pair<Key, T> >,
+ Pred,
+ typename Alloc::template
+ rebind<pair<Key, T> >::other> impl_tree_t;
+/*
+ #else
+ typedef tree_t impl_tree_t;
+ #endif
+*/
+ impl_tree_t m_flat_tree; // flat tree representing flat_map
+
+ typedef typename impl_tree_t::value_type impl_value_type;
+ typedef typename impl_tree_t::pointer impl_pointer;
+ typedef typename impl_tree_t::const_pointer impl_const_pointer;
+ typedef typename impl_tree_t::reference impl_reference;
+ typedef typename impl_tree_t::const_reference impl_const_reference;
+ typedef typename impl_tree_t::value_compare impl_value_compare;
+ typedef typename impl_tree_t::iterator impl_iterator;
+ typedef typename impl_tree_t::const_iterator impl_const_iterator;
+ typedef typename impl_tree_t::reverse_iterator impl_reverse_iterator;
+ typedef typename impl_tree_t::const_reverse_iterator impl_const_reverse_iterator;
+ typedef typename impl_tree_t::allocator_type impl_allocator_type;
+ #ifndef BOOST_HAS_RVALUE_REFS
+ typedef boost::rv<impl_value_type> impl_moved_value_type;
+ #endif
+
+ //#ifndef BOOST_HAS_RVALUE_REFS
+ template<class D, class S>
+ static D &force(const S &s)
+ { return *const_cast<D*>((reinterpret_cast<const D*>(&s))); }
+
+ template<class D, class S>
+ static D force_copy(S s)
+ {
+ value_type *vp = reinterpret_cast<value_type *>(&*s);
+ return D(vp);
+ }
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(flat_multimap)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef typename tree_t::value_compare value_compare;
+ typedef T mapped_type;
+ typedef typename tree_t::key_compare key_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison
+ //! object and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit flat_multimap(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, force<impl_allocator_type>(a)) { }
+
+ //! <b>Effects</b>: Constructs an empty flat_multimap using the specified comparison object
+ //! and allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ flat_multimap(InputIterator first, InputIterator last,
+ const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, force<impl_allocator_type>(a))
+ { m_flat_tree.insert_equal(first, last); }
+
+ //! <b>Effects</b>: Copy constructs a flat_multimap.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ flat_multimap(const flat_multimap<Key,T,Pred,Alloc>& x)
+ : m_flat_tree(x.m_flat_tree) { }
+
+ //! <b>Effects</b>: Move constructs a flat_multimap. Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_multimap(boost::rv<flat_multimap<Key,T,Pred,Alloc> > &x)
+ : m_flat_tree(boost::move(x.get().m_flat_tree)) { }
+ #else
+ flat_multimap(flat_multimap<Key,T,Pred,Alloc> && x)
+ : m_flat_tree(boost::move(x.m_flat_tree)) { }
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ flat_multimap<Key,T,Pred,Alloc>& operator=(const flat_multimap<Key,T,Pred,Alloc>& x)
+ { m_flat_tree = x.m_flat_tree; return *this; }
+
+ //! <b>Effects</b>: this->swap(x.get()).
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_multimap<Key,T,Pred,Alloc>& operator=(boost::rv<flat_multimap<Key,T,Pred,Alloc> > &mx)
+ { m_flat_tree = boost::move(mx.get().m_flat_tree); return *this; }
+ #else
+ flat_multimap<Key,T,Pred,Alloc>& operator=(flat_multimap<Key,T,Pred,Alloc> && mx)
+ { m_flat_tree = boost::move(mx.m_flat_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return force<key_compare>(m_flat_tree.key_comp()); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return value_compare(force<key_compare>(m_flat_tree.key_comp())); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return force<allocator_type>(m_flat_tree.get_allocator()); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return force<stored_allocator_type>(m_flat_tree.get_stored_allocator()); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return force<stored_allocator_type>(m_flat_tree.get_stored_allocator()); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return force_copy<iterator>(m_flat_tree.begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return force<const_iterator>(m_flat_tree.begin()); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return force_copy<iterator>(m_flat_tree.end()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return force<const_iterator>(m_flat_tree.end()); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return force<reverse_iterator>(m_flat_tree.rbegin()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return force<const_reverse_iterator>(m_flat_tree.rbegin()); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return force<reverse_iterator>(m_flat_tree.rend()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return force<const_reverse_iterator>(m_flat_tree.rend()); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_flat_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_flat_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_flat_tree.max_size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<flat_multimap> &x)
+ { this->swap(x.get()); }
+ void swap(flat_multimap& x)
+ #else
+ void swap(flat_multimap &&x)
+ #endif
+ { m_flat_tree.swap(x.m_flat_tree); }
+
+ //! <b>Effects</b>: Inserts x and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ iterator insert(const value_type& x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_value_type>(x))); }
+
+ //! <b>Effects</b>: Inserts a new value move-constructed from x and returns
+ //! the iterator pointing to the newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(boost::rv<value_type> &x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_moved_value_type>(x))); }
+ #else
+ iterator insert(value_type &&x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(boost::move(x))); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a new value move-constructed from x and returns
+ //! the iterator pointing to the newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(boost::rv<impl_value_type> &x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_moved_value_type>(x))); }
+ #else
+ iterator insert(impl_value_type &&x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(boost::move(x))); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant time if the value
+ //! is to be inserted before p) plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ iterator insert(const_iterator position, const value_type& x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_const_iterator>(position), force<impl_value_type>(x))); }
+
+ //! <b>Effects</b>: Inserts a value move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant time if the value
+ //! is to be inserted before p) plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<value_type> &x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_const_iterator>(position), force<impl_moved_value_type>(x))); }
+ #else
+ iterator insert(const_iterator position, value_type &&x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_const_iterator>(position), boost::move(x))); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a value move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant time if the value
+ //! is to be inserted before p) plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<impl_value_type> &x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_const_iterator>(position), x)); }
+ #else
+ iterator insert(const_iterator position, impl_value_type &&x)
+ { return force_copy<iterator>(m_flat_tree.insert_equal(force<impl_const_iterator>(position), boost::move(x))); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) .
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ //! search time plus N*size() insertion time.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_flat_tree.insert_equal(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return force_copy<iterator>(m_flat_tree.emplace_equal(boost::forward_constructor<Args>(args)...)); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant time if the value
+ //! is to be inserted before p) plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ {
+ return force_copy<iterator>(m_flat_tree.emplace_hint_equal
+ (force<impl_const_iterator>(hint), boost::forward_constructor<Args>(args)...));
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return force_copy<iterator>(m_flat_tree.emplace_equal()); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return force_copy<iterator>(m_flat_tree.emplace_hint_equal(force<impl_const_iterator>(hint))); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return force_copy<iterator>(m_flat_tree.emplace_equal \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return force_copy<iterator>(m_flat_tree.emplace_hint_equal \
+ (force<impl_const_iterator>(hint), \
+ BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by position.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Linear to the elements with keys bigger than position
+ //!
+ //! <b>Note</b>: Invalidates elements with keys
+ //! not less than the erased element.
+ iterator erase(const_iterator position)
+ { return force_copy<iterator>(m_flat_tree.erase(force<impl_const_iterator>(position))); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ size_type erase(const key_type& x)
+ { return m_flat_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: size()*N where N is the distance from first to last.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ iterator erase(const_iterator first, const_iterator last)
+ { return force_copy<iterator>(m_flat_tree.erase(force<impl_const_iterator>(first), force<impl_const_iterator>(last))); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_flat_tree.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()
+ { m_flat_tree.shrink_to_fit(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return force_copy<iterator>(m_flat_tree.find(x)); }
+
+ //! <b>Returns</b>: An const_iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ const_iterator find(const key_type& x) const
+ { return force<const_iterator>(m_flat_tree.find(x)); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_flat_tree.count(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ {return force_copy<iterator>(m_flat_tree.lower_bound(x)); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key
+ //! not less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return force<const_iterator>(m_flat_tree.lower_bound(x)); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ {return force_copy<iterator>(m_flat_tree.upper_bound(x)); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key
+ //! not less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return force<const_iterator>(m_flat_tree.upper_bound(x)); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator> equal_range(const key_type& x)
+ { return force_copy<std::pair<iterator,iterator> >(m_flat_tree.equal_range(x)); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator,const_iterator>
+ equal_range(const key_type& x) const
+ { return force_copy<std::pair<const_iterator,const_iterator> >(m_flat_tree.equal_range(x)); }
+
+ //! <b>Effects</b>: Number of elements for which memory has been allocated.
+ //! capacity() is always greater than or equal to size().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type capacity() const
+ { return m_flat_tree.capacity(); }
+
+ //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
+ //! effect. Otherwise, it is a request for allocation of additional memory.
+ //! If the request is successful, then capacity() is greater than or equal to
+ //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
+ //!
+ //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Note</b>: If capacity() is less than "count", iterators and references to
+ //! to values might be invalidated.
+ void reserve(size_type count)
+ { m_flat_tree.reserve(count); }
+
+ /// @cond
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator== (const flat_multimap<K1, T1, C1, A1>& x,
+ const flat_multimap<K1, T1, C1, A1>& y);
+
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator< (const flat_multimap<K1, T1, C1, A1>& x,
+ const flat_multimap<K1, T1, C1, A1>& y);
+ /// @endcond
+};
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y)
+ { return x.m_flat_tree == y.m_flat_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y)
+ { return x.m_flat_tree < y.m_flat_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator!=(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y)
+ { return !(x == y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y)
+ { return y < x; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<=(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y)
+ { return !(y < x); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>=(const flat_multimap<Key,T,Pred,Alloc>& x,
+ const flat_multimap<Key,T,Pred,Alloc>& y)
+ { return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(flat_multimap<Key,T,Pred,Alloc>& x,
+ flat_multimap<Key,T,Pred,Alloc>& y)
+ { x.swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(boost::rv<flat_multimap<Key,T,Pred,Alloc> > &x,
+ flat_multimap<Key,T,Pred,Alloc>& y)
+ { x.get().swap(y); }
+
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(flat_multimap<Key,T,Pred,Alloc>& x,
+ boost::rv<flat_multimap<Key,T,Pred,Alloc> > &y)
+ { x.swap(y.get()); }
+#else
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(flat_multimap<Key,T,Pred,Alloc>&&x,
+ flat_multimap<Key,T,Pred,Alloc>&&y)
+ { x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class K, class T, class C, class A>
+struct has_trivial_destructor_after_move<flat_multimap<K, T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+/// @endcond
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_FLAT_MAP_HPP */
Added: sandbox/boost/interprocess/containers/flat_set.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/flat_set.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1234 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_SET_HPP
+#define BOOST_INTERPROCESS_FLAT_SET_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <utility>
+#include <functional>
+#include <memory>
+#include <boost/interprocess/containers/detail/flat_tree.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/move_semantics/move.hpp>
+
+
+namespace boost { namespace interprocess {
+
+/// @cond
+// Forward declarations of operators < and ==, needed for friend declaration.
+
+template <class T, class Pred, class Alloc>
+class flat_set;
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y);
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y);
+/// @endcond
+
+//! flat_set is a Sorted Associative Container that stores objects of type Key.
+//! flat_set is a Simple Associative Container, meaning that its value type,
+//! as well as its key type, is Key. It is also a Unique Associative Container,
+//! meaning that no two elements are the same.
+//!
+//! flat_set is similar to std::set but it's implemented like an ordered vector.
+//! This means that inserting a new element into a flat_set invalidates
+//! previous iterators and references
+//!
+//! Erasing an element of a flat_set invalidates iterators and references
+//! pointing to elements that come after (their keys are bigger) the erased element.
+template <class T, class Pred, class Alloc>
+class flat_set
+{
+ /// @cond
+ private:
+ typedef detail::flat_tree<T, T, detail::identity<T>, Pred, Alloc> tree_t;
+ tree_t m_flat_tree; // flat tree representing flat_set
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(flat_set)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef typename tree_t::key_compare key_compare;
+ typedef typename tree_t::value_compare value_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ //! <b>Effects</b>: Constructs an empty flat_map using the specified
+ //! comparison object and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit flat_set(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, a)
+ {}
+
+ //! <b>Effects</b>: Constructs an empty map using the specified comparison object and
+ //! allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ flat_set(InputIterator first, InputIterator last,
+ const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, a)
+ { m_flat_tree.insert_unique(first, last); }
+
+ //! <b>Effects</b>: Copy constructs a map.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ flat_set(const flat_set<T,Pred,Alloc>& x)
+ : m_flat_tree(x.m_flat_tree) {}
+
+ //! <b>Effects</b>: Move constructs a map. Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_set(boost::rv<flat_set<T,Pred,Alloc> > &mx)
+ : m_flat_tree(boost::move(mx.get().m_flat_tree)) {}
+ #else
+ flat_set(flat_set<T,Pred,Alloc> && mx)
+ : m_flat_tree(boost::move(mx.m_flat_tree)) {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ flat_set<T,Pred,Alloc>& operator=(const flat_set<T, Pred, Alloc>& x)
+ { m_flat_tree = x.m_flat_tree; return *this; }
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_set<T,Pred,Alloc>& operator=(boost::rv<flat_set<T, Pred, Alloc> > &mx)
+ { m_flat_tree = boost::move(mx.get().m_flat_tree); return *this; }
+
+ #else
+ flat_set<T,Pred,Alloc>& operator=(flat_set<T, Pred, Alloc> &&mx)
+ { m_flat_tree = boost::move(mx.m_flat_tree); return *this; }
+
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return m_flat_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return m_flat_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return m_flat_tree.get_allocator(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return m_flat_tree.get_stored_allocator(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return m_flat_tree.get_stored_allocator(); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return m_flat_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return m_flat_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return m_flat_tree.cbegin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return m_flat_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return m_flat_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return m_flat_tree.cend(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return m_flat_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return m_flat_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return m_flat_tree.crbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return m_flat_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return m_flat_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return m_flat_tree.crend(); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_flat_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_flat_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_flat_tree.max_size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<flat_set> &x)
+ { this->swap(x.get()); }
+ void swap(flat_set& x)
+ #else
+ void swap(flat_set &&x)
+ #endif
+ { m_flat_tree.swap(x.m_flat_tree); }
+
+ //! <b>Effects</b>: Inserts x if and only if there is no element in the container
+ //! with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ std::pair<iterator,bool> insert(const value_type& x)
+ { return m_flat_tree.insert_unique(x); }
+
+ //! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
+ //! only if there is no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<value_type> &x)
+ { return m_flat_tree.insert_unique(x); }
+ #else
+ std::pair<iterator,bool> insert(value_type && x)
+ { return m_flat_tree.insert_unique(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ iterator insert(const_iterator position, const value_type& x)
+ { return m_flat_tree.insert_unique(position, x); }
+
+ //! <b>Effects</b>: Inserts an element move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<value_type> &x)
+ { return m_flat_tree.insert_unique(position, x); }
+ #else
+ iterator insert(const_iterator position, value_type && x)
+ { return m_flat_tree.insert_unique(position, boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) if and only
+ //! if there is no element with key equivalent to the key of that element.
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ //! search time plus N*size() insertion time.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_flat_tree.insert_unique(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... if and only if there is no element in the container
+ //! with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return m_flat_tree.emplace_unique(boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return m_flat_tree.emplace_hint_unique(hint, boost::forward_constructor<Args>(args)...); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return m_flat_tree.emplace_unique(); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return m_flat_tree.emplace_hint_unique(hint); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_flat_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_flat_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by position.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Linear to the elements with keys bigger than position
+ //!
+ //! <b>Note</b>: Invalidates elements with keys
+ //! not less than the erased element.
+ iterator erase(const_iterator position)
+ { return m_flat_tree.erase(position); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ size_type erase(const key_type& x)
+ { return m_flat_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: size()*N where N is the distance from first to last.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ iterator erase(const_iterator first, const_iterator last)
+ { return m_flat_tree.erase(first, last); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_flat_tree.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()
+ { m_flat_tree.shrink_to_fit(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return m_flat_tree.find(x); }
+
+ //! <b>Returns</b>: A const_iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.s
+ const_iterator find(const key_type& x) const
+ { return m_flat_tree.find(x); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ { return m_flat_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return m_flat_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return m_flat_tree.upper_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return m_flat_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& x) const
+ { return m_flat_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator>
+ equal_range(const key_type& x)
+ { return m_flat_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Number of elements for which memory has been allocated.
+ //! capacity() is always greater than or equal to size().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type capacity() const
+ { return m_flat_tree.capacity(); }
+
+ //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
+ //! effect. Otherwise, it is a request for allocation of additional memory.
+ //! If the request is successful, then capacity() is greater than or equal to
+ //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
+ //!
+ //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Note</b>: If capacity() is less than "count", iterators and references to
+ //! to values might be invalidated.
+ void reserve(size_type count)
+ { m_flat_tree.reserve(count); }
+
+ /// @cond
+ template <class K1, class C1, class A1>
+ friend bool operator== (const flat_set<K1,C1,A1>&, const flat_set<K1,C1,A1>&);
+
+ template <class K1, class C1, class A1>
+ friend bool operator< (const flat_set<K1,C1,A1>&, const flat_set<K1,C1,A1>&);
+ /// @endcond
+};
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y)
+ { return x.m_flat_tree == y.m_flat_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y)
+ { return x.m_flat_tree < y.m_flat_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator!=(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y)
+ { return !(x == y); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y)
+ { return y < x; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<=(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y)
+ { return !(y < x); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>=(const flat_set<T,Pred,Alloc>& x,
+ const flat_set<T,Pred,Alloc>& y)
+ { return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class Pred, class Alloc>
+inline void swap(flat_set<T,Pred,Alloc>& x, flat_set<T,Pred,Alloc>& y)
+ { x.swap(y); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(boost::rv<flat_set<T,Pred,Alloc> > &x, flat_set<T,Pred,Alloc>& y)
+ { x.get().swap(y); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(flat_set<T,Pred,Alloc>& x, boost::rv<flat_set<T,Pred,Alloc> > &y)
+ { x.swap(y.get()); }
+#else
+template <class T, class Pred, class Alloc>
+inline void swap(flat_set<T,Pred,Alloc>&&x, flat_set<T,Pred,Alloc>&&y)
+ { x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class C, class A>
+struct has_trivial_destructor_after_move<flat_set<T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+
+// Forward declaration of operators < and ==, needed for friend declaration.
+
+template <class T, class Pred, class Alloc>
+class flat_multiset;
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y);
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y);
+/// @endcond
+
+//! flat_multiset is a Sorted Associative Container that stores objects of type Key.
+//! flat_multiset is a Simple Associative Container, meaning that its value type,
+//! as well as its key type, is Key.
+//! flat_Multiset can store multiple copies of the same key value.
+//!
+//! flat_multiset is similar to std::multiset but it's implemented like an ordered vector.
+//! This means that inserting a new element into a flat_multiset invalidates
+//! previous iterators and references
+//!
+//! Erasing an element of a flat_multiset invalidates iterators and references
+//! pointing to elements that come after (their keys are equal or bigger) the erased element.
+template <class T, class Pred, class Alloc>
+class flat_multiset
+{
+ /// @cond
+ private:
+ typedef detail::flat_tree<T, T, detail::identity<T>, Pred, Alloc> tree_t;
+ tree_t m_flat_tree; // flat tree representing flat_multiset
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(flat_multiset)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef typename tree_t::key_compare key_compare;
+ typedef typename tree_t::value_compare value_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ // allocation/deallocation
+ explicit flat_multiset(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, a) {}
+
+ template <class InputIterator>
+ flat_multiset(InputIterator first, InputIterator last,
+ const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_flat_tree(comp, a)
+ { m_flat_tree.insert_equal(first, last); }
+
+ flat_multiset(const flat_multiset<T,Pred,Alloc>& x)
+ : m_flat_tree(x.m_flat_tree) {}
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_multiset(boost::rv<flat_multiset<T,Pred,Alloc> > &x)
+ : m_flat_tree(boost::move(x.get().m_flat_tree)) {}
+ #else
+ flat_multiset(flat_multiset<T,Pred,Alloc> && x)
+ : m_flat_tree(boost::move(x.m_flat_tree)) {}
+ #endif
+
+ flat_multiset<T,Pred,Alloc>& operator=(const flat_multiset<T,Pred,Alloc>& x)
+ { m_flat_tree = x.m_flat_tree; return *this; }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ flat_multiset<T,Pred,Alloc>& operator=(boost::rv<flat_multiset<T,Pred,Alloc> > &mx)
+ { m_flat_tree = boost::move(mx.get().m_flat_tree); return *this; }
+ #else
+ flat_multiset<T,Pred,Alloc>& operator=(flat_multiset<T,Pred,Alloc> && mx)
+ { m_flat_tree = boost::move(mx.m_flat_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return m_flat_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return m_flat_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return m_flat_tree.get_allocator(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return m_flat_tree.get_stored_allocator(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return m_flat_tree.get_stored_allocator(); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return m_flat_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return m_flat_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return m_flat_tree.cbegin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return m_flat_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return m_flat_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return m_flat_tree.cend(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return m_flat_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return m_flat_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return m_flat_tree.crbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return m_flat_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return m_flat_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return m_flat_tree.crend(); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_flat_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_flat_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_flat_tree.max_size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<flat_multiset> &x)
+ { this->swap(x.get()); }
+ void swap(flat_multiset& x)
+ #else
+ void swap(flat_multiset &&x)
+ #endif
+ { m_flat_tree.swap(x.m_flat_tree); }
+
+ //! <b>Effects</b>: Inserts x and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ iterator insert(const value_type& x)
+ { return m_flat_tree.insert_equal(x); }
+
+ //! <b>Effects</b>: Inserts a new value_type move constructed from x
+ //! and returns the iterator pointing to the newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(boost::rv<value_type> &x)
+ { return m_flat_tree.insert_equal(x); }
+ #else
+ iterator insert(value_type && x)
+ { return m_flat_tree.insert_equal(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ iterator insert(const_iterator position, const value_type& x)
+ { return m_flat_tree.insert_equal(position, x); }
+
+ //! <b>Effects</b>: Inserts a new value move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<value_type> &x)
+ { return m_flat_tree.insert_equal(position, x); }
+ #else
+ iterator insert(const_iterator position, value_type && x)
+ { return m_flat_tree.insert_equal(position, boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) .
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ //! search time plus N*size() insertion time.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_flat_tree.insert_equal(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus linear insertion
+ //! to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return m_flat_tree.emplace_equal(boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time (constant if x is inserted
+ //! right before p) plus insertion linear to the elements with bigger keys than x.
+ //!
+ //! <b>Note</b>: If an element it's inserted it might invalidate elements.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return m_flat_tree.emplace_hint_equal(hint, boost::forward_constructor<Args>(args)...); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return m_flat_tree.emplace_equal(); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return m_flat_tree.emplace_hint_equal(hint); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_flat_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_flat_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by position.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Linear to the elements with keys bigger than position
+ //!
+ //! <b>Note</b>: Invalidates elements with keys
+ //! not less than the erased element.
+ iterator erase(const_iterator position)
+ { return m_flat_tree.erase(position); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ size_type erase(const key_type& x)
+ { return m_flat_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: size()*N where N is the distance from first to last.
+ //!
+ //! <b>Complexity</b>: Logarithmic search time plus erasure time
+ //! linear to the elements with bigger keys.
+ iterator erase(const_iterator first, const_iterator last)
+ { return m_flat_tree.erase(first, last); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_flat_tree.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()
+ { m_flat_tree.shrink_to_fit(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return m_flat_tree.find(x); }
+
+ //! <b>Returns</b>: A const_iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.s
+ const_iterator find(const key_type& x) const
+ { return m_flat_tree.find(x); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_flat_tree.count(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ { return m_flat_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return m_flat_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return m_flat_tree.upper_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return m_flat_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& x) const
+ { return m_flat_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator>
+ equal_range(const key_type& x)
+ { return m_flat_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Number of elements for which memory has been allocated.
+ //! capacity() is always greater than or equal to size().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type capacity() const
+ { return m_flat_tree.capacity(); }
+
+ //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
+ //! effect. Otherwise, it is a request for allocation of additional memory.
+ //! If the request is successful, then capacity() is greater than or equal to
+ //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
+ //!
+ //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Note</b>: If capacity() is less than "count", iterators and references to
+ //! to values might be invalidated.
+ void reserve(size_type count)
+ { m_flat_tree.reserve(count); }
+
+ /// @cond
+ template <class K1, class C1, class A1>
+ friend bool operator== (const flat_multiset<K1,C1,A1>&,
+ const flat_multiset<K1,C1,A1>&);
+ template <class K1, class C1, class A1>
+ friend bool operator< (const flat_multiset<K1,C1,A1>&,
+ const flat_multiset<K1,C1,A1>&);
+ /// @endcond
+};
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y)
+ { return x.m_flat_tree == y.m_flat_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y)
+ { return x.m_flat_tree < y.m_flat_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator!=(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y)
+ { return !(x == y); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y)
+ { return y < x; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<=(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y)
+ { return !(y < x); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>=(const flat_multiset<T,Pred,Alloc>& x,
+ const flat_multiset<T,Pred,Alloc>& y)
+{ return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class Pred, class Alloc>
+inline void swap(flat_multiset<T,Pred,Alloc>& x, flat_multiset<T,Pred,Alloc>& y)
+ { x.swap(y); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(boost::rv<flat_multiset<T,Pred,Alloc> > &x, flat_multiset<T,Pred,Alloc>& y)
+ { x.get().swap(y); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(flat_multiset<T,Pred,Alloc>& x, boost::rv<flat_multiset<T,Pred,Alloc> > &y)
+ { x.swap(y.get()); }
+#else
+template <class T, class Pred, class Alloc>
+inline void swap(flat_multiset<T,Pred,Alloc>&&x, flat_multiset<T,Pred,Alloc>&&y)
+ { x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class C, class A>
+struct has_trivial_destructor_after_move<flat_multiset<T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+/// @endcond
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_FLAT_SET_HPP */
Added: sandbox/boost/interprocess/containers/list.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/list.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1456 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's stl_list.h file. Modified by Ion Gaztanaga 2004
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef BOOST_INTERPROCESS_LIST_HPP_
+#define BOOST_INTERPROCESS_LIST_HPP_
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/version_type.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/algorithms.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/interprocess/containers/detail/node_alloc_holder.hpp>
+
+#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+//Preprocessor library to emulate perfect forwarding
+#include <boost/interprocess/detail/preprocessor.hpp>
+#endif
+
+#include <iterator>
+#include <utility>
+#include <memory>
+#include <functional>
+#include <algorithm>
+#include <stdexcept>
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail {
+
+template<class VoidPointer>
+struct list_hook
+{
+ typedef typename bi::make_list_base_hook
+ <bi::void_pointer<VoidPointer>, bi::link_mode<bi::normal_link> >::type type;
+};
+
+template <class T, class VoidPointer>
+struct list_node
+ : public list_hook<VoidPointer>::type
+{
+
+ #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ list_node()
+ : m_data()
+ {}
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ list_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \
+ {} \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template<class ...Args>
+ list_node(Args &&...args)
+ : m_data(boost::forward_constructor<Args>(args)...)
+ {}
+ #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ T m_data;
+};
+
+template<class A>
+struct intrusive_list_type
+{
+ typedef typename A::value_type value_type;
+ typedef typename detail::pointer_to_other
+ <typename A::pointer, void>::type void_pointer;
+ typedef typename detail::list_node
+ <value_type, void_pointer> node_type;
+ typedef typename bi::make_list
+ < node_type
+ , bi::base_hook<typename list_hook<void_pointer>::type>
+ , bi::constant_time_size<true>
+ , bi::size_type<typename A::size_type>
+ >::type container_type;
+ typedef container_type type ;
+};
+
+} //namespace detail {
+/// @endcond
+
+//! A list is a doubly linked list. That is, it is a Sequence that supports both
+//! forward and backward traversal, and (amortized) constant time insertion and
+//! removal of elements at the beginning or the end, or in the middle. Lists have
+//! the important property that insertion and splicing do not invalidate iterators
+//! to list elements, and that even removal invalidates only the iterators that point
+//! to the elements that are removed. The ordering of iterators may be changed
+//! (that is, list<T>::iterator might have a different predecessor or successor
+//! after a list operation than it did before), but the iterators themselves will
+//! not be invalidated or made to point to different elements unless that invalidation
+//! or mutation is explicit.
+template <class T, class A>
+class list
+ : protected detail::node_alloc_holder
+ <A, typename detail::intrusive_list_type<A>::type>
+{
+ /// @cond
+ typedef typename
+ detail::intrusive_list_type<A>::type Icont;
+ typedef list <T, A> ThisType;
+ typedef detail::node_alloc_holder<A, Icont> AllocHolder;
+ typedef typename AllocHolder::NodePtr NodePtr;
+ typedef typename AllocHolder::NodeAlloc NodeAlloc;
+ typedef typename AllocHolder::ValAlloc ValAlloc;
+ typedef typename AllocHolder::Node Node;
+ typedef detail::allocator_destroyer<NodeAlloc> Destroyer;
+ typedef typename AllocHolder::allocator_v1 allocator_v1;
+ typedef typename AllocHolder::allocator_v2 allocator_v2;
+ typedef typename AllocHolder::alloc_version alloc_version;
+
+ class equal_to_value
+ {
+ typedef typename AllocHolder::value_type value_type;
+ const value_type &t_;
+
+ public:
+ equal_to_value(const value_type &t)
+ : t_(t)
+ {}
+
+ bool operator()(const value_type &t)const
+ { return t_ == t; }
+ };
+
+ template<class Pred>
+ struct ValueCompareToNodeCompare
+ : Pred
+ {
+ ValueCompareToNodeCompare(Pred pred)
+ : Pred(pred)
+ {}
+
+ bool operator()(const Node &a, const Node &b) const
+ { return static_cast<const Pred&>(*this)(a.m_data, b.m_data); }
+
+ bool operator()(const Node &a) const
+ { return static_cast<const Pred&>(*this)(a.m_data); }
+ };
+ /// @endcond
+
+ public:
+ //! The type of object, T, stored in the list
+ typedef T value_type;
+ //! Pointer to T
+ typedef typename A::pointer pointer;
+ //! Const pointer to T
+ typedef typename A::const_pointer const_pointer;
+ //! Reference to T
+ typedef typename A::reference reference;
+ //! Const reference to T
+ typedef typename A::const_reference const_reference;
+ //! An unsigned integral type
+ typedef typename A::size_type size_type;
+ //! A signed integral type
+ typedef typename A::difference_type difference_type;
+ //! The allocator type
+ typedef A allocator_type;
+ //! The stored allocator type
+ typedef NodeAlloc stored_allocator_type;
+
+ /// @cond
+ private:
+ typedef difference_type list_difference_type;
+ typedef pointer list_pointer;
+ typedef const_pointer list_const_pointer;
+ typedef reference list_reference;
+ typedef const_reference list_const_reference;
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(list)
+
+ //! Const iterator used to iterate through a list.
+ class const_iterator
+ /// @cond
+ : public std::iterator<std::bidirectional_iterator_tag,
+ value_type, list_difference_type,
+ list_const_pointer, list_const_reference>
+ {
+
+ protected:
+ typename Icont::iterator m_it;
+ explicit const_iterator(typename Icont::iterator it) : m_it(it){}
+ void prot_incr() { ++m_it; }
+ void prot_decr() { --m_it; }
+
+ private:
+ typename Icont::iterator get()
+ { return this->m_it; }
+
+ public:
+ friend class list<T, A>;
+ typedef list_difference_type difference_type;
+
+ //Constructors
+ const_iterator()
+ : m_it()
+ {}
+
+ //Pointer like operators
+ const_reference operator*() const
+ { return m_it->m_data; }
+
+ const_pointer operator->() const
+ { return const_pointer(&m_it->m_data); }
+
+ //Increment / Decrement
+ const_iterator& operator++()
+ { prot_incr(); return *this; }
+
+ const_iterator operator++(int)
+ { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); }
+
+ const_iterator& operator--()
+ { prot_decr(); return *this; }
+
+ const_iterator operator--(int)
+ { typename Icont::iterator tmp = m_it; --*this; return const_iterator(tmp); }
+
+ //Comparison operators
+ bool operator== (const const_iterator& r) const
+ { return m_it == r.m_it; }
+
+ bool operator!= (const const_iterator& r) const
+ { return m_it != r.m_it; }
+ }
+ /// @endcond
+ ;
+
+ //! Iterator used to iterate through a list
+ class iterator
+ /// @cond
+ : public const_iterator
+ {
+
+ private:
+ explicit iterator(typename Icont::iterator it)
+ : const_iterator(it)
+ {}
+
+ typename Icont::iterator get()
+ { return this->m_it; }
+
+ public:
+ friend class list<T, A>;
+ typedef list_pointer pointer;
+ typedef list_reference reference;
+
+ //Constructors
+ iterator(){}
+
+ //Pointer like operators
+ reference operator*() const { return this->m_it->m_data; }
+ pointer operator->() const { return pointer(&this->m_it->m_data); }
+
+ //Increment / Decrement
+ iterator& operator++()
+ { this->prot_incr(); return *this; }
+
+ iterator operator++(int)
+ { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); }
+
+ iterator& operator--()
+ { this->prot_decr(); return *this; }
+
+ iterator operator--(int)
+ { iterator tmp = *this; --*this; return tmp; }
+ };
+ /// @endcond
+
+ //! Iterator used to iterate backwards through a list.
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ //! Const iterator used to iterate backwards through a list.
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ //! <b>Effects</b>: Constructs a list taking the allocator as parameter.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit list(const allocator_type &a = A())
+ : AllocHolder(a)
+ {}
+
+ //! <b>Effects</b>: Constructs a list that will use a copy of allocator a
+ //! and inserts n copies of value.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's default or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ list(size_type n)
+ : AllocHolder(A())
+ { this->resize(n); }
+
+ //! <b>Effects</b>: Constructs a list that will use a copy of allocator a
+ //! and inserts n copies of value.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's default or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ list(size_type n, const T& value, const A& a = A())
+ : AllocHolder(a)
+ { this->insert(this->cbegin(), n, value); }
+
+ //! <b>Effects</b>: Copy constructs a list.
+ //!
+ //! <b>Postcondition</b>: x == *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the elements x contains.
+ list(const list& x)
+ : AllocHolder(x)
+ { this->insert(this->cbegin(), x.begin(), x.end()); }
+
+ //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ list(boost::rv<list> &x)
+ : AllocHolder(boost::move((AllocHolder&)x.get()))
+ {}
+ #else
+ list(list &&x)
+ : AllocHolder(boost::move((AllocHolder&)x))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Constructs a list that will use a copy of allocator a
+ //! and inserts a copy of the range [first, last) in the list.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's constructor taking an dereferenced InIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to the range [first, last).
+ template <class InpIt>
+ list(InpIt first, InpIt last, const A &a = A())
+ : AllocHolder(a)
+ { this->insert(this->cbegin(), first, last); }
+
+ //! <b>Effects</b>: Destroys the list. All stored values are destroyed
+ //! and used memory is deallocated.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements.
+ ~list()
+ {} //AllocHolder clears the list
+
+ //! <b>Effects</b>: Returns a copy of the internal allocator.
+ //!
+ //! <b>Throws</b>: If allocator's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return allocator_type(this->node_alloc()); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return this->node_alloc(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return this->node_alloc(); }
+
+ //! <b>Effects</b>: Erases all the elements of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in the list.
+ void clear()
+ { AllocHolder::clear(alloc_version()); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return iterator(this->icont().begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return this->cbegin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return iterator(this->icont().end()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return this->cend(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return reverse_iterator(end()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return this->crbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return reverse_iterator(begin()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return this->crend(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return const_iterator(this->non_const_icont().begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return const_iterator(this->non_const_icont().end()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return const_reverse_iterator(this->cend()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return const_reverse_iterator(this->cbegin()); }
+
+ //! <b>Effects</b>: Returns true if the list contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return !this->size(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return this->icont().size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return AllocHolder::max_size(); }
+
+ //! <b>Effects</b>: Inserts a copy of t in the beginning of the list.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void push_front(const T& x)
+ { this->insert(this->cbegin(), x); }
+
+ //! <b>Effects</b>: Constructs a new element in the beginning of the list
+ //! and moves the resources of t to this new element.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void push_front(boost::rv<T> &x)
+ { this->insert(this->cbegin(), x); }
+ #else
+ void push_front(T &&x)
+ { this->insert(this->cbegin(), boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Removes the last element from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void push_back (const T& x)
+ { this->insert(this->cend(), x); }
+
+ //! <b>Effects</b>: Removes the first element from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void push_back (boost::rv<T> &x)
+ { this->insert(this->cend(), x); }
+ #else
+ void push_back (T &&x)
+ { this->insert(this->cend(), boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Removes the first element from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void pop_front()
+ { this->erase(this->cbegin()); }
+
+ //! <b>Effects</b>: Removes the last element from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void pop_back()
+ { const_iterator tmp = this->cend(); this->erase(--tmp); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference front()
+ { return *this->begin(); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a const reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference front() const
+ { return *this->begin(); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference back()
+ { return *(--this->end()); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a const reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference back() const
+ { return *(--this->end()); }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are copy constructed from x.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type new_size, const T& x)
+ {
+ const_iterator iend = this->cend();
+ size_type len = this->size();
+
+ if(len > new_size){
+ size_type to_erase = len - new_size;
+ while(to_erase--){
+ --iend;
+ }
+ this->erase(iend, this->cend());
+ }
+ else{
+ this->priv_create_and_insert_nodes(iend, new_size - len, x);
+ }
+ }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are default constructed.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type new_size)
+ {
+ const_iterator iend = this->end();
+ size_type len = this->size();
+
+ if(len > new_size){
+ size_type to_erase = len - new_size;
+ const_iterator ifirst;
+ if(to_erase < len/2u){
+ ifirst = iend;
+ while(to_erase--){
+ --ifirst;
+ }
+ }
+ else{
+ ifirst = this->begin();
+ size_type to_skip = len - to_erase;
+ while(to_skip--){
+ ++ifirst;
+ }
+ }
+ this->erase(ifirst, iend);
+ }
+ else{
+ this->priv_create_and_insert_nodes(this->cend(), new_size - len);
+ }
+ }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type()
+ //! allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<ThisType> &x)
+ { this->swap(x.get()); }
+ void swap(ThisType& x)
+ #else
+ void swap(ThisType &&x)
+ #endif
+ { AllocHolder::swap(x); }
+
+ //! <b>Effects</b>: Makes *this contain the same elements as x.
+ //!
+ //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
+ //! of each of x's elements.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in x.
+ ThisType& operator=(const ThisType& x)
+ {
+ if (this != &x) {
+ this->assign(x.begin(), x.end());
+ }
+ return *this;
+ }
+
+ //! <b>Effects</b>: Move assignment. All mx's values are transferred to *this.
+ //!
+ //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
+ //! before the function.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ ThisType& operator=(boost::rv<ThisType> &mx)
+ {
+ this->clear();
+ this->swap(mx.get());
+ return *this;
+ }
+ #else
+ ThisType& operator=(ThisType &&mx)
+ {
+ this->clear();
+ this->swap(mx);
+ return *this;
+ }
+ #endif
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts n copies of x before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ void insert(const_iterator p, size_type n, const T& x)
+ { this->priv_create_and_insert_nodes(p, n, x); }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a copy of the [first, last) range before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, T's constructor from a
+ //! dereferenced InpIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to std::distance [first, last).
+ template <class InpIt>
+ void insert(const_iterator p, InpIt first, InpIt last)
+ {
+ const bool aux_boolean = detail::is_convertible<InpIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_insert_dispatch(p, first, last, Result());
+ }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a copy of x before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or x's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ iterator insert(const_iterator p, const T& x)
+ {
+ NodePtr tmp = AllocHolder::create_node(x);
+ return iterator(this->icont().insert(p.get(), *tmp));
+ }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a new element before p with mx's resources.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator p, boost::rv<T> &x)
+ {
+ NodePtr tmp = AllocHolder::create_node(x);
+ return iterator(this->icont().insert(p.get(), *tmp));
+ }
+ #else
+ iterator insert(const_iterator p, T &&x)
+ {
+ NodePtr tmp = AllocHolder::create_node(boost::move(x));
+ return iterator(this->icont().insert(p.get(), *tmp));
+ }
+ #endif
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the end of the list.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant
+ template <class... Args>
+ void emplace_back(Args&&... args)
+ {
+ this->emplace(this->cend(), boost::forward_constructor<Args>(args)...);
+ }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the beginning of the list.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant
+ template <class... Args>
+ void emplace_front(Args&&... args)
+ {
+ this->emplace(this->cbegin(), boost::forward_constructor<Args>(args)...);
+ }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant
+ template <class... Args>
+ iterator emplace(const_iterator p, Args&&... args)
+ {
+ typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator());
+ new ((void*)detail::get_pointer(d.get())) Node(boost::forward_constructor<Args>(args)...);
+ NodePtr node = d.get();
+ d.release();
+ return iterator(this->icont().insert(p.get(), *node));
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //0 args
+ void emplace_back()
+ { this->emplace(this->cend()); }
+
+ void emplace_front()
+ { this->emplace(this->cbegin()); }
+
+ iterator emplace(const_iterator p)
+ {
+ typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator());
+ new ((void*)detail::get_pointer(d.get())) Node();
+ NodePtr node = d.get();
+ d.release();
+ return iterator(this->icont().insert(p.get(), *node));
+ }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ this->emplace(this->cend(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { this->emplace(this->cbegin(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));} \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \
+ new ((void*)detail::get_pointer(d.get())) \
+ Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ NodePtr node = d.get(); \
+ d.release(); \
+ return iterator(this->icont().insert(p.get(), *node)); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Erases the element at p p.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ iterator erase(const_iterator p)
+ { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); }
+
+ //! <b>Requires</b>: first and last must be valid iterator to elements in *this.
+ //!
+ //! <b>Effects</b>: Erases the elements pointed by [first, last).
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the distance between first and last.
+ iterator erase(const_iterator first, const_iterator last)
+ { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); }
+
+ //! <b>Effects</b>: Assigns the n copies of val to *this.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ void assign(size_type n, const T& val)
+ { this->priv_fill_assign(n, val); }
+
+ //! <b>Effects</b>: Assigns the the range [first, last) to *this.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's constructor from dereferencing InpIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ template <class InpIt>
+ void assign(InpIt first, InpIt last)
+ {
+ const bool aux_boolean = detail::is_convertible<InpIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_assign_dispatch(first, last, Result());
+ }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by the list. x != *this
+ //!
+ //! <b>Effects</b>: Transfers all the elements of list x to this list, before the
+ //! the element pointed by p. No destructors or copy constructors are called.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of
+ //! this list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(iterator p, boost::rv<ThisType> &x)
+ { this->splice(p, x.get()); }
+ void splice(iterator p, ThisType& x)
+ #else
+ void splice(iterator p, ThisType&& x)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice(p.get(), x.icont());
+ }
+ else{
+ throw std::runtime_error("list::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by this list. i must point to an element contained in list x.
+ //!
+ //! <b>Effects</b>: Transfers the value pointed by i, from list x to this list,
+ //! before the the element pointed by p. No destructors or copy constructors are called.
+ //! If p == i or p == ++i, this function is a null operation.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(const_iterator p, boost::rv<ThisType> &x, const_iterator i)
+ { this->splice(p, x.get(), i); }
+ void splice(const_iterator p, ThisType &x, const_iterator i)
+ #else
+ void splice(const_iterator p, ThisType &&x, const_iterator i)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice(p.get(), x.icont(), i.get());
+ }
+ else{
+ throw std::runtime_error("list::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by this list. first and last must point to elements contained in list x.
+ //!
+ //! <b>Effects</b>: Transfers the range pointed by first and last from list x to this list,
+ //! before the the element pointed by p. No destructors or copy constructors are called.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements transferred.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(const_iterator p, boost::rv<ThisType> &x, const_iterator first, const_iterator last)
+ { this->splice(p, x.get(), first, last); }
+ void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last)
+ #else
+ void splice(const_iterator p, ThisType &&x, const_iterator first, const_iterator last)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice(p.get(), x.icont(), first.get(), last.get());
+ }
+ else{
+ throw std::runtime_error("list::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by this list. first and last must point to elements contained in list x.
+ //! n == std::distance(first, last)
+ //!
+ //! <b>Effects</b>: Transfers the range pointed by first and last from list x to this list,
+ //! before the the element pointed by p. No destructors or copy constructors are called.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(const_iterator p, boost::rv<ThisType> &x, const_iterator first, const_iterator last, size_type n)
+ { this->splice(p, x.get(), first, last, n); }
+ void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n)
+ #else
+ void splice(const_iterator p, ThisType &&x, const_iterator first, const_iterator last, size_type n)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n);
+ }
+ else{
+ throw std::runtime_error("list::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Effects</b>: Reverses the order of elements in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: This function is linear time.
+ //!
+ //! <b>Note</b>: Iterators and references are not invalidated
+ void reverse()
+ { this->icont().reverse(); }
+
+ //! <b>Effects</b>: Removes all the elements that compare equal to value.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ void remove(const T& value)
+ { remove_if(equal_to_value(value)); }
+
+ //! <b>Effects</b>: Removes all the elements for which a specified
+ //! predicate is satisfied.
+ //!
+ //! <b>Throws</b>: If pred throws.
+ //!
+ //! <b>Complexity</b>: Linear time. It performs exactly size() calls to the predicate.
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ template <class Pred>
+ void remove_if(Pred pred)
+ {
+ typedef ValueCompareToNodeCompare<Pred> Predicate;
+ this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc()));
+ }
+
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent
+ //! elements that are equal from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear time (size()-1 comparisons calls to pred()).
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ void unique()
+ { this->unique(value_equal()); }
+
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent
+ //! elements that satisfy some binary predicate from the list.
+ //!
+ //! <b>Throws</b>: If pred throws.
+ //!
+ //! <b>Complexity</b>: Linear time (size()-1 comparisons equality comparisons).
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ template <class BinaryPredicate>
+ void unique(BinaryPredicate binary_pred)
+ {
+ typedef ValueCompareToNodeCompare<BinaryPredicate> Predicate;
+ this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc()));
+ }
+
+ //! <b>Requires</b>: The lists x and *this must be distinct.
+ //!
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them
+ //! in order into *this according to std::less<value_type>. The merge is stable;
+ //! that is, if an element from *this is equivalent to one from x, then the element
+ //! from *this will precede the one from x.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: This function is linear time: it performs at most
+ //! size() + x.size() - 1 comparisons.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void merge(boost::rv<list<T, A> > &x)
+ { this->merge(x.get()); }
+ void merge(list<T, A>& x)
+ #else
+ void merge(list<T, A>&& x)
+ #endif
+ { this->merge(x, value_less()); }
+
+ //! <b>Requires</b>: p must be a comparison function that induces a strict weak
+ //! ordering and both *this and x must be sorted according to that ordering
+ //! The lists x and *this must be distinct.
+ //!
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them
+ //! in order into *this. The merge is stable; that is, if an element from *this is
+ //! equivalent to one from x, then the element from *this will precede the one from x.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: This function is linear time: it performs at most
+ //! size() + x.size() - 1 comparisons.
+ //!
+ //! <b>Note</b>: Iterators and references to *this are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template <class StrictWeakOrdering>
+ void merge(boost::rv<list<T, A> > &x, StrictWeakOrdering comp)
+ { this->merge(x.get(), comp); }
+ template <class StrictWeakOrdering>
+ void merge(list<T, A>& x, StrictWeakOrdering comp)
+ #else
+ template <class StrictWeakOrdering>
+ void merge(list<T, A>&& x, StrictWeakOrdering comp)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().merge(x.icont(),
+ ValueCompareToNodeCompare<StrictWeakOrdering>(comp));
+ }
+ else{
+ throw std::runtime_error("list::merge called with unequal allocators");
+ }
+ }
+
+ //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
+ //! The sort is stable, that is, the relative order of equivalent elements is preserved.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Notes</b>: Iterators and references are not invalidated.
+ //!
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N
+ //! is the list's size.
+ void sort()
+ { this->sort(value_less()); }
+
+ //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
+ //! The sort is stable, that is, the relative order of equivalent elements is preserved.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Notes</b>: Iterators and references are not invalidated.
+ //!
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N
+ //! is the list's size.
+ template <class StrictWeakOrdering>
+ void sort(StrictWeakOrdering comp)
+ {
+ // nothing if the list has length 0 or 1.
+ if (this->size() < 2)
+ return;
+ this->icont().sort(ValueCompareToNodeCompare<StrictWeakOrdering>(comp));
+ }
+
+ /// @cond
+ private:
+
+ //Iterator range version
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator pos, InpIterator beg, InpIterator end)
+ {
+ typedef typename std::iterator_traits<InpIterator>::iterator_category ItCat;
+ priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat());
+ }
+
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator pos, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag)
+ {
+ for (; beg != end; ++beg){
+ this->icont().insert(pos.get(), *this->create_node_from_it(beg));
+ }
+ }
+
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator pos, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag)
+ { //Just forward to the default one
+ priv_create_and_insert_nodes(pos, beg, end, allocator_v1(), std::input_iterator_tag());
+ }
+
+ class insertion_functor;
+ friend class insertion_functor;
+
+ class insertion_functor
+ {
+ Icont &icont_;
+ typename Icont::const_iterator pos_;
+
+ public:
+ insertion_functor(Icont &icont, typename Icont::const_iterator pos)
+ : icont_(icont), pos_(pos)
+ {}
+
+ void operator()(Node &n)
+ { this->icont_.insert(pos_, n); }
+ };
+
+
+ template<class FwdIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator pos, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag)
+ {
+ if(beg != end){
+ //Optimized allocation and construction
+ this->allocate_many_and_construct
+ (beg, std::distance(beg, end), insertion_functor(this->icont(), pos.get()));
+ }
+ }
+
+ //Default constructed version
+ void priv_create_and_insert_nodes(const_iterator pos, size_type n)
+ {
+ typedef default_construct_iterator<value_type, difference_type> default_iterator;
+ this->priv_create_and_insert_nodes(pos, default_iterator(n), default_iterator());
+ }
+
+ //Copy constructed version
+ void priv_create_and_insert_nodes(const_iterator pos, size_type n, const T& x)
+ {
+ typedef constant_iterator<value_type, difference_type> cvalue_iterator;
+ this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator());
+ }
+
+ //Dispatch to detect iterator range or integer overloads
+ template <class InputIter>
+ void priv_insert_dispatch(const_iterator p,
+ InputIter first, InputIter last,
+ detail::false_)
+ { this->priv_create_and_insert_nodes(p, first, last); }
+
+ template<class Integer>
+ void priv_insert_dispatch(const_iterator p, Integer n, Integer x, detail::true_)
+ { this->insert(p, (size_type)n, x); }
+
+ void priv_fill_assign(size_type n, const T& val)
+ {
+ iterator i = this->begin(), iend = this->end();
+
+ for ( ; i != iend && n > 0; ++i, --n)
+ *i = val;
+ if (n > 0){
+ this->priv_create_and_insert_nodes(this->cend(), n, val);
+ }
+ else{
+ this->erase(i, cend());
+ }
+ }
+
+ template <class Integer>
+ void priv_assign_dispatch(Integer n, Integer val, detail::true_)
+ { this->priv_fill_assign((size_type) n, (T) val); }
+
+ template <class InputIter>
+ void priv_assign_dispatch(InputIter first2, InputIter last2, detail::false_)
+ {
+ iterator first1 = this->begin();
+ iterator last1 = this->end();
+ for ( ; first1 != last1 && first2 != last2; ++first1, ++first2)
+ *first1 = *first2;
+ if (first2 == last2)
+ this->erase(first1, last1);
+ else{
+ this->priv_create_and_insert_nodes(last1, first2, last2);
+ }
+ }
+
+ //Functors for member algorithm defaults
+ struct value_less
+ {
+ bool operator()(const value_type &a, const value_type &b) const
+ { return a < b; }
+ };
+
+ struct value_equal
+ {
+ bool operator()(const value_type &a, const value_type &b) const
+ { return a == b; }
+ };
+ /// @endcond
+
+};
+
+template <class T, class A>
+inline bool operator==(const list<T,A>& x, const list<T,A>& y)
+{
+ if(x.size() != y.size()){
+ return false;
+ }
+ typedef typename list<T,A>::const_iterator const_iterator;
+ const_iterator end1 = x.end();
+
+ const_iterator i1 = x.begin();
+ const_iterator i2 = y.begin();
+ while (i1 != end1 && *i1 == *i2) {
+ ++i1;
+ ++i2;
+ }
+ return i1 == end1;
+}
+
+template <class T, class A>
+inline bool operator<(const list<T,A>& x,
+ const list<T,A>& y)
+{
+ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+}
+
+template <class T, class A>
+inline bool operator!=(const list<T,A>& x, const list<T,A>& y)
+{
+ return !(x == y);
+}
+
+template <class T, class A>
+inline bool operator>(const list<T,A>& x, const list<T,A>& y)
+{
+ return y < x;
+}
+
+template <class T, class A>
+inline bool operator<=(const list<T,A>& x, const list<T,A>& y)
+{
+ return !(y < x);
+}
+
+template <class T, class A>
+inline bool operator>=(const list<T,A>& x, const list<T,A>& y)
+{
+ return !(x < y);
+}
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class A>
+inline void swap(list<T, A>& x, list<T, A>& y)
+{
+ x.swap(y);
+}
+
+template <class T, class A>
+inline void swap(boost::rv<list<T, A> >& x, list<T, A> y)
+{
+ x.get().swap(y);
+}
+
+template <class T, class A>
+inline void swap(list<T, A>& x, boost::rv<list<T, A> > &y)
+{
+ x.swap(y.get());
+}
+#else
+template <class T, class A>
+inline void swap(list<T, A> &&x, list<T, A> &&y)
+{
+ x.swap(y);
+}
+
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class A>
+struct has_trivial_destructor_after_move<list<T, A> >
+{
+ enum { value = has_trivial_destructor<A>::value };
+};
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_LIST_HPP_
Added: sandbox/boost/interprocess/containers/map.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/map.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1368 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gaztanaga.
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef BOOST_INTERPROCESS_MAP_HPP
+#define BOOST_INTERPROCESS_MAP_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <utility>
+#include <functional>
+#include <memory>
+#include <stdexcept>
+#include <boost/interprocess/containers/detail/tree.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/move_semantics/move.hpp>
+
+namespace boost { namespace interprocess {
+
+/// @cond
+// Forward declarations of operators == and <, needed for friend declarations.
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y);
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y);
+/// @endcond
+
+//! A map is a kind of associative container that supports unique keys (contains at
+//! most one of each key value) and provides for fast retrieval of values of another
+//! type T based on the keys. The map class supports bidirectional iterators.
+//!
+//! A map satisfies all of the requirements of a container and of a reversible
+//! container and of an associative container. For a
+//! map<Key,T> the key_type is Key and the value_type is std::pair<const Key,T>.
+//!
+//! Pred is the ordering function for Keys (e.g. <i>std::less<Key></i>).
+//!
+//! Alloc is the allocator to allocate the value_types
+//! (e.g. <i>boost::interprocess:allocator< std::pair<const Key, T></i>).
+template <class Key, class T, class Pred, class Alloc>
+class map
+{
+ /// @cond
+ private:
+ typedef detail::rbtree<Key,
+ std::pair<const Key, T>,
+ detail::select1st< std::pair<const Key, T> >,
+ Pred,
+ Alloc> tree_t;
+ tree_t m_tree; // red-black tree representing map
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(map)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef T mapped_type;
+ typedef Pred key_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ /// @cond
+ class value_compare_impl
+ : public Pred,
+ public std::binary_function<value_type, value_type, bool>
+ {
+ friend class map<Key,T,Pred,Alloc>;
+ protected :
+ value_compare_impl(const Pred &c) : Pred(c) {}
+ public:
+ bool operator()(const value_type& x, const value_type& y) const {
+ return Pred::operator()(x.first, y.first);
+ }
+ };
+ /// @endcond
+ typedef value_compare_impl value_compare;
+
+ //! <b>Effects</b>: Constructs an empty map using the specified comparison object
+ //! and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit map(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(comp, a)
+ {}
+
+ //! <b>Effects</b>: Constructs an empty map using the specified comparison object and
+ //! allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ map(InputIterator first, InputIterator last, const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(first, last, comp, a, true)
+ {}
+
+ //! <b>Effects</b>: Copy constructs a map.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ map(const map<Key,T,Pred,Alloc>& x)
+ : m_tree(x.m_tree)
+ {}
+
+ //! <b>Effects</b>: Move constructs a map. Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ map(boost::rv<map<Key,T,Pred,Alloc> > &x)
+ : m_tree(boost::move(x.get().m_tree))
+ {}
+ #else
+ map(map<Key,T,Pred,Alloc> &&x)
+ : m_tree(boost::move(x.m_tree))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ map<Key,T,Pred,Alloc>& operator=(const map<Key, T, Pred, Alloc>& x)
+ { m_tree = x.m_tree; return *this; }
+
+ //! <b>Effects</b>: this->swap(x.get()).
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ map<Key,T,Pred,Alloc>& operator=(boost::rv<map<Key,T,Pred,Alloc> > &x)
+ { m_tree = boost::move(x.get().m_tree); return *this; }
+ #else
+ map<Key,T,Pred,Alloc>& operator=(map<Key,T,Pred,Alloc> &&x)
+ { m_tree = boost::move(x.m_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return m_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return value_compare(m_tree.key_comp()); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return m_tree.get_allocator(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return m_tree.get_stored_allocator(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return m_tree.get_stored_allocator(); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_tree.max_size(); }
+
+ //! Effects: If there is no key equivalent to x in the map, inserts
+ //! value_type(x, T()) into the map.
+ //!
+ //! Returns: A reference to the mapped_type corresponding to x in *this.
+ //!
+ //! Complexity: Logarithmic.
+ T& operator[](const key_type& k)
+ {
+ //we can optimize this
+ iterator i = lower_bound(k);
+ // i->first is greater than or equivalent to k.
+ if (i == end() || key_comp()(k, (*i).first)){
+ detail::value_init<T> v;
+ value_type val(k, boost::move(v.m_t));
+ i = insert(i, boost::move(val));
+ }
+ return (*i).second;
+ }
+
+ //! Effects: If there is no key equivalent to x in the map, inserts
+ //! value_type(boost::move(x), T()) into the map (the key is move-constructed)
+ //!
+ //! Returns: A reference to the mapped_type corresponding to x in *this.
+ //!
+ //! Complexity: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ T& operator[](boost::rv<key_type> &mk)
+ {
+ key_type &k = mk.get();
+ //we can optimize this
+ iterator i = lower_bound(k);
+ // i->first is greater than or equivalent to k.
+ if (i == end() || key_comp()(k, (*i).first)){
+ value_type val(k, boost::move(T()));
+ i = insert(i, boost::move(val));
+ }
+ return (*i).second;
+ }
+ #else
+ T& operator[](key_type &&mk)
+ {
+ key_type &k = mk;
+ //we can optimize this
+ iterator i = lower_bound(k);
+ // i->first is greater than or equivalent to k.
+ if (i == end() || key_comp()(k, (*i).first)){
+ value_type val(boost::move(k), boost::move(T()));
+ i = insert(i, boost::move(val));
+ }
+ return (*i).second;
+ }
+ #endif
+
+ //! Returns: A reference to the element whose key is equivalent to x.
+ //! Throws: An exception object of type out_of_range if no such element is present.
+ //! Complexity: logarithmic.
+ T& at(const key_type& k)
+ {
+ iterator i = this->find(k);
+ if(i == this->end()){
+ throw std::out_of_range("key not found");
+ }
+ return i->second;
+ }
+
+ //! Returns: A reference to the element whose key is equivalent to x.
+ //! Throws: An exception object of type out_of_range if no such element is present.
+ //! Complexity: logarithmic.
+ const T& at(const key_type& k) const
+ {
+ const_iterator i = this->find(k);
+ if(i == this->end()){
+ throw std::out_of_range("key not found");
+ }
+ return i->second;
+ }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<map> &x)
+ { this->swap(x.get()); }
+ void swap(map& x)
+ #else
+ void swap(map &&x)
+ #endif
+ { m_tree.swap(x.m_tree); }
+
+ //! <b>Effects</b>: Inserts x if and only if there is no element in the container
+ //! with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ std::pair<iterator,bool> insert(const value_type& x)
+ { return m_tree.insert_unique(x); }
+
+ //! <b>Effects</b>: Inserts a new value_type created from the pair if and only if
+ //! there is no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ std::pair<iterator,bool> insert(const std::pair<key_type, mapped_type>& x)
+ { return m_tree.insert_unique(x); }
+
+ //! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
+ //! only if there is no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<std::pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_unique(x); }
+ #else
+ std::pair<iterator,bool> insert(std::pair<key_type, mapped_type> &&x)
+ { return m_tree.insert_unique(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a new value_type move constructed from the pair if and
+ //! only if there is no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_unique(x); }
+ #else
+ std::pair<iterator,bool> insert(pair<key_type, mapped_type> &&x)
+ { return m_tree.insert_unique(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Move constructs a new value from x if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<value_type> &x)
+ { return m_tree.insert_unique(x); }
+ #else
+ std::pair<iterator,bool> insert(value_type &&x)
+ { return m_tree.insert_unique(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ iterator insert(iterator position, const value_type& x)
+ { return m_tree.insert_unique(position, x); }
+
+ //! <b>Effects</b>: Move constructs a new value from x if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(iterator position, boost::rv<std::pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_unique(position, x); }
+ #else
+ iterator insert(iterator position, std::pair<key_type, mapped_type> &&x)
+ { return m_tree.insert_unique(position, boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Move constructs a new value from x if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(iterator position, boost::rv<pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_unique(position, x); }
+ #else
+ iterator insert(iterator position, pair<key_type, mapped_type> &&x)
+ { return m_tree.insert_unique(position, boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator insert(iterator position, const std::pair<key_type, mapped_type>& x)
+ { return m_tree.insert_unique(position, x); }
+
+ //! <b>Effects</b>: Inserts an element move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(iterator position, boost::rv<value_type> &x)
+ { return m_tree.insert_unique(position, x); }
+ #else
+ iterator insert(iterator position, value_type &&x)
+ { return m_tree.insert_unique(position, boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) if and only
+ //! if there is no element with key equivalent to the key of that element.
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_tree.insert_unique(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container if and only if there is
+ //! no element in the container with an equivalent key.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return m_tree.emplace_unique(boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container if and only if there is
+ //! no element in the container with an equivalent key.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return m_tree.emplace_hint_unique(hint, boost::forward_constructor<Args>(args)...); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return m_tree.emplace_unique(); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return m_tree.emplace_hint_unique(hint); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));}\
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by position.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Amortized constant time
+ iterator erase(const_iterator position)
+ { return m_tree.erase(position); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: log(size()) + count(k)
+ size_type erase(const key_type& x)
+ { return m_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: log(size())+N where N is the distance from first to last.
+ iterator erase(const_iterator first, const_iterator last)
+ { return m_tree.erase(first, last); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_tree.clear(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: A const_iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ const_iterator find(const key_type& x) const
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_tree.find(x) == m_tree.end() ? 0 : 1; }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator> equal_range(const key_type& x)
+ { return m_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
+ { return m_tree.equal_range(x); }
+
+ /// @cond
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator== (const map<K1, T1, C1, A1>&,
+ const map<K1, T1, C1, A1>&);
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator< (const map<K1, T1, C1, A1>&,
+ const map<K1, T1, C1, A1>&);
+ /// @endcond
+};
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y)
+ { return x.m_tree == y.m_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y)
+ { return x.m_tree < y.m_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator!=(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y)
+ { return !(x == y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y)
+ { return y < x; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<=(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y)
+ { return !(y < x); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>=(const map<Key,T,Pred,Alloc>& x,
+ const map<Key,T,Pred,Alloc>& y)
+ { return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(map<Key,T,Pred,Alloc>& x, map<Key,T,Pred,Alloc>& y)
+ { x.swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(boost::rv<map<Key,T,Pred,Alloc> > &x, map<Key,T,Pred,Alloc>& y)
+ { x.get().swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(map<Key,T,Pred,Alloc>& x, boost::rv<map<Key,T,Pred,Alloc> > &y)
+ { x.swap(y.get()); }
+#else
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(map<Key,T,Pred,Alloc>&&x, map<Key,T,Pred,Alloc>&&y)
+ { x.swap(y); }
+#endif
+
+
+/// @cond
+
+// Forward declaration of operators < and ==, needed for friend declaration.
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y);
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y);
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class K, class T, class C, class A>
+struct has_trivial_destructor_after_move<map<K, T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+/// @endcond
+
+//! A multimap is a kind of associative container that supports equivalent keys
+//! (possibly containing multiple copies of the same key value) and provides for
+//! fast retrieval of values of another type T based on the keys. The multimap class
+//! supports bidirectional iterators.
+//!
+//! A multimap satisfies all of the requirements of a container and of a reversible
+//! container and of an associative container. For a
+//! map<Key,T> the key_type is Key and the value_type is std::pair<const Key,T>.
+//!
+//! Pred is the ordering function for Keys (e.g. <i>std::less<Key></i>).
+//!
+//! Alloc is the allocator to allocate the value_types
+//!(e.g. <i>boost::interprocess:allocator< std::pair<<b>const</b> Key, T></i>).
+template <class Key, class T, class Pred, class Alloc>
+class multimap
+{
+ /// @cond
+ private:
+ typedef detail::rbtree<Key,
+ std::pair<const Key, T>,
+ detail::select1st< std::pair<const Key, T> >,
+ Pred,
+ Alloc> tree_t;
+ tree_t m_tree; // red-black tree representing map
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(multimap)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef T mapped_type;
+ typedef Pred key_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ /// @cond
+ class value_compare_impl
+ : public Pred,
+ public std::binary_function<value_type, value_type, bool>
+ {
+ friend class multimap<Key,T,Pred,Alloc>;
+ protected :
+ value_compare_impl(const Pred &c) : Pred(c) {}
+ public:
+ bool operator()(const value_type& x, const value_type& y) const {
+ return Pred::operator()(x.first, y.first);
+ }
+ };
+ /// @endcond
+ typedef value_compare_impl value_compare;
+
+ //! <b>Effects</b>: Constructs an empty multimap using the specified comparison
+ //! object and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit multimap(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(comp, a)
+ {}
+
+ //! <b>Effects</b>: Constructs an empty multimap using the specified comparison object
+ //! and allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ multimap(InputIterator first, InputIterator last,
+ const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(first, last, comp, a, false)
+ {}
+
+ //! <b>Effects</b>: Copy constructs a multimap.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ multimap(const multimap<Key,T,Pred,Alloc>& x)
+ : m_tree(x.m_tree)
+ {}
+
+ //! <b>Effects</b>: Move constructs a multimap. Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ multimap(boost::rv<multimap<Key,T,Pred,Alloc> > &x)
+ : m_tree(boost::move(x.get().m_tree))
+ {}
+ #else
+ multimap(multimap<Key,T,Pred,Alloc> && x)
+ : m_tree(boost::move(x.m_tree))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ multimap<Key,T,Pred,Alloc>&
+ operator=(const multimap<Key,T,Pred,Alloc>& x)
+ { m_tree = x.m_tree; return *this; }
+
+ //! <b>Effects</b>: this->swap(x.get()).
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ multimap<Key,T,Pred,Alloc>& operator=(boost::rv<multimap<Key,T,Pred,Alloc> > &x)
+ { m_tree = boost::move(x.get().m_tree); return *this; }
+ #else
+ multimap<Key,T,Pred,Alloc>& operator=(multimap<Key,T,Pred,Alloc> && x)
+ { m_tree = boost::move(x.m_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return m_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return value_compare(m_tree.key_comp()); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return m_tree.get_allocator(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return m_tree.get_stored_allocator(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return m_tree.get_stored_allocator(); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_tree.max_size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<multimap> &x)
+ { this->swap(x.get()); }
+ void swap(multimap& x)
+ #else
+ void swap(multimap &&x)
+ #endif
+ { m_tree.swap(x.m_tree); }
+
+ //! <b>Effects</b>: Inserts x and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator insert(const value_type& x)
+ { return m_tree.insert_equal(x); }
+
+ //! <b>Effects</b>: Inserts a new value constructed from x and returns
+ //! the iterator pointing to the newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator insert(const std::pair<key_type, mapped_type>& x)
+ { return m_tree.insert_equal(x); }
+
+ //! <b>Effects</b>: Inserts a new value move-constructed from x and returns
+ //! the iterator pointing to the newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(boost::rv<std::pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_equal(x); }
+ #else
+ iterator insert(std::pair<key_type, mapped_type> && x)
+ { return m_tree.insert_equal(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a new value move-constructed from x and returns
+ //! the iterator pointing to the newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(boost::rv<pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_equal(x); }
+ #else
+ iterator insert(pair<key_type, mapped_type> && x)
+ { return m_tree.insert_equal(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ iterator insert(iterator position, const value_type& x)
+ { return m_tree.insert_equal(position, x); }
+
+ //! <b>Effects</b>: Inserts a new value constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ iterator insert(iterator position, const std::pair<key_type, mapped_type>& x)
+ { return m_tree.insert_equal(position, x); }
+
+ //! <b>Effects</b>: Inserts a new value move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(iterator position, boost::rv<std::pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_equal(position, x); }
+ #else
+ iterator insert(iterator position, std::pair<key_type, mapped_type> && x)
+ { return m_tree.insert_equal(position, boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a new value move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(iterator position, boost::rv<pair<key_type, mapped_type> > &x)
+ { return m_tree.insert_equal(position, x); }
+ #else
+ iterator insert(iterator position, pair<key_type, mapped_type> && x)
+ { return m_tree.insert_equal(position, boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) .
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_tree.insert_equal(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return m_tree.emplace_equal(boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return m_tree.emplace_hint_equal(hint, boost::forward_constructor<Args>(args)...); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return m_tree.emplace_equal(); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return m_tree.emplace_hint_equal(hint); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by position.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Amortized constant time
+ iterator erase(const_iterator position)
+ { return m_tree.erase(position); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: log(size()) + count(k)
+ size_type erase(const key_type& x)
+ { return m_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: log(size())+N where N is the distance from first to last.
+ iterator erase(const_iterator first, const_iterator last)
+ { return m_tree.erase(first, last); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_tree.clear(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ const_iterator find(const key_type& x) const
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_tree.count(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ {return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator> equal_range(const key_type& x)
+ { return m_tree.equal_range(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator,const_iterator>
+ equal_range(const key_type& x) const
+ { return m_tree.equal_range(x); }
+
+ /// @cond
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator== (const multimap<K1, T1, C1, A1>& x,
+ const multimap<K1, T1, C1, A1>& y);
+
+ template <class K1, class T1, class C1, class A1>
+ friend bool operator< (const multimap<K1, T1, C1, A1>& x,
+ const multimap<K1, T1, C1, A1>& y);
+ /// @endcond
+};
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator==(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y)
+{ return x.m_tree == y.m_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y)
+{ return x.m_tree < y.m_tree; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator!=(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y)
+{ return !(x == y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y)
+{ return y < x; }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator<=(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y)
+{ return !(y < x); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline bool operator>=(const multimap<Key,T,Pred,Alloc>& x,
+ const multimap<Key,T,Pred,Alloc>& y)
+{ return !(x < y); }
+
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(multimap<Key,T,Pred,Alloc>& x, multimap<Key,T,Pred,Alloc>& y)
+{ x.swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(boost::rv<multimap<Key,T,Pred,Alloc> > &x, multimap<Key,T,Pred,Alloc>& y)
+{ x.get().swap(y); }
+
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(multimap<Key,T,Pred,Alloc>& x, boost::rv<multimap<Key,T,Pred,Alloc> > &y)
+{ x.swap(y.get()); }
+#else
+template <class Key, class T, class Pred, class Alloc>
+inline void swap(multimap<Key,T,Pred,Alloc>&&x, multimap<Key,T,Pred,Alloc>&&y)
+{ x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class K, class T, class C, class A>
+struct has_trivial_destructor_after_move<multimap<K, T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+/// @endcond
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_MAP_HPP */
+
Added: sandbox/boost/interprocess/containers/set.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/set.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1176 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's stl_set/stl_multiset files. Modified by Ion Gaztanaga 2004.
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef BOOST_INTERPROCESS_SET_HPP
+#define BOOST_INTERPROCESS_SET_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+
+#include <utility>
+#include <functional>
+#include <memory>
+
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/containers/detail/tree.hpp>
+#include <boost/move_semantics/move.hpp>
+#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+#include <boost/interprocess/detail/preprocessor.hpp>
+#endif
+
+namespace boost { namespace interprocess {
+
+/// @cond
+// Forward declarations of operators < and ==, needed for friend declaration.
+template <class T, class Pred, class Alloc>
+inline bool operator==(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y);
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y);
+/// @endcond
+
+//! A set is a kind of associative container that supports unique keys (contains at
+//! most one of each key value) and provides for fast retrieval of the keys themselves.
+//! Class set supports bidirectional iterators.
+//!
+//! A set satisfies all of the requirements of a container and of a reversible container
+//! , and of an associative container. A set also provides most operations described in
+//! for unique keys.
+template <class T, class Pred, class Alloc>
+class set
+{
+ /// @cond
+ private:
+ typedef detail::rbtree<T, T,
+ detail::identity<T>, Pred, Alloc> tree_t;
+ tree_t m_tree; // red-black tree representing set
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(set)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef Pred key_compare;
+ typedef Pred value_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ //! <b>Effects</b>: Constructs an empty set using the specified comparison object
+ //! and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit set(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(comp, a)
+ {}
+
+ //! <b>Effects</b>: Constructs an empty set using the specified comparison object and
+ //! allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ set(InputIterator first, InputIterator last, const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(first, last, comp, a, true)
+ {}
+
+ //! <b>Effects</b>: Copy constructs a set.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ set(const set<T,Pred,Alloc>& x)
+ : m_tree(x.m_tree)
+ {}
+
+ //! <b>Effects</b>: Move constructs a set. Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ set(boost::rv<set<T,Pred,Alloc> > &x)
+ : m_tree(boost::move(x.get().m_tree))
+ {}
+ #else
+ set(set<T,Pred,Alloc> &&x)
+ : m_tree(boost::move(x.m_tree))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ set<T,Pred,Alloc>& operator=(const set<T, Pred, Alloc>& x)
+ { m_tree = x.m_tree; return *this; }
+
+ //! <b>Effects</b>: this->swap(x.get()).
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ set<T,Pred,Alloc>& operator=(boost::rv<set<T, Pred, Alloc> > &x)
+ { m_tree = boost::move(x.get().m_tree); return *this; }
+ #else
+ set<T,Pred,Alloc>& operator=(set<T, Pred, Alloc> &&x)
+ { m_tree = boost::move(x.m_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return m_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return m_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return m_tree.get_allocator(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return m_tree.get_stored_allocator(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return m_tree.get_stored_allocator(); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant
+ iterator begin()
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return m_tree.cbegin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return m_tree.cend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return m_tree.crbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return m_tree.crend(); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_tree.max_size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<set> &x)
+ { this->swap(x.get()); }
+ void swap(set& x)
+ #else
+ void swap(set &&x)
+ #endif
+ { m_tree.swap(x.m_tree); }
+
+ //! <b>Effects</b>: Inserts x if and only if there is no element in the container
+ //! with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ std::pair<iterator,bool> insert(const value_type& x)
+ { return m_tree.insert_unique(x); }
+
+ //! <b>Effects</b>: Move constructs a new value from x if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //!
+ //! <b>Returns</b>: The bool component of the returned pair is true if and only
+ //! if the insertion takes place, and the iterator component of the pair
+ //! points to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ std::pair<iterator,bool> insert(boost::rv<value_type> &x)
+ { return m_tree.insert_unique(x); }
+ #else
+ std::pair<iterator,bool> insert(value_type &&x)
+ { return m_tree.insert_unique(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container if and only if there is
+ //! no element in the container with key equivalent to the key of x.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ iterator insert(const_iterator p, const value_type& x)
+ { return m_tree.insert_unique(p, x); }
+
+ //! <b>Effects</b>: Inserts an element move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator p, boost::rv<value_type> &x)
+ { return m_tree.insert_unique(p, x); }
+ #else
+ iterator insert(const_iterator p, value_type &&x)
+ { return m_tree.insert_unique(p, boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) if and only
+ //! if there is no element with key equivalent to the key of that element.
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_tree.insert_unique(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... if and only if there is
+ //! no element in the container with equivalent value.
+ //! and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return m_tree.emplace_unique(boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... if and only if there is
+ //! no element in the container with equivalent value.
+ //! p is a hint pointing to where the insert
+ //! should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return m_tree.emplace_hint_unique(hint, boost::forward_constructor<Args>(args)...); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return m_tree.emplace_unique(); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return m_tree.emplace_hint_unique(hint); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _));}\
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by p.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Amortized constant time
+ iterator erase(const_iterator p)
+ { return m_tree.erase(p); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: log(size()) + count(k)
+ size_type erase(const key_type& x)
+ { return m_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: log(size())+N where N is the distance from first to last.
+ iterator erase(const_iterator first, const_iterator last)
+ { return m_tree.erase(first, last); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_tree.clear(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: A const_iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ const_iterator find(const key_type& x) const
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_tree.find(x) == m_tree.end() ? 0 : 1; }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator>
+ equal_range(const key_type& x)
+ { return m_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& x) const
+ { return m_tree.equal_range(x); }
+
+ /// @cond
+ template <class K1, class C1, class A1>
+ friend bool operator== (const set<K1,C1,A1>&, const set<K1,C1,A1>&);
+
+ template <class K1, class C1, class A1>
+ friend bool operator< (const set<K1,C1,A1>&, const set<K1,C1,A1>&);
+ /// @endcond
+};
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y)
+{ return x.m_tree == y.m_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y)
+{ return x.m_tree < y.m_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator!=(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y)
+{ return !(x == y); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y)
+{ return y < x; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<=(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y)
+{ return !(y < x); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>=(const set<T,Pred,Alloc>& x,
+ const set<T,Pred,Alloc>& y)
+{ return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class Pred, class Alloc>
+inline void swap(set<T,Pred,Alloc>& x, set<T,Pred,Alloc>& y)
+{ x.swap(y); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(set<T,Pred,Alloc>& x, boost::rv<set<T,Pred,Alloc> >& y)
+{ x.swap(y.get()); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(boost::rv<set<T,Pred,Alloc> >& y, set<T,Pred,Alloc>& x)
+{ y.swap(x.get()); }
+
+#else
+template <class T, class Pred, class Alloc>
+inline void swap(set<T,Pred,Alloc>&&x, set<T,Pred,Alloc>&&y)
+{ x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class C, class A>
+struct has_trivial_destructor_after_move<set<T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+
+// Forward declaration of operators < and ==, needed for friend declaration.
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y);
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y);
+/// @endcond
+
+//! A multiset is a kind of associative container that supports equivalent keys
+//! (possibly contains multiple copies of the same key value) and provides for
+//! fast retrieval of the keys themselves. Class multiset supports bidirectional iterators.
+//!
+//! A multiset satisfies all of the requirements of a container and of a reversible
+//! container, and of an associative container). multiset also provides most operations
+//! described for duplicate keys.
+template <class T, class Pred, class Alloc>
+class multiset
+{
+ /// @cond
+ private:
+ typedef detail::rbtree<T, T,
+ detail::identity<T>, Pred, Alloc> tree_t;
+ tree_t m_tree; // red-black tree representing multiset
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(multiset)
+
+ // typedefs:
+ typedef typename tree_t::key_type key_type;
+ typedef typename tree_t::value_type value_type;
+ typedef typename tree_t::pointer pointer;
+ typedef typename tree_t::const_pointer const_pointer;
+ typedef typename tree_t::reference reference;
+ typedef typename tree_t::const_reference const_reference;
+ typedef Pred key_compare;
+ typedef Pred value_compare;
+ typedef typename tree_t::iterator iterator;
+ typedef typename tree_t::const_iterator const_iterator;
+ typedef typename tree_t::reverse_iterator reverse_iterator;
+ typedef typename tree_t::const_reverse_iterator const_reverse_iterator;
+ typedef typename tree_t::size_type size_type;
+ typedef typename tree_t::difference_type difference_type;
+ typedef typename tree_t::allocator_type allocator_type;
+ typedef typename tree_t::stored_allocator_type stored_allocator_type;
+
+ //! <b>Effects</b>: Constructs an empty multiset using the specified comparison
+ //! object and allocator.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit multiset(const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(comp, a)
+ {}
+
+ //! <b>Effects</b>: Constructs an empty multiset using the specified comparison object
+ //! and allocator, and inserts elements from the range [first ,last ).
+ //!
+ //! <b>Complexity</b>: Linear in N if the range [first ,last ) is already sorted using
+ //! comp and otherwise N logN, where N is last - first.
+ template <class InputIterator>
+ multiset(InputIterator first, InputIterator last,
+ const Pred& comp = Pred(),
+ const allocator_type& a = allocator_type())
+ : m_tree(first, last, comp, a, false)
+ {}
+
+ //! <b>Effects</b>: Copy constructs a multiset.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ multiset(const multiset<T,Pred,Alloc>& x)
+ : m_tree(x.m_tree)
+ {}
+
+ //! <b>Effects</b>: Move constructs a multiset. Constructs *this using x's resources.
+ //!
+ //! <b>Complexity</b>: Construct.
+ //!
+ //! <b>Postcondition</b>: x is emptied.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ multiset(boost::rv<multiset<T,Pred,Alloc> > &x)
+ : m_tree(boost::move(x.get().m_tree))
+ {}
+ #else
+ multiset(multiset<T,Pred,Alloc> &&x)
+ : m_tree(boost::move(x.m_tree))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this a copy of x.
+ //!
+ //! <b>Complexity</b>: Linear in x.size().
+ multiset<T,Pred,Alloc>& operator=(const multiset<T,Pred,Alloc>& x)
+ { m_tree = x.m_tree; return *this; }
+
+ //! <b>Effects</b>: this->swap(x.get()).
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ multiset<T,Pred,Alloc>& operator=(boost::rv<multiset<T,Pred,Alloc> > &x)
+ { m_tree = boost::move(x.get().m_tree); return *this; }
+ #else
+ multiset<T,Pred,Alloc>& operator=(multiset<T,Pred,Alloc> &&x)
+ { m_tree = boost::move(x.m_tree); return *this; }
+ #endif
+
+ //! <b>Effects</b>: Returns the comparison object out
+ //! of which a was constructed.
+ //!
+ //! <b>Complexity</b>: Constant.
+ key_compare key_comp() const
+ { return m_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns an object of value_compare constructed out
+ //! of the comparison object.
+ //!
+ //! <b>Complexity</b>: Constant.
+ value_compare value_comp() const
+ { return m_tree.key_comp(); }
+
+ //! <b>Effects</b>: Returns a copy of the Allocator that
+ //! was passed to the object's constructor.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return m_tree.get_allocator(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return m_tree.get_stored_allocator(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return m_tree.get_stored_allocator(); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return m_tree.begin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return m_tree.end(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return m_tree.rbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return m_tree.rend(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return m_tree.cbegin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return m_tree.cend(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin() const
+ { return m_tree.crbegin(); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return m_tree.crend(); }
+
+ //! <b>Effects</b>: Returns true if the container contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return m_tree.empty(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return m_tree.size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return m_tree.max_size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type() allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<multiset> &x)
+ { this->swap(x.get()); }
+ void swap(multiset& x)
+ #else
+ void swap(multiset &&x)
+ #endif
+ { m_tree.swap(x.m_tree); }
+
+ //! <b>Effects</b>: Inserts x and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator insert(const value_type& x)
+ { return m_tree.insert_equal(x); }
+
+ //! <b>Effects</b>: Inserts a copy of x in the container.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(boost::rv<value_type> &x)
+ { return m_tree.insert_equal(x); }
+ #else
+ iterator insert(value_type && x)
+ { return m_tree.insert_equal(boost::move(x)); }
+ #endif
+
+ //! <b>Effects</b>: Inserts a copy of x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ iterator insert(const_iterator p, const value_type& x)
+ { return m_tree.insert_equal(p, x); }
+
+ //! <b>Effects</b>: Inserts a value move constructed from x in the container.
+ //! p is a hint pointing to where the insert should start to search.
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator p, boost::rv<value_type> &x)
+ { return m_tree.insert_equal(p, x); }
+ #else
+ iterator insert(const_iterator p, value_type && x)
+ { return m_tree.insert_equal(p, boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: i, j are not iterators into *this.
+ //!
+ //! <b>Effects</b>: inserts each element from the range [i,j) .
+ //!
+ //! <b>Complexity</b>: N log(size()+N) (N is the distance from i to j)
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { m_tree.insert_equal(first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... and returns the iterator pointing to the
+ //! newly inserted element.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ { return m_tree.emplace_equal(boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)...
+ //!
+ //! <b>Returns</b>: An iterator pointing to the element with key equivalent
+ //! to the key of x.
+ //!
+ //! <b>Complexity</b>: Logarithmic in general, but amortized constant if t
+ //! is inserted right before p.
+ template <class... Args>
+ iterator emplace_hint(const_iterator hint, Args&&... args)
+ { return m_tree.emplace_hint_equal(hint, boost::forward_constructor<Args>(args)...); }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ iterator emplace()
+ { return m_tree.emplace_equal(); }
+
+ iterator emplace_hint(const_iterator hint)
+ { return m_tree.emplace_hint_equal(hint); }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); }\
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element pointed to by p.
+ //!
+ //! <b>Returns</b>: Returns an iterator pointing to the element immediately
+ //! following q prior to the element being erased. If no such element exists,
+ //! returns end().
+ //!
+ //! <b>Complexity</b>: Amortized constant time
+ iterator erase(const_iterator p)
+ { return m_tree.erase(p); }
+
+ //! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
+ //!
+ //! <b>Returns</b>: Returns the number of erased elements.
+ //!
+ //! <b>Complexity</b>: log(size()) + count(k)
+ size_type erase(const key_type& x)
+ { return m_tree.erase(x); }
+
+ //! <b>Effects</b>: Erases all the elements in the range [first, last).
+ //!
+ //! <b>Returns</b>: Returns last.
+ //!
+ //! <b>Complexity</b>: log(size())+N where N is the distance from first to last.
+ iterator erase(const_iterator first, const_iterator last)
+ { return m_tree.erase(first, last); }
+
+ //! <b>Effects</b>: erase(a.begin(),a.end()).
+ //!
+ //! <b>Postcondition</b>: size() == 0.
+ //!
+ //! <b>Complexity</b>: linear in size().
+ void clear()
+ { m_tree.clear(); }
+
+ //! <b>Returns</b>: An iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ iterator find(const key_type& x)
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to an element with the key
+ //! equivalent to x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic.
+ const_iterator find(const key_type& x) const
+ { return m_tree.find(x); }
+
+ //! <b>Returns</b>: The number of elements with key equivalent to x.
+ //!
+ //! <b>Complexity</b>: log(size())+count(k)
+ size_type count(const key_type& x) const
+ { return m_tree.count(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator lower_bound(const key_type& x)
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than k, or a.end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator lower_bound(const key_type& x) const
+ { return m_tree.lower_bound(x); }
+
+ //! <b>Returns</b>: An iterator pointing to the first element with key not less
+ //! than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ iterator upper_bound(const key_type& x)
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Returns</b>: A const iterator pointing to the first element with key not
+ //! less than x, or end() if such an element is not found.
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ const_iterator upper_bound(const key_type& x) const
+ { return m_tree.upper_bound(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<iterator,iterator>
+ equal_range(const key_type& x)
+ { return m_tree.equal_range(x); }
+
+ //! <b>Effects</b>: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)).
+ //!
+ //! <b>Complexity</b>: Logarithmic
+ std::pair<const_iterator, const_iterator>
+ equal_range(const key_type& x) const
+ { return m_tree.equal_range(x); }
+
+ /// @cond
+ template <class K1, class C1, class A1>
+ friend bool operator== (const multiset<K1,C1,A1>&,
+ const multiset<K1,C1,A1>&);
+ template <class K1, class C1, class A1>
+ friend bool operator< (const multiset<K1,C1,A1>&,
+ const multiset<K1,C1,A1>&);
+ /// @endcond
+};
+
+template <class T, class Pred, class Alloc>
+inline bool operator==(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y)
+{ return x.m_tree == y.m_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y)
+{ return x.m_tree < y.m_tree; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator!=(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y)
+{ return !(x == y); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y)
+{ return y < x; }
+
+template <class T, class Pred, class Alloc>
+inline bool operator<=(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y)
+{ return !(y < x); }
+
+template <class T, class Pred, class Alloc>
+inline bool operator>=(const multiset<T,Pred,Alloc>& x,
+ const multiset<T,Pred,Alloc>& y)
+{ return !(x < y); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class Pred, class Alloc>
+inline void swap(multiset<T,Pred,Alloc>& x, multiset<T,Pred,Alloc>& y)
+{ x.swap(y); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(multiset<T,Pred,Alloc>& x, boost::rv<multiset<T,Pred,Alloc> >& y)
+{ x.swap(y.get()); }
+
+template <class T, class Pred, class Alloc>
+inline void swap(boost::rv<multiset<T,Pred,Alloc> >& y, multiset<T,Pred,Alloc>& x)
+{ y.swap(x.get()); }
+#else
+template <class T, class Pred, class Alloc>
+inline void swap(multiset<T,Pred,Alloc>&&x, multiset<T,Pred,Alloc>&&y)
+{ x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class C, class A>
+struct has_trivial_destructor_after_move<multiset<T, C, A> >
+{
+ enum { value =
+ has_trivial_destructor<A>::value &&
+ has_trivial_destructor<C>::value };
+};
+/// @endcond
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_SET_HPP */
+
Added: sandbox/boost/interprocess/containers/slist.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/slist.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1621 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2004-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 comes from SGI's stl_slist.h file. Modified by Ion Gaztanaga 2004-2008
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef BOOST_INTERPROCESS_SLIST_HPP
+#define BOOST_INTERPROCESS_SLIST_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/move_semantics/move.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/containers/detail/node_alloc_holder.hpp>
+#include <boost/intrusive/slist.hpp>
+
+
+#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+//Preprocessor library to emulate perfect forwarding
+#include <boost/interprocess/detail/preprocessor.hpp>
+#endif
+
+#include <iterator>
+#include <utility>
+#include <memory>
+#include <functional>
+#include <algorithm>
+
+namespace boost{ namespace interprocess{
+
+/// @cond
+
+namespace detail {
+
+template<class VoidPointer>
+struct slist_hook
+{
+ typedef typename bi::make_slist_base_hook
+ <bi::void_pointer<VoidPointer>, bi::link_mode<bi::normal_link> >::type type;
+};
+
+template <class T, class VoidPointer>
+struct slist_node
+ : public slist_hook<VoidPointer>::type
+{
+ #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ slist_node()
+ : m_data()
+ {}
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ slist_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \
+ {} \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template<class ...Args>
+ slist_node(Args &&...args)
+ : m_data(boost::forward_constructor<Args>(args)...)
+ {}
+ #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ T m_data;
+};
+
+template<class A>
+struct intrusive_slist_type
+{
+ typedef typename A::value_type value_type;
+ typedef typename detail::pointer_to_other
+ <typename A::pointer, void>::type void_pointer;
+ typedef typename detail::slist_node
+ <value_type, void_pointer> node_type;
+
+ typedef typename bi::make_slist
+ <node_type
+ ,bi::base_hook<typename slist_hook<void_pointer>::type>
+ ,bi::constant_time_size<true>
+ ,bi::size_type<typename A::size_type>
+ >::type container_type;
+ typedef container_type type ;
+};
+
+} //namespace detail {
+
+/// @endcond
+
+//! An slist is a singly linked list: a list where each element is linked to the next
+//! element, but not to the previous element. That is, it is a Sequence that
+//! supports forward but not backward traversal, and (amortized) constant time
+//! insertion and removal of elements. Slists, like lists, have the important
+//! property that insertion and splicing do not invalidate iterators to list elements,
+//! and that even removal invalidates only the iterators that point to the elements
+//! that are removed. The ordering of iterators may be changed (that is,
+//! slist<T>::iterator might have a different predecessor or successor after a list
+//! operation than it did before), but the iterators themselves will not be invalidated
+//! or made to point to different elements unless that invalidation or mutation is explicit.
+//!
+//! The main difference between slist and list is that list's iterators are bidirectional
+//! iterators, while slist's iterators are forward iterators. This means that slist is
+//! less versatile than list; frequently, however, bidirectional iterators are
+//! unnecessary. You should usually use slist unless you actually need the extra
+//! functionality of list, because singly linked lists are smaller and faster than double
+//! linked lists.
+//!
+//! Important performance note: like every other Sequence, slist defines the member
+//! functions insert and erase. Using these member functions carelessly, however, can
+//! result in disastrously slow programs. The problem is that insert's first argument is
+//! an iterator p, and that it inserts the new element(s) before p. This means that
+//! insert must find the iterator just before p; this is a constant-time operation
+//! for list, since list has bidirectional iterators, but for slist it must find that
+//! iterator by traversing the list from the beginning up to p. In other words:
+//! insert and erase are slow operations anywhere but near the beginning of the slist.
+//!
+//! Slist provides the member functions insert_after and erase_after, which are constant
+//! time operations: you should always use insert_after and erase_after whenever
+//! possible. If you find that insert_after and erase_after aren't adequate for your
+//! needs, and that you often need to use insert and erase in the middle of the list,
+//! then you should probably use list instead of slist.
+template <class T, class A>
+class slist
+ : protected detail::node_alloc_holder
+ <A, typename detail::intrusive_slist_type<A>::type>
+{
+ /// @cond
+ typedef typename
+ detail::intrusive_slist_type<A>::type Icont;
+ typedef detail::node_alloc_holder<A, Icont> AllocHolder;
+ typedef typename AllocHolder::NodePtr NodePtr;
+ typedef slist <T, A> ThisType;
+ typedef typename AllocHolder::NodeAlloc NodeAlloc;
+ typedef typename AllocHolder::ValAlloc ValAlloc;
+ typedef typename AllocHolder::Node Node;
+ typedef detail::allocator_destroyer<NodeAlloc> Destroyer;
+ typedef typename AllocHolder::allocator_v1 allocator_v1;
+ typedef typename AllocHolder::allocator_v2 allocator_v2;
+ typedef typename AllocHolder::alloc_version alloc_version;
+
+ class equal_to_value
+ {
+ typedef typename AllocHolder::value_type value_type;
+ const value_type &t_;
+
+ public:
+ equal_to_value(const value_type &t)
+ : t_(t)
+ {}
+
+ bool operator()(const value_type &t)const
+ { return t_ == t; }
+ };
+
+ template<class Pred>
+ struct ValueCompareToNodeCompare
+ : Pred
+ {
+ ValueCompareToNodeCompare(Pred pred)
+ : Pred(pred)
+ {}
+
+ bool operator()(const Node &a, const Node &b) const
+ { return static_cast<const Pred&>(*this)(a.m_data, b.m_data); }
+
+ bool operator()(const Node &a) const
+ { return static_cast<const Pred&>(*this)(a.m_data); }
+ };
+ /// @endcond
+ public:
+ //! The type of object, T, stored in the list
+ typedef T value_type;
+ //! Pointer to T
+ typedef typename A::pointer pointer;
+ //! Const pointer to T
+ typedef typename A::const_pointer const_pointer;
+ //! Reference to T
+ typedef typename A::reference reference;
+ //! Const reference to T
+ typedef typename A::const_reference const_reference;
+ //! An unsigned integral type
+ typedef typename A::size_type size_type;
+ //! A signed integral type
+ typedef typename A::difference_type difference_type;
+ //! The allocator type
+ typedef A allocator_type;
+ //! The stored allocator type
+ typedef NodeAlloc stored_allocator_type;
+
+ /// @cond
+ private:
+ typedef difference_type list_difference_type;
+ typedef pointer list_pointer;
+ typedef const_pointer list_const_pointer;
+ typedef reference list_reference;
+ typedef const_reference list_const_reference;
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(slist)
+
+ //! Const iterator used to iterate through a list.
+ class const_iterator
+ /// @cond
+ : public std::iterator<std::forward_iterator_tag,
+ value_type, list_difference_type,
+ list_const_pointer, list_const_reference>
+ {
+
+ protected:
+ typename Icont::iterator m_it;
+ explicit const_iterator(typename Icont::iterator it) : m_it(it){}
+ void prot_incr(){ ++m_it; }
+
+ private:
+ typename Icont::iterator get()
+ { return this->m_it; }
+
+ public:
+ friend class slist<T, A>;
+ typedef list_difference_type difference_type;
+
+ //Constructors
+ const_iterator()
+ : m_it()
+ {}
+
+ //Pointer like operators
+ const_reference operator*() const
+ { return m_it->m_data; }
+
+ const_pointer operator->() const
+ { return const_pointer(&m_it->m_data); }
+
+ //Increment / Decrement
+ const_iterator& operator++()
+ { prot_incr(); return *this; }
+
+ const_iterator operator++(int)
+ { typename Icont::iterator tmp = m_it; ++*this; return const_iterator(tmp); }
+
+ //Comparison operators
+ bool operator== (const const_iterator& r) const
+ { return m_it == r.m_it; }
+
+ bool operator!= (const const_iterator& r) const
+ { return m_it != r.m_it; }
+ }
+ /// @endcond
+ ;
+
+ //! Iterator used to iterate through a list
+ class iterator
+ /// @cond
+ : public const_iterator
+ {
+
+ private:
+ explicit iterator(typename Icont::iterator it)
+ : const_iterator(it)
+ {}
+
+ typename Icont::iterator get()
+ { return this->m_it; }
+
+ public:
+ friend class slist<T, A>;
+ typedef list_pointer pointer;
+ typedef list_reference reference;
+
+ //Constructors
+ iterator(){}
+
+ //Pointer like operators
+ reference operator*() const { return this->m_it->m_data; }
+ pointer operator->() const { return pointer(&this->m_it->m_data); }
+
+ //Increment / Decrement
+ iterator& operator++()
+ { this->prot_incr(); return *this; }
+
+ iterator operator++(int)
+ { typename Icont::iterator tmp = this->m_it; ++*this; return iterator(tmp); }
+ }
+ /// @endcond
+ ;
+
+ public:
+ //! <b>Effects</b>: Constructs a list taking the allocator as parameter.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit slist(const allocator_type& a = allocator_type())
+ : AllocHolder(a)
+ {}
+
+ explicit slist(size_type n)
+ : AllocHolder(allocator_type())
+ { this->resize(n); }
+
+ //! <b>Effects</b>: Constructs a list that will use a copy of allocator a
+ //! and inserts n copies of value.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's default or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ explicit slist(size_type n, const value_type& x, const allocator_type& a = allocator_type())
+ : AllocHolder(a)
+ { this->priv_create_and_insert_nodes(this->before_begin(), n, x); }
+
+ //! <b>Effects</b>: Constructs a list that will use a copy of allocator a
+ //! and inserts a copy of the range [first, last) in the list.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's constructor taking an dereferenced InIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to the range [first, last).
+ template <class InpIt>
+ slist(InpIt first, InpIt last,
+ const allocator_type& a = allocator_type())
+ : AllocHolder(a)
+ { this->insert_after(this->before_begin(), first, last); }
+
+ //! <b>Effects</b>: Copy constructs a list.
+ //!
+ //! <b>Postcondition</b>: x == *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the elements x contains.
+ slist(const slist& x)
+ : AllocHolder(x)
+ { this->insert_after(this->before_begin(), x.begin(), x.end()); }
+
+ //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ slist(boost::rv<slist> &x)
+ : AllocHolder(boost::move((AllocHolder&)x.get()))
+ {}
+ #else
+ slist(slist &&x)
+ : AllocHolder(boost::move((AllocHolder&)x))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Makes *this contain the same elements as x.
+ //!
+ //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
+ //! of each of x's elements.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in x.
+ slist& operator= (const slist& x)
+ {
+ if (&x != this){
+ this->assign(x.begin(), x.end());
+ }
+ return *this;
+ }
+
+ //! <b>Effects</b>: Makes *this contain the same elements as x.
+ //!
+ //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
+ //! of each of x's elements.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in x.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ slist& operator= (boost::rv<slist> &mx)
+ {
+ if (&mx.get() != this){
+ this->clear();
+ this->swap(mx.get());
+ }
+ return *this;
+ }
+ #else
+ slist& operator= (slist && mx)
+ {
+ if (&mx != this){
+ this->clear();
+ this->swap(mx);
+ }
+ return *this;
+ }
+ #endif
+
+ //! <b>Effects</b>: Destroys the list. All stored values are destroyed
+ //! and used memory is deallocated.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements.
+ ~slist()
+ {} //AllocHolder clears the slist
+
+ //! <b>Effects</b>: Returns a copy of the internal allocator.
+ //!
+ //! <b>Throws</b>: If allocator's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return allocator_type(this->node_alloc()); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return this->node_alloc(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return this->node_alloc(); }
+
+ public:
+
+ //! <b>Effects</b>: Assigns the n copies of val to *this.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ void assign(size_type n, const T& val)
+ { this->priv_fill_assign(n, val); }
+
+ //! <b>Effects</b>: Assigns the range [first, last) to *this.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's constructor from dereferencing InpIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ template <class InpIt>
+ void assign(InpIt first, InpIt last)
+ {
+ const bool aux_boolean = detail::is_convertible<InpIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_assign_dispatch(first, last, Result());
+ }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return iterator(this->icont().begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return this->cbegin(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return iterator(this->icont().end()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return this->cend(); }
+
+ //! <b>Effects</b>: Returns a non-dereferenceable iterator that,
+ //! when incremented, yields begin(). This iterator may be used
+ //! as the argument toinsert_after, erase_after, etc.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator before_begin()
+ { return iterator(end()); }
+
+ //! <b>Effects</b>: Returns a non-dereferenceable const_iterator
+ //! that, when incremented, yields begin(). This iterator may be used
+ //! as the argument toinsert_after, erase_after, etc.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator before_begin() const
+ { return this->cbefore_begin(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return const_iterator(this->non_const_icont().begin()); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return const_iterator(this->non_const_icont().end()); }
+
+ //! <b>Effects</b>: Returns a non-dereferenceable const_iterator
+ //! that, when incremented, yields begin(). This iterator may be used
+ //! as the argument toinsert_after, erase_after, etc.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbefore_begin() const
+ { return const_iterator(end()); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return this->icont().size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return AllocHolder::max_size(); }
+
+ //! <b>Effects</b>: Returns true if the list contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return !this->size(); }
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type()
+ //! allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements on *this and x.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<slist> &x)
+ { this->swap(x.get()); }
+ void swap(slist& x)
+ #else
+ void swap(slist &&x)
+ #endif
+ { AllocHolder::swap(x); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference front()
+ { return *this->begin(); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a const reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference front() const
+ { return *this->begin(); }
+
+ //! <b>Effects</b>: Inserts a copy of t in the beginning of the list.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void push_front(const value_type& x)
+ { this->icont().push_front(*this->create_node(x)); }
+
+ //! <b>Effects</b>: Constructs a new element in the beginning of the list
+ //! and moves the resources of t to this new element.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void push_front(boost::rv<T> &x)
+ { this->icont().push_front(*this->create_node(x)); }
+ #else
+ void push_front(T && x)
+ { this->icont().push_front(*this->create_node(boost::move(x))); }
+ #endif
+
+ //! <b>Effects</b>: Removes the first element from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void pop_front()
+ { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); }
+
+ //! <b>Returns</b>: The iterator to the element before i in the sequence.
+ //! Returns the end-iterator, if either i is the begin-iterator or the
+ //! sequence is empty.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements before i.
+ iterator previous(iterator p)
+ { return iterator(this->icont().previous(p.get())); }
+
+ //! <b>Returns</b>: The const_iterator to the element before i in the sequence.
+ //! Returns the end-const_iterator, if either i is the begin-const_iterator or
+ //! the sequence is empty.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements before i.
+ const_iterator previous(const_iterator p)
+ { return const_iterator(this->icont().previous(p.get())); }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts a copy of the value after the p pointed
+ //! by prev_p.
+ //!
+ //! <b>Returns</b>: An iterator to the inserted element.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ //!
+ //! <b>Note</b>: Does not affect the validity of iterators and references of
+ //! previous values.
+ iterator insert_after(const_iterator prev_pos, const value_type& x)
+ { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); }
+
+ //! <b>Requires</b>: prev_pos must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts a move constructed copy object from the value after the
+ //! p pointed by prev_pos.
+ //!
+ //! <b>Returns</b>: An iterator to the inserted element.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ //!
+ //! <b>Note</b>: Does not affect the validity of iterators and references of
+ //! previous values.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert_after(const_iterator prev_pos, boost::rv<value_type> &x)
+ { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); }
+ #else
+ iterator insert_after(const_iterator prev_pos, value_type && x)
+ { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(boost::move(x)))); }
+ #endif
+
+ //! <b>Requires</b>: prev_pos must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts n copies of x after prev_pos.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ //!
+ //! <b>Note</b>: Does not affect the validity of iterators and references of
+ //! previous values.
+ void insert_after(const_iterator prev_pos, size_type n, const value_type& x)
+ { this->priv_create_and_insert_nodes(prev_pos, n, x); }
+
+ //! <b>Requires</b>: prev_pos must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts the range pointed by [first, last)
+ //! after the p prev_pos.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, T's constructor from a
+ //! dereferenced InpIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements inserted.
+ //!
+ //! <b>Note</b>: Does not affect the validity of iterators and references of
+ //! previous values.
+ template <class InIter>
+ void insert_after(const_iterator prev_pos, InIter first, InIter last)
+ {
+ const bool aux_boolean = detail::is_convertible<InIter, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_insert_after_range_dispatch(prev_pos, first, last, Result());
+ }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a copy of x before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or x's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the elements before p.
+ iterator insert(const_iterator p, const value_type& x)
+ { return this->insert_after(previous(p), x); }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a new element before p with mx's resources.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: Linear to the elements before p.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator p, boost::rv<value_type> &x)
+ { return this->insert_after(previous(p), x); }
+ #else
+ iterator insert(const_iterator p, value_type && x)
+ { return this->insert_after(previous(p), boost::move(x)); }
+ #endif
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts n copies of x before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n plus linear to the elements before p.
+ void insert(const_iterator p, size_type n, const value_type& x)
+ { return this->insert_after(previous(p), n, x); }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a copy of the [first, last) range before p.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, T's constructor from a
+ //! dereferenced InpIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to std::distance [first, last) plus
+ //! linear to the elements before p.
+ template <class InIter>
+ void insert(const_iterator p, InIter first, InIter last)
+ { return this->insert_after(previous(p), first, last); }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the front of the list
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ template <class... Args>
+ void emplace_front(Args&&... args)
+ { this->emplace_after(this->cbefore_begin(), boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... before p
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the elements before p
+ template <class... Args>
+ iterator emplace(const_iterator p, Args&&... args)
+ { return this->emplace_after(this->previous(p), boost::forward_constructor<Args>(args)...); }
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... after prev
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant
+ template <class... Args>
+ iterator emplace_after(const_iterator prev, Args&&... args)
+ {
+ typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator());
+ new ((void*)detail::get_pointer(d.get())) Node(boost::forward_constructor<Args>(args)...);
+ NodePtr node = d.get();
+ d.release();
+ return iterator(this->icont().insert_after(prev.get(), *node));
+ }
+
+ #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //0 args
+ void emplace_front()
+ { this->emplace_after(this->cbefore_begin()); }
+
+ iterator emplace(const_iterator p)
+ { return this->emplace_after(this->previous(p)); }
+
+ iterator emplace_after(const_iterator prev)
+ {
+ typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator());
+ new ((void*)detail::get_pointer(d.get())) Node();
+ NodePtr node = d.get();
+ d.release();
+ return iterator(this->icont().insert_after(prev.get(), *node));
+ }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ void emplace_front(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ this->emplace \
+ (this->cbegin(), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace \
+ (const_iterator p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ return this->emplace_after \
+ (this->previous(p), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace_after \
+ (const_iterator prev, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \
+ new ((void*)detail::get_pointer(d.get())) \
+ Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ NodePtr node = d.get(); \
+ d.release(); \
+ return iterator(this->icont().insert_after(prev.get(), *node)); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Erases the element after the element pointed by prev_pos
+ //! of the list.
+ //!
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,
+ //! or end() if no such element exists.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Note</b>: Does not invalidate iterators or references to non erased elements.
+ iterator erase_after(const_iterator prev_pos)
+ {
+ return iterator(this->icont().erase_after_and_dispose(prev_pos.get(), Destroyer(this->node_alloc())));
+ }
+
+ //! <b>Effects</b>: Erases the range (before_first, last) from
+ //! the list.
+ //!
+ //! <b>Returns</b>: the first element remaining beyond the removed elements,
+ //! or end() if no such element exists.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of erased elements.
+ //!
+ //! <b>Note</b>: Does not invalidate iterators or references to non erased elements.
+ iterator erase_after(const_iterator before_first, const_iterator last)
+ {
+ return iterator(this->icont().erase_after_and_dispose(before_first.get(), last.get(), Destroyer(this->node_alloc())));
+ }
+
+ //! <b>Requires</b>: p must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Erases the element at p p.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements before p.
+ iterator erase(const_iterator p)
+ { return iterator(this->erase_after(previous(p))); }
+
+ //! <b>Requires</b>: first and last must be valid iterator to elements in *this.
+ //!
+ //! <b>Effects</b>: Erases the elements pointed by [first, last).
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the distance between first and last plus
+ //! linear to the elements before first.
+ iterator erase(const_iterator first, const_iterator last)
+ { return iterator(this->erase_after(previous(first), last)); }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are copy constructed from x.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type new_size, const T& x)
+ {
+ typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next;
+ while (++(cur_next = cur) != end_n && new_size > 0){
+ --new_size;
+ cur = cur_next;
+ }
+ if (cur_next != end_n)
+ this->erase_after(const_iterator(cur), const_iterator(end_n));
+ else
+ this->insert_after(const_iterator(cur), new_size, x);
+ }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are default constructed.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type new_size)
+ {
+ typename Icont::iterator end_n(this->icont().end()), cur(this->icont().before_begin()), cur_next;
+ size_type len = this->size();
+ size_type left = new_size;
+
+ while (++(cur_next = cur) != end_n && left > 0){
+ --left;
+ cur = cur_next;
+ }
+ if (cur_next != end_n){
+ this->erase_after(const_iterator(cur), const_iterator(end_n));
+ }
+ else{
+ this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len);
+ }
+ }
+
+ //! <b>Effects</b>: Erases all the elements of the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in the list.
+ void clear()
+ { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by the list. x != *this
+ //!
+ //! <b>Effects</b>: Transfers all the elements of list x to this list, after the
+ //! the element pointed by p. No destructors or copy constructors are called.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Linear to the elements in x.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of
+ //! this list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice_after(const_iterator prev_pos, boost::rv<slist> &x)
+ { this->splice_after(prev_pos, x.get()); }
+ void splice_after(const_iterator prev_pos, slist& x)
+ #else
+ void splice_after(const_iterator prev_pos, slist&& x)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice_after(prev_pos.get(), x.icont());
+ }
+ else{
+ throw std::runtime_error("slist::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: prev_pos must be a valid iterator of this.
+ //! i must point to an element contained in list x.
+ //!
+ //! <b>Effects</b>: Transfers the value pointed by i, from list x to this list,
+ //! after the element pointed by prev_pos.
+ //! If prev_pos == prev or prev_pos == ++prev, this function is a null operation.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice_after(const_iterator prev_pos, boost::rv<slist> &x, const_iterator prev)
+ { this->splice_after(prev_pos, x.get(), prev); }
+ void splice_after(const_iterator prev_pos, slist& x, const_iterator prev)
+ #else
+ void splice_after(const_iterator prev_pos, slist&& x, const_iterator prev)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice_after(prev_pos.get(), x.icont(), prev.get());
+ }
+ else{
+ throw std::runtime_error("slist::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: prev_pos must be a valid iterator of this.
+ //! before_first and before_last must be valid iterators of x.
+ //! prev_pos must not be contained in [before_first, before_last) range.
+ //!
+ //! <b>Effects</b>: Transfers the range [before_first + 1, before_last + 1)
+ //! from list x to this list, after the element pointed by prev_pos.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Linear to the number of transferred elements.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice_after(const_iterator prev_pos, boost::rv<slist> &x,
+ const_iterator before_first, const_iterator before_last)
+ { this->splice_after(prev_pos, x.get(), before_first, before_last); }
+ void splice_after(const_iterator prev_pos, slist& x,
+ const_iterator before_first, const_iterator before_last)
+ #else
+ void splice_after(const_iterator prev_pos, slist&& x,
+ const_iterator before_first, const_iterator before_last)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice_after
+ (prev_pos.get(), x.icont(), before_first.get(), before_last.get());
+ }
+ else{
+ throw std::runtime_error("slist::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: prev_pos must be a valid iterator of this.
+ //! before_first and before_last must be valid iterators of x.
+ //! prev_pos must not be contained in [before_first, before_last) range.
+ //! n == std::distance(before_first, before_last)
+ //!
+ //! <b>Effects</b>: Transfers the range [before_first + 1, before_last + 1)
+ //! from list x to this list, after the element pointed by prev_pos.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Constant.
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice_after(const_iterator prev_pos, boost::rv<slist> &x,
+ const_iterator before_first, const_iterator before_last,
+ size_type n)
+ { this->splice_after(prev_pos, x.get(), before_first, before_last, n); }
+ void splice_after(const_iterator prev_pos, slist& x,
+ const_iterator before_first, const_iterator before_last,
+ size_type n)
+ #else
+ void splice_after(const_iterator prev_pos, slist&& x,
+ const_iterator before_first, const_iterator before_last,
+ size_type n)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().splice_after
+ (prev_pos.get(), x.icont(), before_first.get(), before_last.get(), n);
+ }
+ else{
+ throw std::runtime_error("slist::splice called with unequal allocators");
+ }
+ }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by the list. x != *this
+ //!
+ //! <b>Effects</b>: Transfers all the elements of list x to this list, before the
+ //! the element pointed by p. No destructors or copy constructors are called.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Linear in distance(begin(), p), and linear in x.size().
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of
+ //! this list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(const_iterator p, boost::rv<ThisType> &x)
+ { this->splice(p, x.get()); }
+ void splice(const_iterator p, ThisType& x)
+ #else
+ void splice(const_iterator p, ThisType&& x)
+ #endif
+ { this->splice_after(this->previous(p), x); }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by this list. i must point to an element contained in list x.
+ //!
+ //! <b>Effects</b>: Transfers the value pointed by i, from list x to this list,
+ //! before the the element pointed by p. No destructors or copy constructors are called.
+ //! If p == i or p == ++i, this function is a null operation.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Linear in distance(begin(), p), and in distance(x.begin(), i).
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(const_iterator p, boost::rv<ThisType> &x, const_iterator i)
+ { this->splice(p, x.get(), i); }
+ void splice(const_iterator p, slist& x, const_iterator i)
+ #else
+ void splice(const_iterator p, slist&& x, const_iterator i)
+ #endif
+ { this->splice_after(previous(p), x, i); }
+
+ //! <b>Requires</b>: p must point to an element contained
+ //! by this list. first and last must point to elements contained in list x.
+ //!
+ //! <b>Effects</b>: Transfers the range pointed by first and last from list x to this list,
+ //! before the the element pointed by p. No destructors or copy constructors are called.
+ //!
+ //! <b>Throws</b>: std::runtime_error if this' allocator and x's allocator
+ //! are not equal.
+ //!
+ //! <b>Complexity</b>: Linear in distance(begin(), p), in distance(x.begin(), first),
+ //! and in distance(first, last).
+ //!
+ //! <b>Note</b>: Iterators of values obtained from list x now point to elements of this
+ //! list. Iterators of this list and all the references are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void splice(const_iterator p, boost::rv<ThisType> &x, const_iterator first, const_iterator last)
+ { this->splice(p, x.get(), first, last); }
+ void splice(const_iterator p, slist& x, const_iterator first, const_iterator last)
+ #else
+ void splice(const_iterator p, slist&& x, const_iterator first, const_iterator last)
+ #endif
+ { this->splice_after(previous(p), x, previous(first), previous(last)); }
+
+ //! <b>Effects</b>: Reverses the order of elements in the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: This function is linear time.
+ //!
+ //! <b>Note</b>: Iterators and references are not invalidated
+ void reverse()
+ { this->icont().reverse(); }
+
+ //! <b>Effects</b>: Removes all the elements that compare equal to value.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear time. It performs exactly size() comparisons for equality.
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ void remove(const T& value)
+ { remove_if(equal_to_value(value)); }
+
+ //! <b>Effects</b>: Removes all the elements for which a specified
+ //! predicate is satisfied.
+ //!
+ //! <b>Throws</b>: If pred throws.
+ //!
+ //! <b>Complexity</b>: Linear time. It performs exactly size() calls to the predicate.
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ template <class Pred>
+ void remove_if(Pred pred)
+ {
+ typedef ValueCompareToNodeCompare<Pred> Predicate;
+ this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc()));
+ }
+
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent
+ //! elements that are equal from the list.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear time (size()-1 comparisons calls to pred()).
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ void unique()
+ { this->unique(value_equal()); }
+
+ //! <b>Effects</b>: Removes adjacent duplicate elements or adjacent
+ //! elements that satisfy some binary predicate from the list.
+ //!
+ //! <b>Throws</b>: If pred throws.
+ //!
+ //! <b>Complexity</b>: Linear time (size()-1 comparisons equality comparisons).
+ //!
+ //! <b>Note</b>: The relative order of elements that are not removed is unchanged,
+ //! and iterators to elements that are not removed remain valid.
+ template <class Pred>
+ void unique(Pred pred)
+ {
+ typedef ValueCompareToNodeCompare<Pred> Predicate;
+ this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc()));
+ }
+
+ //! <b>Requires</b>: The lists x and *this must be distinct.
+ //!
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them
+ //! in order into *this according to std::less<value_type>. The merge is stable;
+ //! that is, if an element from *this is equivalent to one from x, then the element
+ //! from *this will precede the one from x.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: This function is linear time: it performs at most
+ //! size() + x.size() - 1 comparisons.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void merge(boost::rv<slist<T, A> > &x)
+ { this->merge(x.get()); }
+ void merge(slist<T, A>& x)
+ #else
+ void merge(slist<T, A>&& x)
+ #endif
+ { this->merge(x, value_less()); }
+
+ //! <b>Requires</b>: p must be a comparison function that induces a strict weak
+ //! ordering and both *this and x must be sorted according to that ordering
+ //! The lists x and *this must be distinct.
+ //!
+ //! <b>Effects</b>: This function removes all of x's elements and inserts them
+ //! in order into *this. The merge is stable; that is, if an element from *this is
+ //! equivalent to one from x, then the element from *this will precede the one from x.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: This function is linear time: it performs at most
+ //! size() + x.size() - 1 comparisons.
+ //!
+ //! <b>Note</b>: Iterators and references to *this are not invalidated.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template <class StrictWeakOrdering>
+ void merge(boost::rv<slist<T, A> > &x, StrictWeakOrdering comp)
+ { this->merge(x.get(), comp); }
+ template <class StrictWeakOrdering>
+ void merge(slist<T, A>& x, StrictWeakOrdering comp)
+ #else
+ template <class StrictWeakOrdering>
+ void merge(slist<T, A>&& x, StrictWeakOrdering comp)
+ #endif
+ {
+ if((NodeAlloc&)*this == (NodeAlloc&)x){
+ this->icont().merge(x.icont(),
+ ValueCompareToNodeCompare<StrictWeakOrdering>(comp));
+ }
+ else{
+ throw std::runtime_error("list::merge called with unequal allocators");
+ }
+ }
+
+ //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
+ //! The sort is stable, that is, the relative order of equivalent elements is preserved.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Notes</b>: Iterators and references are not invalidated.
+ //!
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N
+ //! is the list's size.
+ void sort()
+ { this->sort(value_less()); }
+
+ //! <b>Effects</b>: This function sorts the list *this according to std::less<value_type>.
+ //! The sort is stable, that is, the relative order of equivalent elements is preserved.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Notes</b>: Iterators and references are not invalidated.
+ //!
+ //! <b>Complexity</b>: The number of comparisons is approximately N log N, where N
+ //! is the list's size.
+ template <class StrictWeakOrdering>
+ void sort(StrictWeakOrdering comp)
+ {
+ // nothing if the slist has length 0 or 1.
+ if (this->size() < 2)
+ return;
+ this->icont().sort(ValueCompareToNodeCompare<StrictWeakOrdering>(comp));
+ }
+
+ /// @cond
+ private:
+
+ //Iterator range version
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator prev, InpIterator beg, InpIterator end)
+ {
+ typedef typename std::iterator_traits<InpIterator>::iterator_category ItCat;
+ priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat());
+ }
+
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator prev, InpIterator beg, InpIterator end, allocator_v1, std::input_iterator_tag)
+ {
+ for (; beg != end; ++beg){
+ this->icont().insert_after(prev.get(), *this->create_node_from_it(beg));
+ ++prev;
+ }
+ }
+
+ template<class InpIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator prev, InpIterator beg, InpIterator end, allocator_v2, std::input_iterator_tag)
+ { //Just forward to the default one
+ priv_create_and_insert_nodes(prev, beg, end, allocator_v1(), std::input_iterator_tag());
+ }
+
+ class insertion_functor;
+ friend class insertion_functor;
+
+ class insertion_functor
+ {
+ Icont &icont_;
+ typename Icont::const_iterator prev_;
+
+ public:
+ insertion_functor(Icont &icont, typename Icont::const_iterator prev)
+ : icont_(icont), prev_(prev)
+ {}
+
+ void operator()(Node &n)
+ { prev_ = this->icont_.insert_after(prev_, n); }
+ };
+
+ template<class FwdIterator>
+ void priv_create_and_insert_nodes
+ (const_iterator prev, FwdIterator beg, FwdIterator end, allocator_v2, std::forward_iterator_tag)
+ {
+ //Optimized allocation and construction
+ this->allocate_many_and_construct
+ (beg, std::distance(beg, end), insertion_functor(this->icont(), prev.get()));
+ }
+
+ //Default constructed version
+ void priv_create_and_insert_nodes(const_iterator prev, size_type n)
+ {
+ typedef default_construct_iterator<value_type, difference_type> default_iterator;
+ this->priv_create_and_insert_nodes(prev, default_iterator(n), default_iterator());
+ }
+
+ //Copy constructed version
+ void priv_create_and_insert_nodes(const_iterator prev, size_type n, const T& x)
+ {
+ typedef constant_iterator<value_type, difference_type> cvalue_iterator;
+ this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator());
+ }
+
+ //Dispatch to detect iterator range or integer overloads
+ template <class InputIter>
+ void priv_insert_dispatch(const_iterator prev,
+ InputIter first, InputIter last,
+ detail::false_)
+ { this->priv_create_and_insert_nodes(prev, first, last); }
+
+ template<class Integer>
+ void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, detail::true_)
+ { this->priv_create_and_insert_nodes(prev, n, x); }
+
+ void priv_fill_assign(size_type n, const T& val)
+ {
+ iterator end_n(this->end());
+ iterator prev(this->before_begin());
+ iterator node(this->begin());
+ for ( ; node != end_n && n > 0 ; --n){
+ *node = val;
+ prev = node;
+ ++node;
+ }
+ if (n > 0)
+ this->priv_create_and_insert_nodes(prev, n, val);
+ else
+ this->erase_after(prev, end_n);
+ }
+
+ template <class Int>
+ void priv_assign_dispatch(Int n, Int val, detail::true_)
+ { this->priv_fill_assign((size_type) n, (T)val); }
+
+ template <class InpIt>
+ void priv_assign_dispatch(InpIt first, InpIt last, detail::false_)
+ {
+ iterator end_n(this->end());
+ iterator prev(this->before_begin());
+ iterator node(this->begin());
+ while (node != end_n && first != last){
+ *node = *first;
+ prev = node;
+ ++node;
+ ++first;
+ }
+ if (first != last)
+ this->priv_create_and_insert_nodes(prev, first, last);
+ else
+ this->erase_after(prev, end_n);
+ }
+
+ template <class Int>
+ void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, detail::true_)
+ { this->priv_create_and_insert_nodes(prev_pos, n, x); }
+
+ template <class InIter>
+ void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, detail::false_)
+ { this->priv_create_and_insert_nodes(prev_pos, first, last); }
+
+ //Functors for member algorithm defaults
+ struct value_less
+ {
+ bool operator()(const value_type &a, const value_type &b) const
+ { return a < b; }
+ };
+
+ struct value_equal
+ {
+ bool operator()(const value_type &a, const value_type &b) const
+ { return a == b; }
+ };
+
+ struct value_equal_to_this
+ {
+ explicit value_equal_to_this(const value_type &ref)
+ : m_ref(ref){}
+
+ bool operator()(const value_type &val) const
+ { return m_ref == val; }
+
+ const value_type &m_ref;
+ };
+ /// @endcond
+};
+
+template <class T, class A>
+inline bool
+operator==(const slist<T,A>& x, const slist<T,A>& y)
+{
+ if(x.size() != y.size()){
+ return false;
+ }
+ typedef typename slist<T,A>::const_iterator const_iterator;
+ const_iterator end1 = x.end();
+
+ const_iterator i1 = x.begin();
+ const_iterator i2 = y.begin();
+ while (i1 != end1 && *i1 == *i2){
+ ++i1;
+ ++i2;
+ }
+ return i1 == end1;
+}
+
+template <class T, class A>
+inline bool
+operator<(const slist<T,A>& sL1, const slist<T,A>& sL2)
+{
+ return std::lexicographical_compare
+ (sL1.begin(), sL1.end(), sL2.begin(), sL2.end());
+}
+
+template <class T, class A>
+inline bool
+operator!=(const slist<T,A>& sL1, const slist<T,A>& sL2)
+ { return !(sL1 == sL2); }
+
+template <class T, class A>
+inline bool
+operator>(const slist<T,A>& sL1, const slist<T,A>& sL2)
+ { return sL2 < sL1; }
+
+template <class T, class A>
+inline bool
+operator<=(const slist<T,A>& sL1, const slist<T,A>& sL2)
+ { return !(sL2 < sL1); }
+
+template <class T, class A>
+inline bool
+operator>=(const slist<T,A>& sL1, const slist<T,A>& sL2)
+ { return !(sL1 < sL2); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class A>
+inline void swap(slist<T,A>& x, slist<T,A>& y)
+ { x.swap(y); }
+
+template <class T, class A>
+inline void swap(boost::rv<slist<T,A> > &x, slist<T,A>& y)
+ { x.get().swap(y); }
+
+template <class T, class A>
+inline void swap(slist<T,A>& x, boost::rv<slist<T,A> > &y)
+ { x.swap(y.get()); }
+#else
+template <class T, class A>
+inline void swap(slist<T,A>&&x, slist<T,A>&&y)
+ { x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class A>
+struct has_trivial_destructor_after_move<slist<T, A> >
+{
+ enum { value = has_trivial_destructor<A>::value };
+};
+/// @endcond
+
+}} //namespace boost{ namespace interprocess{
+
+// Specialization of insert_iterator so that insertions will be constant
+// time rather than linear time.
+
+///@cond
+
+//Ummm, I don't like to define things in namespace std, but
+//there is no other way
+namespace std {
+
+template <class T, class A>
+class insert_iterator<boost::interprocess::slist<T, A> >
+{
+ protected:
+ typedef boost::interprocess::slist<T, A> Container;
+ Container* container;
+ typename Container::iterator iter;
+ public:
+ typedef Container container_type;
+ typedef output_iterator_tag iterator_category;
+ typedef void value_type;
+ typedef void difference_type;
+ typedef void pointer;
+ typedef void reference;
+
+ insert_iterator(Container& x,
+ typename Container::iterator i,
+ bool is_previous = false)
+ : container(&x), iter(is_previous ? i : x.previous(i)){ }
+
+ insert_iterator<Container>&
+ operator=(const typename Container::value_type& value)
+ {
+ iter = container->insert_after(iter, value);
+ return *this;
+ }
+ insert_iterator<Container>& operator*(){ return *this; }
+ insert_iterator<Container>& operator++(){ return *this; }
+ insert_iterator<Container>& operator++(int){ return *this; }
+};
+
+} //namespace std;
+
+///@endcond
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_SLIST_HPP */
Added: sandbox/boost/interprocess/containers/stable_vector.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/stable_vector.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1179 @@
+/* Stable vector.
+ *
+ * Copyright 2008 Joaquin M Lopez Munoz.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#ifndef STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66
+#define STABLE_VECTOR_HPP_3A7EB5C0_55BF_11DD_AE16_0800200C9A66
+
+#define STABLE_VECTOR_VERSION 200
+
+#include <algorithm>
+#include <stdexcept>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/not.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/interprocess/detail/version_type.hpp>
+#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/pointer_to_other.hpp>
+#include <boost/get_pointer.hpp>
+
+#define STABLE_VECTOR_USE_INTERPROCESS_VECTOR
+
+#if defined (STABLE_VECTOR_USE_INTERPROCESS_VECTOR)
+#include <boost/interprocess/containers/vector.hpp>
+#else
+#include <vector>
+#endif //STABLE_VECTOR_USE_INTERPROCESS_VECTOR
+
+//#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING
+
+#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
+#include <boost/assert.hpp>
+#endif
+
+namespace boost{
+namespace interprocess{
+namespace stable_vector_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;}
+};
+
+template<class Ptr>
+inline typename smart_ptr_type<Ptr>::pointer get_pointer(const Ptr &ptr)
+{ return smart_ptr_type<Ptr>::get(ptr); }
+
+template <class C>
+class clear_on_destroy
+{
+ public:
+ clear_on_destroy(C &c)
+ : c_(c), do_clear_(true)
+ {}
+
+ void release()
+ { do_clear_ = false; }
+
+ ~clear_on_destroy()
+ {
+ if(do_clear_){
+ c_.clear();
+ c_.clear_pool();
+ }
+ }
+
+ private:
+ C &c_;
+ bool do_clear_;
+};
+
+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 VoidPtr>
+struct node_type_base
+{
+ node_type_base(VoidPtr p)
+ : up(p)
+ {}
+ VoidPtr up;
+};
+
+template<typename VoidPointer, typename T>
+struct node_type
+ : public node_type_base<VoidPointer>
+{
+ node_type(VoidPointer p, const T &v)
+ : node_type_base<VoidPointer>(p), value(v)
+ {}
+ T value;
+};
+
+template<typename T, typename Value, typename Pointer>
+class iterator
+ : public std::iterator< std::random_access_iterator_tag
+ , const typename std::iterator_traits<Pointer>::value_type
+ , typename std::iterator_traits<Pointer>::difference_type
+ , Pointer
+ , Value &>
+{
+
+ typedef typename boost::pointer_to_other
+ <Pointer, void>::type void_ptr;
+ typedef node_type<void_ptr, T> node_type_t;
+ typedef typename boost::pointer_to_other
+ <void_ptr, node_type_t>::type node_type_ptr_t;
+ typedef typename boost::pointer_to_other
+ <void_ptr, void_ptr>::type void_ptr_ptr;
+
+ friend class iterator<T, const T, typename boost::pointer_to_other<Pointer, T>::type>;
+
+ public:
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef Value value_type;
+ typedef typename std::iterator_traits
+ <Pointer>::difference_type difference_type;
+ typedef Pointer pointer;
+ typedef Value & reference;
+
+ iterator()
+ {}
+
+ explicit iterator(node_type_ptr_t pn)
+ : pn(pn)
+ {}
+
+ iterator(const iterator<T, T, typename boost::pointer_to_other<Pointer, T>::type >& x)
+ : pn(x.pn)
+ {}
+
+ private:
+ static node_type_ptr_t node_ptr_cast(void_ptr p)
+ {
+ using boost::get_pointer;
+ return node_type_ptr_t(static_cast<node_type_t*>(stable_vector_detail::get_pointer(p)));
+ }
+
+ static void_ptr_ptr void_ptr_ptr_cast(void_ptr p)
+ {
+ using boost::get_pointer;
+ return void_ptr_ptr(static_cast<void_ptr*>(stable_vector_detail::get_pointer(p)));
+ }
+
+ Value& dereference() const
+ { return pn->value; }
+ bool equal(const iterator& x) const
+ { return pn==x.pn; }
+ void increment()
+ { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+1)); }
+ void decrement()
+ { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)-1)); }
+ void advance(std::ptrdiff_t n)
+ { pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+n)); }
+ std::ptrdiff_t distance_to(const iterator& x)const
+ { return void_ptr_ptr_cast(x.pn->up) - void_ptr_ptr_cast(pn->up); }
+
+ public:
+ //Pointer like operators
+ reference operator*() const { return this->dereference(); }
+ pointer operator->() const { return pointer(&this->dereference()); }
+
+ //Increment / Decrement
+ iterator& operator++()
+ { this->increment(); return *this; }
+
+ iterator operator++(int)
+ { iterator tmp(*this); ++*this; return iterator(tmp); }
+
+ iterator& operator--()
+ { this->decrement(); return *this; }
+
+ iterator operator--(int)
+ { iterator tmp(*this); --*this; return iterator(tmp); }
+
+ reference operator[](difference_type off) const
+ {
+ iterator tmp(*this);
+ tmp += off;
+ return *tmp;
+ }
+
+ iterator& operator+=(difference_type off)
+ {
+ pn = node_ptr_cast(*(void_ptr_ptr_cast(pn->up)+off));
+ return *this;
+ }
+
+ iterator operator+(difference_type off) const
+ {
+ iterator tmp(*this);
+ tmp += off;
+ return tmp;
+ }
+
+ friend iterator operator+(difference_type off, const iterator& right)
+ {
+ iterator tmp(right);
+ tmp += off;
+ return tmp;
+ }
+
+ iterator& operator-=(difference_type off)
+ { *this += -off; return *this; }
+
+ iterator operator-(difference_type off) const
+ {
+ iterator tmp(*this);
+ tmp -= off;
+ return tmp;
+ }
+
+ difference_type operator-(const iterator& right) const
+ {
+ void_ptr_ptr p1 = void_ptr_ptr_cast(this->pn->up);
+ void_ptr_ptr p2 = void_ptr_ptr_cast(right.pn->up);
+ return p1 - p2;
+ }
+
+ //Comparison operators
+ bool operator== (const iterator& r) const
+ { return pn == r.pn; }
+
+ bool operator!= (const iterator& r) const
+ { return pn != r.pn; }
+
+ bool operator< (const iterator& r) const
+ { return void_ptr_ptr_cast(pn->up) < void_ptr_ptr_cast(r.pn->up); }
+
+ bool operator<= (const iterator& r) const
+ { return void_ptr_ptr_cast(pn->up) <= void_ptr_ptr_cast(r.pn->up); }
+
+ bool operator> (const iterator& r) const
+ { return void_ptr_ptr_cast(pn->up) > void_ptr_ptr_cast(r.pn->up); }
+
+ bool operator>= (const iterator& r) const
+ { return void_ptr_ptr_cast(pn->up) >= void_ptr_ptr_cast(r.pn->up); }
+
+ node_type_ptr_t pn;
+};
+/*
+class node_access
+{
+ public:
+ template<typename T, typename Value, typename VoidPointer>
+ static typename iterator<T, Value, VoidPointer>::node_type_t* get(const iterator<T,Value,VoidPointer>& it)
+ {
+ return stable_vector_detail::get_pointer(it.pn);
+ }
+};
+*/
+template<class Allocator, unsigned int Version>
+struct select_multiallocation_chain
+{
+ typedef typename Allocator::multiallocation_chain type;
+};
+
+template<class Allocator>
+struct select_multiallocation_chain<Allocator, 1>
+{
+ typedef typename Allocator::template
+ rebind<void>::other::pointer void_ptr;
+ typedef detail::basic_multiallocation_cached_slist<void_ptr> multialloc_cached;
+ typedef detail::basic_multiallocation_cached_counted_slist
+ <multialloc_cached> multialloc_cached_counted;
+ typedef boost::interprocess::detail::transform_multiallocation_chain
+ <multialloc_cached_counted, typename Allocator::value_type> type;
+};
+
+} //namespace stable_vector_detail
+
+#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
+
+#define STABLE_VECTOR_CHECK_INVARIANT \
+invariant_checker BOOST_JOIN(check_invariant_,__LINE__)(*this); \
+BOOST_JOIN(check_invariant_,__LINE__).touch();
+#else
+
+#define STABLE_VECTOR_CHECK_INVARIANT
+
+#endif //#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
+
+template<typename T,typename Allocator=std::allocator<T> >
+class stable_vector
+{
+ typedef typename Allocator::template
+ rebind<void>::other::pointer void_ptr;
+ typedef typename Allocator::template
+ rebind<void_ptr>::other::pointer void_ptr_ptr;
+ typedef stable_vector_detail::node_type
+ <void_ptr, T> node_type_t;
+ typedef typename Allocator::template
+ rebind<node_type_t>::other::pointer node_type_ptr_t;
+ typedef stable_vector_detail::node_type_base
+ <void_ptr> node_type_base_t;
+ typedef typename Allocator::template
+ rebind<node_type_base_t>::other::pointer node_type_base_ptr_t;
+ typedef
+ #if defined (STABLE_VECTOR_USE_INTERPROCESS_VECTOR)
+ ::boost::interprocess::
+ #else
+ ::std::
+ #endif //STABLE_VECTOR_USE_INTERPROCESS_VECTOR
+ vector<void_ptr,
+ typename Allocator::
+ template rebind<void_ptr>::other
+ > impl_type;
+ typedef typename impl_type::iterator impl_iterator;
+ typedef typename impl_type::const_iterator const_impl_iterator;
+
+ typedef ::boost::interprocess::detail::
+ integral_constant<unsigned, 1> allocator_v1;
+ typedef ::boost::interprocess::detail::
+ integral_constant<unsigned, 2> allocator_v2;
+ typedef ::boost::interprocess::detail::integral_constant
+ <unsigned, boost::interprocess::detail::
+ version<Allocator>::value> alloc_version;
+ typedef typename Allocator::
+ template rebind<node_type_t>::other node_allocator_type;
+
+ node_type_ptr_t allocate_one()
+ { return this->allocate_one(alloc_version()); }
+
+ node_type_ptr_t allocate_one(allocator_v1)
+ { return get_al().allocate(1); }
+
+ node_type_ptr_t allocate_one(allocator_v2)
+ { return get_al().allocate_one(); }
+
+ void deallocate_one(node_type_ptr_t p)
+ { return this->deallocate_one(p, alloc_version()); }
+
+ void deallocate_one(node_type_ptr_t p, allocator_v1)
+ { get_al().deallocate(p, 1); }
+
+ void deallocate_one(node_type_ptr_t p, allocator_v2)
+ { get_al().deallocate_one(p); }
+
+ friend class stable_vector_detail::clear_on_destroy<stable_vector>;
+
+ public:
+ // types:
+
+ typedef typename Allocator::reference reference;
+ typedef typename Allocator::const_reference const_reference;
+ typedef typename Allocator::pointer pointer;
+ typedef typename Allocator::const_pointer const_pointer;
+ typedef stable_vector_detail::iterator
+ <T,T, pointer> iterator;
+ typedef stable_vector_detail::iterator
+ <T,const T, const_pointer> const_iterator;
+ typedef typename impl_type::size_type size_type;
+ typedef typename iterator::difference_type difference_type;
+ typedef T value_type;
+ typedef Allocator allocator_type;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ private:
+ static const size_type ExtraPointers = 3;
+ typedef typename stable_vector_detail::
+ select_multiallocation_chain
+ < node_allocator_type
+ , alloc_version::value
+ >::type multiallocation_chain;
+
+ public:
+
+ // construct/copy/destroy:
+ explicit stable_vector(const Allocator& al=Allocator())
+ : internal_data(al),impl(al)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ }
+
+ stable_vector(size_type n,const T& t=T(),const Allocator& al=Allocator())
+ : internal_data(al),impl(al)
+ {
+ stable_vector_detail::clear_on_destroy<stable_vector> cod(*this);
+ this->insert(this->cbegin(), n, t);
+ STABLE_VECTOR_CHECK_INVARIANT;
+ cod.release();
+ }
+
+ template <class InputIterator>
+ stable_vector(InputIterator first,InputIterator last,const Allocator& al=Allocator())
+ : internal_data(al),impl(al)
+ {
+ stable_vector_detail::clear_on_destroy<stable_vector> cod(*this);
+ this->insert(this->cbegin(), first, last);
+ STABLE_VECTOR_CHECK_INVARIANT;
+ cod.release();
+ }
+
+ stable_vector(const stable_vector& x)
+ : internal_data(x.get_al()),impl(x.get_al())
+ {
+ stable_vector_detail::clear_on_destroy<stable_vector> cod(*this);
+ this->insert(this->cbegin(), x.begin(), x.end());
+ STABLE_VECTOR_CHECK_INVARIANT;
+ cod.release();
+ }
+
+ ~stable_vector()
+ {
+ this->clear();
+ clear_pool();
+ }
+
+ stable_vector& operator=(stable_vector x)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ this->swap(x);
+ return *this;
+ }
+
+ template<typename InputIterator>
+ void assign(InputIterator first,InputIterator last)
+ {
+ assign_dispatch(first, last, boost::is_integral<InputIterator>());
+ }
+
+ void assign(size_type n,const T& t)
+ {
+ typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
+ return assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_());
+ }
+
+ allocator_type get_allocator()const {return get_al();}
+
+ // iterators:
+
+ iterator begin()
+ { return (impl.empty()) ? end(): iterator(node_ptr_cast(impl.front())) ; }
+
+ const_iterator begin()const
+ { return (impl.empty()) ? cend() : const_iterator(node_ptr_cast(impl.front())) ; }
+
+ iterator end() {return iterator(get_end_node());}
+ const_iterator end()const {return const_iterator(get_end_node());}
+
+ reverse_iterator rbegin() {return reverse_iterator(this->end());}
+ const_reverse_iterator rbegin()const {return const_reverse_iterator(this->end());}
+ reverse_iterator rend() {return reverse_iterator(this->begin());}
+ const_reverse_iterator rend()const {return const_reverse_iterator(this->begin());}
+
+ const_iterator cbegin()const {return this->begin();}
+ const_iterator cend()const {return this->end();}
+ const_reverse_iterator crbegin()const{return this->rbegin();}
+ const_reverse_iterator crend()const {return this->rend();}
+
+ // capacity:
+ size_type size() const
+ { return impl.empty() ? 0 : (impl.size() - ExtraPointers); }
+
+ size_type max_size() const
+ { return impl.max_size() - ExtraPointers; }
+
+ size_type capacity() const
+ {
+ if(!impl.capacity()){
+ return 0;
+ }
+ else{
+ const size_type num_nodes = this->impl.size() + this->internal_data.pool_size;
+ const size_type num_buck = this->impl.capacity();
+ return (num_nodes < num_buck) ? num_nodes : num_buck;
+ }
+ }
+
+ bool empty() const
+ { return impl.empty() || impl.size() == ExtraPointers; }
+
+ void resize(size_type n,const T& t=T())
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ if(n > size())
+ this->insert(this->cend(), n - this->size(), t);
+ else if(n < this->size())
+ this->erase(this->cbegin() + n, this->cend());
+ }
+
+ void reserve(size_type n)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ if(n > this->max_size())
+ throw std::bad_alloc();
+
+ size_type size = this->size();
+ size_type old_capacity = this->capacity();
+ if(n > old_capacity){
+ this->initialize_end_node(n);
+ const void * old_ptr = &impl[0];
+ impl.reserve(n + ExtraPointers);
+ bool realloced = &impl[0] != old_ptr;
+ //Fix the pointers for the newly allocated buffer
+ if(realloced){
+ this->align_nodes(impl.begin(), impl.begin()+size+1);
+ }
+ //Now fill pool if data is not enough
+ if((n - size) > this->internal_data.pool_size){
+ this->add_to_pool((n - size) - this->internal_data.pool_size, alloc_version());
+ }
+ }
+ }
+
+ template<class AllocatorVersion>
+ void clear_pool(AllocatorVersion,
+ typename boost::interprocess::detail::enable_if_c
+ <boost::interprocess::detail::is_same<AllocatorVersion, allocator_v1>
+ ::value>::type * = 0)
+ {
+ if(!impl.empty() && impl.back()){
+ void_ptr &p1 = *(impl.end()-2);
+ void_ptr &p2 = impl.back();
+
+ multiallocation_chain holder(p1, p2, this->internal_data.pool_size);
+ while(!holder.empty()){
+ node_type_ptr_t n = holder.front();
+ holder.pop_front();
+ this->deallocate_one(n);
+ }
+ p1 = p2 = 0;
+ this->internal_data.pool_size = 0;
+ }
+ }
+
+ template<class AllocatorVersion>
+ void clear_pool(AllocatorVersion,
+ typename boost::interprocess::detail::enable_if_c
+ <boost::interprocess::detail::is_same<AllocatorVersion, allocator_v2>
+ ::value>::type * = 0)
+ {
+
+ if(!impl.empty() && impl.back()){
+ void_ptr &p1 = *(impl.end()-2);
+ void_ptr &p2 = impl.back();
+ multiallocation_chain holder(p1, p2, this->internal_data.pool_size);
+ get_al().deallocate_individual(boost::move(holder));
+ p1 = p2 = 0;
+ this->internal_data.pool_size = 0;
+ }
+ }
+
+ void clear_pool()
+ {
+ this->clear_pool(alloc_version());
+ }
+
+ template<class AllocatorVersion>
+ void add_to_pool(size_type n, AllocatorVersion,
+ typename boost::interprocess::detail::enable_if_c
+ <boost::interprocess::detail::is_same<AllocatorVersion, allocator_v1>
+ ::value>::type * = 0)
+ {
+ size_type remaining = n;
+ while(remaining--){
+ this->put_in_pool(this->allocate_one());
+ }
+ }
+
+ template<class AllocatorVersion>
+ void add_to_pool(size_type n, AllocatorVersion,
+ typename boost::interprocess::detail::enable_if_c
+ <boost::interprocess::detail::is_same<AllocatorVersion, allocator_v2>
+ ::value>::type * = 0)
+ {
+ void_ptr &p1 = *(impl.end()-2);
+ void_ptr &p2 = impl.back();
+ multiallocation_chain holder(p1, p2, this->internal_data.pool_size);
+ BOOST_STATIC_ASSERT((boost::is_movable<multiallocation_chain>::value == true));
+ multiallocation_chain m (get_al().allocate_individual(n));
+ holder.splice_after(holder.before_begin(), m, m.before_begin(), m.last(), n);
+ this->internal_data.pool_size += n;
+ std::pair<void_ptr, void_ptr> data(holder.extract_data());
+ p1 = data.first;
+ p2 = data.second;
+ }
+
+ void put_in_pool(node_type_ptr_t p)
+ {
+ void_ptr &p1 = *(impl.end()-2);
+ void_ptr &p2 = impl.back();
+ multiallocation_chain holder(p1, p2, internal_data.pool_size);
+ holder.push_front(p);
+ ++this->internal_data.pool_size;
+ std::pair<void_ptr, void_ptr> ret(holder.extract_data());
+ p1 = ret.first;
+ p2 = ret.second;
+ }
+
+ node_type_ptr_t get_from_pool()
+ {
+ if(!impl.back()){
+ return node_type_ptr_t(0);
+ }
+ else{
+ void_ptr &p1 = *(impl.end()-2);
+ void_ptr &p2 = impl.back();
+ multiallocation_chain holder(p1, p2, internal_data.pool_size);
+ node_type_ptr_t ret = holder.front();
+ holder.pop_front();
+ std::pair<void_ptr, void_ptr> data(holder.extract_data());
+ p1 = data.first;
+ p2 = data.second;
+ --this->internal_data.pool_size;
+ return ret;
+ }
+ }
+
+ // element access:
+
+ reference operator[](size_type n){return value(impl[n]);}
+ const_reference operator[](size_type n)const{return value(impl[n]);}
+
+ const_reference at(size_type n)const
+ {
+ if(n>=size())
+ throw std::out_of_range("invalid subscript at stable_vector::at");
+ return operator[](n);
+ }
+
+ reference at(size_type n)
+ {
+ if(n>=size())
+ throw std::out_of_range("invalid subscript at stable_vector::at");
+ return operator[](n);
+ }
+
+ reference front()
+ { return value(impl.front()); }
+
+ const_reference front()const
+ { return value(impl.front()); }
+
+ reference back()
+ { return value(*(&impl.back() - ExtraPointers)); }
+
+ const_reference back()const
+ { return value(*(&impl.back() - ExtraPointers)); }
+
+ // modifiers:
+
+ void push_back(const T& t)
+ { this->insert(end(),t); }
+
+ void pop_back()
+ { this->erase(this->end()-1); }
+
+ iterator insert(const_iterator position,const T& t)
+ {
+ typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
+ return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag());
+ }
+
+ void insert(const_iterator position,size_type n,const T& t)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ this->insert_not_iter(position, n, t);
+ }
+
+ template <class InputIterator>
+ void insert(const_iterator position,InputIterator first,InputIterator last)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ this->insert_iter(position,first,last,
+ boost::mpl::not_<boost::is_integral<InputIterator> >());
+ }
+
+ iterator erase(const_iterator position)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ difference_type d=position-this->cbegin();
+ impl_iterator it=impl.begin()+d;
+ this->delete_node(*it);
+ impl.erase(it);
+ this->align_nodes(impl.begin()+d,get_last_align());
+ return this->begin()+d;
+ }
+
+ iterator erase(const_iterator first, const_iterator last)
+ { return priv_erase(first, last, alloc_version()); }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ void swap(stable_vector & x)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ this->swap_impl(*this,x);
+ }
+ void swap(boost::rv<stable_vector> & x)
+ #else
+ void swap(stable_vector&& x)
+ #endif
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ this->swap_impl(*this,x);
+ }
+
+
+
+ void clear()
+ { this->erase(this->cbegin(),this->cend()); }
+
+ private:
+
+ template<typename InputIterator>
+ void assign_dispatch(InputIterator first, InputIterator last, boost::mpl::false_)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ iterator first1 = this->begin();
+ iterator last1 = this->end();
+ for ( ; first1 != last1 && first != last; ++first1, ++first)
+ *first1 = *first;
+ if (first == last){
+ this->erase(first1, last1);
+ }
+ else{
+ this->insert(last1, first, last);
+ }
+ }
+
+ template<typename Integer>
+ void assign_dispatch(Integer n, Integer t, boost::mpl::true_)
+ {
+ typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
+ this->assign_dispatch(cvalue_iterator(t, n), cvalue_iterator(), boost::mpl::false_());
+ }
+
+ iterator priv_erase(const_iterator first, const_iterator last, allocator_v1)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ difference_type d1 = first - this->cbegin(), d2 = last - this->cbegin();
+ if(d1 != d2){
+ impl_iterator it1(impl.begin() + d1), it2(impl.begin() + d2);
+ for(impl_iterator it = it1; it != it2; ++it)
+ this->delete_node(*it);
+ impl.erase(it1, it2);
+ this->align_nodes(impl.begin() + d1, get_last_align());
+ }
+ return iterator(this->begin() + d1);
+ }
+
+ impl_iterator get_last_align()
+ {
+ return impl.end() - (ExtraPointers - 1);
+ }
+
+ const_impl_iterator get_last_align() const
+ {
+ return impl.cend() - (ExtraPointers - 1);
+ }
+
+ template<class AllocatorVersion>
+ iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion,
+ typename boost::interprocess::detail::enable_if_c
+ <boost::interprocess::detail::is_same<AllocatorVersion, allocator_v2>
+ ::value>::type * = 0)
+ {
+ STABLE_VECTOR_CHECK_INVARIANT;
+ return priv_erase(first, last, allocator_v1());
+ }
+
+ static node_type_ptr_t node_ptr_cast(void_ptr p)
+ {
+ using boost::get_pointer;
+ return node_type_ptr_t(static_cast<node_type_t*>(stable_vector_detail::get_pointer(p)));
+ }
+
+ static node_type_base_ptr_t node_base_ptr_cast(void_ptr p)
+ {
+ using boost::get_pointer;
+ return node_type_base_ptr_t(static_cast<node_type_base_t*>(stable_vector_detail::get_pointer(p)));
+ }
+
+ static value_type& value(void_ptr p)
+ {
+ return node_ptr_cast(p)->value;
+ }
+
+ void initialize_end_node(size_type impl_capacity = 0)
+ {
+ if(impl.empty()){
+ impl.reserve(impl_capacity + ExtraPointers);
+ impl.resize (ExtraPointers, void_ptr(0));
+ impl[0] = &this->internal_data.end_node;
+ this->internal_data.end_node.up = &impl[0];
+ }
+ }
+
+ void readjust_end_node()
+ {
+ if(!this->impl.empty()){
+ void_ptr &end_node_ref = *(this->get_last_align()-1);
+ end_node_ref = this->get_end_node();
+ this->internal_data.end_node.up = &end_node_ref;
+ }
+ else{
+ this->internal_data.end_node.up = void_ptr(&this->internal_data.end_node.up);
+ }
+ }
+
+ node_type_ptr_t get_end_node() const
+ {
+ const node_type_base_t* cp = &this->internal_data.end_node;
+ node_type_base_t* p = const_cast<node_type_base_t*>(cp);
+ return node_ptr_cast(p);
+ }
+
+ void_ptr new_node(void_ptr up, const T& t)
+ {
+ node_type_ptr_t p = this->allocate_one();
+ try{
+ new(&*p) node_type_t(up, t);
+ }
+ catch(...){
+ this->deallocate_one(p);
+ throw;
+ }
+ return p;
+ }
+
+ void delete_node(void_ptr p)
+ {
+ node_type_ptr_t n(node_ptr_cast(p));
+ n->~node_type_t();
+ this->put_in_pool(n);
+ }
+
+ static void align_nodes(impl_iterator first,impl_iterator last)
+ {
+ while(first!=last){
+ node_ptr_cast(*first)->up = void_ptr(&*first);
+ ++first;
+ }
+ }
+
+ void insert_not_iter(const_iterator position,size_type n,const T& t)
+ {
+ typedef stable_vector_detail::constant_iterator<value_type, difference_type> cvalue_iterator;
+ this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag());
+ }
+
+ template <class InputIterator>
+ void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_)
+ {
+ typedef typename std::iterator_traits<InputIterator>::iterator_category category;
+ this->insert_iter(position,first,last,category());
+ }
+
+ template <class InputIterator>
+ void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag)
+ {
+ for(; first!=last; ++first){
+ this->insert(position, *first);
+ }
+ }
+
+ template <class InputIterator>
+ iterator insert_iter(const_iterator position,InputIterator first,InputIterator last,std::forward_iterator_tag)
+ {
+ size_type n = (size_type)std::distance(first,last);
+ difference_type d = position-this->cbegin();
+ if(n){
+ initialize_end_node(n);
+ const void* old_ptr = &impl[0];
+ //size_type old_capacity = capacity();
+ //size_type old_size = size();
+ impl.insert(impl.begin()+d, n, 0);
+ bool realloced = &impl[0] != old_ptr;
+ //Fix the pointers for the newly allocated buffer
+ if(realloced){
+ align_nodes(impl.begin(), impl.begin()+d);
+ }
+ const impl_iterator it(impl.begin() + d);
+ this->insert_iter_fwd(it, first, last, n);
+
+ //Fix the pointers for the newly allocated buffer
+ this->align_nodes(it + n, get_last_align());
+ }
+ return this->begin() + d;
+ }
+
+ template <class FwdIterator>
+ void insert_iter_fwd_alloc(const impl_iterator it,FwdIterator first,FwdIterator last, difference_type n, allocator_v1)
+ {
+ size_type i=0;
+ try{
+ while(first!=last){
+ *(it + i) = this->new_node(void_ptr((void*)(&*(it + i))), *first++);
+ ++i;
+ }
+ }
+ catch(...){
+ impl.erase(it + i, it + n);
+ this->align_nodes(it + i, get_last_align());
+ throw;
+ }
+ }
+
+ template <class FwdIterator>
+ void insert_iter_fwd_alloc(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n, allocator_v2)
+ {
+ multiallocation_chain mem(get_al().allocate_individual(n));
+
+ size_type i = 0;
+ node_type_ptr_t p = 0;
+ try{
+ while(first != last){
+ p = mem.front();
+ mem.pop_front();
+ //This can throw
+ new(&*p) node_type_t(void_ptr((void*)(&*(it + i))), *first++);
+ *(it + i) = p;
+ ++i;
+ }
+ }
+ catch(...){
+ get_al().deallocate_one(p);
+ get_al().deallocate_many(boost::move(mem));
+ impl.erase(it+i, it+n);
+ this->align_nodes(it+i,get_last_align());
+ throw;
+ }
+ }
+
+ template <class FwdIterator>
+ void insert_iter_fwd(const impl_iterator it, FwdIterator first, FwdIterator last, difference_type n)
+ {
+ size_type i = 0;
+ node_type_ptr_t p = 0;
+ try{
+ while(first != last){
+ p = get_from_pool();
+ if(!p){
+ insert_iter_fwd_alloc(it+i, first, last, n-i, alloc_version());
+ break;
+ }
+ //This can throw
+ new(&*p) node_type_t(void_ptr(&*(it+i)), *first++);
+ *(it+i)=p;
+ ++i;
+ }
+ }
+ catch(...){
+ put_in_pool(p);
+ impl.erase(it+i,it+n);
+ this->align_nodes(it+i,get_last_align());
+ throw;
+ }
+ }
+
+ template <class InputIterator>
+ void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::false_)
+ {
+ this->insert_not_iter(position,first,last);
+ }
+
+ static void swap_impl(stable_vector& x,stable_vector& y)
+ {
+ using std::swap;
+ swap(x.get_al(),y.get_al());
+ swap(x.impl,y.impl);
+ swap(x.internal_data.pool_size, y.internal_data.pool_size);
+ x.readjust_end_node();
+ y.readjust_end_node();
+ }
+
+ #if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING)
+ bool invariant()const
+ {
+ if(impl.empty())
+ return !capacity() && !size();
+ if(get_end_node() != *(impl.end() - ExtraPointers)){
+ return false;
+ }
+ for(const_impl_iterator it=impl.begin(),it_end=get_last_align();it!=it_end;++it){
+ if(node_ptr_cast(*it)->up != &*it)
+ return false;
+ }
+ size_type n = capacity()-size();
+ const void_ptr &pool_head = impl.back();
+ size_type num_pool = 0;
+ node_type_ptr_t p = node_ptr_cast(pool_head);
+ while(p){
+ ++num_pool;
+ p = p->up;
+ }
+ return n >= num_pool;
+ }
+
+ class invariant_checker:private boost::noncopyable
+ {
+ const stable_vector* p;
+ public:
+ invariant_checker(const stable_vector& v):p(&v){}
+ ~invariant_checker(){BOOST_ASSERT(p->invariant());}
+ void touch(){}
+ };
+ #endif
+
+ struct ebo_holder
+ : node_allocator_type
+ {
+ ebo_holder(const allocator_type &a)
+ : node_allocator_type(a), pool_size(0), end_node(void_ptr(&end_node.up))
+ {}
+ size_type pool_size;
+ node_type_base_t end_node;
+ } internal_data;
+
+ node_allocator_type &get_al() { return internal_data; }
+ const node_allocator_type &get_al() const { return internal_data; }
+
+ impl_type impl;
+};
+
+template <typename T,typename Allocator>
+bool operator==(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
+{
+ return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin());
+}
+
+template <typename T,typename Allocator>
+bool operator< (const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
+{
+ return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end());
+}
+
+template <typename T,typename Allocator>
+bool operator!=(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
+{
+ return !(x==y);
+}
+
+template <typename T,typename Allocator>
+bool operator> (const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
+{
+ return y<x;
+}
+
+template <typename T,typename Allocator>
+bool operator>=(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
+{
+ return !(x<y);
+}
+
+template <typename T,typename Allocator>
+bool operator<=(const stable_vector<T,Allocator>& x,const stable_vector<T,Allocator>& y)
+{
+ return !(x>y);
+}
+
+// specialized algorithms:
+
+template <typename T, typename Allocator>
+void swap(stable_vector<T,Allocator>& x,stable_vector<T,Allocator>& y)
+{
+ x.swap(y);
+}
+
+#undef STABLE_VECTOR_CHECK_INVARIANT
+
+} //namespace interprocess{
+} //namespace boost{
+
+#endif
Added: sandbox/boost/interprocess/containers/string.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/string.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,2478 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's string file. Modified by Ion Gaztanaga 2004-2008
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 1994
+// Hewlett-Packard Company
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. Hewlett-Packard Company makes no
+// representations about the suitability of this software for any
+// purpose. It is provided "as is" without express or implied warranty.
+
+#ifndef BOOST_INTERPROCESS_STRING_HPP
+#define BOOST_INTERPROCESS_STRING_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/algorithms.hpp>
+#include <boost/interprocess/detail/min_max.hpp>
+#include <boost/interprocess/detail/iterators.hpp>
+#include <boost/interprocess/detail/version_type.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/static_assert.hpp>
+
+#include <functional>
+#include <string>
+#include <stdexcept>
+#include <utility>
+#include <iterator>
+#include <memory>
+#include <algorithm>
+#include <iosfwd>
+#include <istream>
+#include <ostream>
+#include <ios>
+#include <locale>
+#include <cstddef>
+#include <climits>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+/// @cond
+// ------------------------------------------------------------
+// Class basic_string_base.
+
+// basic_string_base is a helper class that makes it it easier to write
+// an exception-safe version of basic_string. The constructor allocates,
+// but does not initialize, a block of memory. The destructor
+// deallocates, but does not destroy elements within, a block of
+// memory. The destructor assumes that the memory either is the internal buffer,
+// or else points to a block of memory that was allocated using _String_base's
+// allocator and whose size is this->m_storage.
+template <class A>
+class basic_string_base
+{
+ basic_string_base();
+ basic_string_base(basic_string_base&);
+ basic_string_base & operator=(basic_string_base&);
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(basic_string_base)
+
+ typedef A allocator_type;
+ //! The stored allocator type
+ typedef allocator_type stored_allocator_type;
+ typedef typename A::pointer pointer;
+ typedef typename A::value_type value_type;
+ typedef typename A::size_type size_type;
+
+ basic_string_base(const allocator_type& a)
+ : members_(a)
+ { init(); }
+
+ basic_string_base(const allocator_type& a, std::size_t n)
+ : members_(a)
+ {
+ this->init();
+ this->allocate_initial_block(n);
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS)
+ basic_string_base(boost::rv<basic_string_base<A> > &b)
+ : members_(b.get().members_)
+ {
+ init();
+ this->swap(b.get());
+ }
+ #else
+ basic_string_base(basic_string_base<A> && b)
+ : members_(b.members_)
+ {
+ init();
+ this->swap(b);
+ }
+ #endif
+
+ ~basic_string_base()
+ {
+ this->deallocate_block();
+ if(!this->is_short()){
+ static_cast<long_t*>(static_cast<void*>(&this->members_.m_repr.r))->~long_t();
+ }
+ }
+
+ private:
+
+ //This is the structure controlling a long string
+ struct long_t
+ {
+ size_type is_short : 1;
+ size_type length : (sizeof(size_type)*CHAR_BIT - 1);
+ size_type storage;
+ pointer start;
+
+ long_t()
+ {}
+
+ long_t(const long_t &other)
+ {
+ this->is_short = other.is_short;
+ length = other.length;
+ storage = other.storage;
+ start = other.start;
+ }
+
+ long_t &operator =(const long_t &other)
+ {
+ this->is_short = other.is_short;
+ length = other.length;
+ storage = other.storage;
+ start = other.start;
+ return *this;
+ }
+ };
+
+ //This basic type should have the same alignment as long_t
+//iG typedef typename type_with_alignment<detail::alignment_of<long_t>::value>::type
+// long_alignment_type;
+ typedef void *long_alignment_type;
+ BOOST_STATIC_ASSERT((detail::alignment_of<long_alignment_type>::value %
+ detail::alignment_of<long_t>::value) == 0);
+
+
+ //This type is the first part of the structure controlling a short string
+ //The "data" member stores
+ struct short_header
+ {
+ unsigned char is_short : 1;
+ unsigned char length : (CHAR_BIT - 1);
+ };
+
+ //This type has the same alignment and size as long_t but it's POD
+ //so, unlike long_t, it can be placed in a union
+ struct long_raw_t
+ {
+ long_alignment_type a;
+ unsigned char b[sizeof(long_t) - sizeof(long_alignment_type)];
+ };
+
+ protected:
+ static const size_type MinInternalBufferChars = 8;
+ static const size_type AlignmentOfValueType =
+ alignment_of<value_type>::value;
+ static const size_type ShortDataOffset =
+ detail::ct_rounded_size<sizeof(short_header), AlignmentOfValueType>::value;
+ static const size_type ZeroCostInternalBufferChars =
+ (sizeof(long_t) - ShortDataOffset)/sizeof(value_type);
+ static const size_type UnalignedFinalInternalBufferChars =
+ (ZeroCostInternalBufferChars > MinInternalBufferChars) ?
+ ZeroCostInternalBufferChars : MinInternalBufferChars;
+
+ struct short_t
+ {
+ short_header h;
+ value_type data[UnalignedFinalInternalBufferChars];
+ };
+
+ union repr_t
+ {
+ long_raw_t r;
+ short_t s;
+
+ short_t &short_repr() const
+ { return *const_cast<short_t *>(&s); }
+
+ long_t &long_repr() const
+ { return *static_cast<long_t*>(const_cast<void*>(static_cast<const void*>(&r))); }
+ };
+
+ struct members_holder
+ : public A
+ {
+ members_holder(const A &a)
+ : A(a)
+ {}
+
+ repr_t m_repr;
+ } members_;
+
+ const A &alloc() const
+ { return members_; }
+
+ A &alloc()
+ { return members_; }
+
+ static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type);
+
+ private:
+
+ static const size_type MinAllocation = InternalBufferChars*2;
+
+ protected:
+ bool is_short() const
+ { return static_cast<bool>(this->members_.m_repr.s.h.is_short != 0); }
+
+ void is_short(bool yes)
+ {
+ if(yes && !this->is_short()){
+ static_cast<long_t*>(static_cast<void*>(&this->members_.m_repr.r))->~long_t();
+ }
+ else{
+ new(static_cast<void*>(&this->members_.m_repr.r))long_t();
+ }
+ this->members_.m_repr.s.h.is_short = yes;
+ }
+
+ private:
+ void init()
+ {
+ this->members_.m_repr.s.h.is_short = 1;
+ this->members_.m_repr.s.h.length = 0;
+ }
+
+ protected:
+
+ typedef detail::integral_constant<unsigned, 1> allocator_v1;
+ typedef detail::integral_constant<unsigned, 2> allocator_v2;
+ typedef detail::integral_constant<unsigned,
+ boost::interprocess::detail::version<A>::value> alloc_version;
+
+ std::pair<pointer, bool>
+ allocation_command(allocation_type command,
+ size_type limit_size,
+ size_type preferred_size,
+ size_type &received_size, pointer reuse = 0)
+ {
+ if(this->is_short() && (command & (expand_fwd | expand_bwd)) ){
+ reuse = pointer(0);
+ command &= ~(expand_fwd | expand_bwd);
+ }
+ return this->allocation_command
+ (command, limit_size, preferred_size, received_size, reuse, alloc_version());
+ }
+
+ std::pair<pointer, bool>
+ allocation_command(allocation_type command,
+ size_type limit_size,
+ size_type preferred_size,
+ size_type &received_size,
+ const pointer &reuse,
+ allocator_v1)
+ {
+ (void)limit_size;
+ (void)reuse;
+ if(!(command & allocate_new))
+ return std::pair<pointer, bool>(pointer(0), 0);
+ received_size = preferred_size;
+ return std::make_pair(this->alloc().allocate(received_size), false);
+ }
+
+ std::pair<pointer, bool>
+ allocation_command(allocation_type command,
+ size_type limit_size,
+ size_type preferred_size,
+ size_type &received_size,
+ pointer reuse,
+ allocator_v2)
+ {
+ return this->alloc().allocation_command(command, limit_size, preferred_size,
+ received_size, reuse);
+ }
+
+ size_type next_capacity(size_type additional_objects) const
+ { return get_next_capacity(this->alloc().max_size(), this->priv_storage(), additional_objects); }
+
+ void deallocate(pointer p, std::size_t n)
+ {
+ if (p && (n > InternalBufferChars))
+ this->alloc().deallocate(p, n);
+ }
+
+ void construct(pointer p, const value_type &value = value_type())
+ { new((void*)detail::get_pointer(p)) value_type(value); }
+
+ void destroy(pointer p, size_type n)
+ {
+ for(; n--; ++p)
+ detail::get_pointer(p)->~value_type();
+ }
+
+ void destroy(pointer p)
+ { detail::get_pointer(p)->~value_type(); }
+
+ void allocate_initial_block(std::size_t n)
+ {
+ if (n <= this->max_size()) {
+ if(n > InternalBufferChars){
+ size_type new_cap = this->next_capacity(n);
+ pointer p = this->allocation_command(allocate_new, n, new_cap, new_cap).first;
+ this->is_short(false);
+ this->priv_addr(p);
+ this->priv_size(0);
+ this->priv_storage(new_cap);
+ }
+ }
+ else
+ throw_length_error();
+ }
+
+ void deallocate_block()
+ { this->deallocate(this->priv_addr(), this->priv_storage()); }
+
+ std::size_t max_size() const
+ { return this->alloc().max_size() - 1; }
+
+ // Helper functions for exception handling.
+ void throw_length_error() const
+ { throw(std::length_error("basic_string")); }
+
+ void throw_out_of_range() const
+ { throw(std::out_of_range("basic_string")); }
+
+ protected:
+ size_type priv_capacity() const
+ { return this->priv_storage() - 1; }
+
+ pointer priv_addr() const
+ { return this->is_short() ? pointer(&this->members_.m_repr.short_repr().data[0]) : this->members_.m_repr.long_repr().start; }
+
+ void priv_addr(pointer addr)
+ { this->members_.m_repr.long_repr().start = addr; }
+
+ size_type priv_storage() const
+ { return this->is_short() ? InternalBufferChars : this->members_.m_repr.long_repr().storage; }
+
+ void priv_storage(size_type storage)
+ {
+ if(!this->is_short())
+ this->members_.m_repr.long_repr().storage = storage;
+ }
+
+ size_type priv_size() const
+ { return this->is_short() ? this->members_.m_repr.short_repr().h.length : this->members_.m_repr.long_repr().length; }
+
+ void priv_size(size_type sz)
+ {
+ if(this->is_short())
+ this->members_.m_repr.s.h.length = (unsigned char)sz;
+ else
+ this->members_.m_repr.long_repr().length = static_cast<typename A::size_type>(sz);
+ }
+
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_string_base> &x)
+ { this->swap(x.get()); }
+ void swap(basic_string_base& other)
+ #else
+ void swap(basic_string_base &&other)
+ #endif
+ {
+ if(this->is_short()){
+ if(other.is_short()){
+ std::swap(this->members_.m_repr, other.members_.m_repr);
+ }
+ else{
+ repr_t copied(this->members_.m_repr);
+ this->members_.m_repr.long_repr() = other.members_.m_repr.long_repr();
+ other.members_.m_repr = copied;
+ }
+ }
+ else{
+ if(other.is_short()){
+ repr_t copied(other.members_.m_repr);
+ other.members_.m_repr.long_repr() = this->members_.m_repr.long_repr();
+ this->members_.m_repr = copied;
+ }
+ else{
+ std::swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr());
+ }
+ }
+
+ allocator_type & this_al = this->alloc(), &other_al = other.alloc();
+ if(this_al != other_al){
+ detail::do_swap(this_al, other_al);
+ }
+ }
+};
+/// @endcond
+
+} //namespace detail {
+
+
+//! The basic_string class represents a Sequence of characters. It contains all the
+//! usual operations of a Sequence, and, additionally, it contains standard string
+//! operations such as search and concatenation.
+//!
+//! The basic_string class is parameterized by character type, and by that type's
+//! Character Traits.
+//!
+//! This class has performance characteristics very much like vector<>, meaning,
+//! for example, that it does not perform reference-count or copy-on-write, and that
+//! concatenation of two strings is an O(N) operation.
+//!
+//! Some of basic_string's member functions use an unusual method of specifying positions
+//! and ranges. In addition to the conventional method using iterators, many of
+//! basic_string's member functions use a single value pos of type size_type to represent a
+//! position (in which case the position is begin() + pos, and many of basic_string's
+//! member functions use two values, pos and n, to represent a range. In that case pos is
+//! the beginning of the range and n is its size. That is, the range is
+//! [begin() + pos, begin() + pos + n).
+//!
+//! Note that the C++ standard does not specify the complexity of basic_string operations.
+//! In this implementation, basic_string has performance characteristics very similar to
+//! those of vector: access to a single character is O(1), while copy and concatenation
+//! are O(N).
+//!
+//! In this implementation, begin(),
+//! end(), rbegin(), rend(), operator[], c_str(), and data() do not invalidate iterators.
+//! In this implementation, iterators are only invalidated by member functions that
+//! explicitly change the string's contents.
+template <class CharT, class Traits, class A>
+class basic_string
+ : private detail::basic_string_base<A>
+{
+ /// @cond
+ private:
+ typedef detail::basic_string_base<A> base_t;
+ static const typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars;
+
+ protected:
+ // A helper class to use a char_traits as a function object.
+
+ template <class Tr>
+ struct Eq_traits
+ : public std::binary_function<typename Tr::char_type,
+ typename Tr::char_type,
+ bool>
+ {
+ bool operator()(const typename Tr::char_type& x,
+ const typename Tr::char_type& y) const
+ { return Tr::eq(x, y); }
+ };
+
+ template <class Tr>
+ struct Not_within_traits
+ : public std::unary_function<typename Tr::char_type, bool>
+ {
+ typedef const typename Tr::char_type* Pointer;
+ const Pointer m_first;
+ const Pointer m_last;
+
+ Not_within_traits(Pointer f, Pointer l)
+ : m_first(f), m_last(l) {}
+
+ bool operator()(const typename Tr::char_type& x) const
+ {
+ return std::find_if(m_first, m_last,
+ std::bind1st(Eq_traits<Tr>(), x)) == m_last;
+ }
+ };
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(basic_string)
+
+ //! The allocator type
+ typedef A allocator_type;
+ //! The stored allocator type
+ typedef allocator_type stored_allocator_type;
+ //! The type of object, CharT, stored in the string
+ typedef CharT value_type;
+ //! The second template parameter Traits
+ typedef Traits traits_type;
+ //! Pointer to CharT
+ typedef typename A::pointer pointer;
+ //! Const pointer to CharT
+ typedef typename A::const_pointer const_pointer;
+ //! Reference to CharT
+ typedef typename A::reference reference;
+ //! Const reference to CharT
+ typedef typename A::const_reference const_reference;
+ //! An unsigned integral type
+ typedef typename A::size_type size_type;
+ //! A signed integral type
+ typedef typename A::difference_type difference_type;
+ //! Iterator used to iterate through a string. It's a Random Access Iterator
+ typedef pointer iterator;
+ //! Const iterator used to iterate through a string. It's a Random Access Iterator
+ typedef const_pointer const_iterator;
+ //! Iterator used to iterate backwards through a string
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ //! Const iterator used to iterate backwards through a string
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ //! The largest possible value of type size_type. That is, size_type(-1).
+ static const size_type npos;
+
+ /// @cond
+ private:
+ typedef constant_iterator<CharT, difference_type> cvalue_iterator;
+ /// @endcond
+
+ public: // Constructor, destructor, assignment.
+ /// @cond
+ struct reserve_t {};
+ /// @endcond
+
+ basic_string(reserve_t, std::size_t n,
+ const allocator_type& a = allocator_type())
+ : base_t(a, n + 1)
+ { this->priv_terminate_string(); }
+
+ //! <b>Effects</b>: Constructs a basic_string taking the allocator as parameter.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ explicit basic_string(const allocator_type& a = allocator_type())
+ : base_t(a, InternalBufferChars)
+ { this->priv_terminate_string(); }
+
+ //! <b>Effects</b>: Copy constructs a basic_string.
+ //!
+ //! <b>Postcondition</b>: x == *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor throws.
+ basic_string(const basic_string& s)
+ : base_t(s.alloc())
+ { this->priv_range_initialize(s.begin(), s.end()); }
+
+ //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_string(boost::rv<basic_string> &s)
+ : base_t(boost::move((base_t&)s.get()))
+ {}
+ #else
+ basic_string(basic_string && s)
+ : base_t(boost::move((base_t&)s))
+ {}
+ #endif
+
+ //! <b>Effects</b>: Constructs a basic_string taking the allocator as parameter,
+ //! and is initialized by a specific number of characters of the s string.
+ basic_string(const basic_string& s, size_type pos, size_type n = npos,
+ const allocator_type& a = allocator_type())
+ : base_t(a)
+ {
+ if (pos > s.size())
+ this->throw_out_of_range();
+ else
+ this->priv_range_initialize
+ (s.begin() + pos, s.begin() + pos + min_value(n, s.size() - pos));
+ }
+
+ //! <b>Effects</b>: Constructs a basic_string taking the allocator as parameter,
+ //! and is initialized by a specific number of characters of the s c-string.
+ basic_string(const CharT* s, size_type n,
+ const allocator_type& a = allocator_type())
+ : base_t(a)
+ { this->priv_range_initialize(s, s + n); }
+
+ //! <b>Effects</b>: Constructs a basic_string taking the allocator as parameter,
+ //! and is initialized by the null-terminated s c-string.
+ basic_string(const CharT* s,
+ const allocator_type& a = allocator_type())
+ : base_t(a)
+ { this->priv_range_initialize(s, s + Traits::length(s)); }
+
+ //! <b>Effects</b>: Constructs a basic_string taking the allocator as parameter,
+ //! and is initialized by n copies of c.
+ basic_string(size_type n, CharT c,
+ const allocator_type& a = allocator_type())
+ : base_t(a)
+ {
+ this->priv_range_initialize(cvalue_iterator(c, n),
+ cvalue_iterator());
+ }
+
+ //! <b>Effects</b>: Constructs a basic_string taking the allocator as parameter,
+ //! and a range of iterators.
+ template <class InputIterator>
+ basic_string(InputIterator f, InputIterator l,
+ const allocator_type& a = allocator_type())
+ : base_t(a)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InputIterator, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_initialize_dispatch(f, l, Result());
+ }
+
+ //! <b>Effects</b>: Destroys the basic_string. All used memory is deallocated.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ ~basic_string()
+ {}
+
+ //! <b>Effects</b>: Copy constructs a string.
+ //!
+ //! <b>Postcondition</b>: x == *this.
+ //!
+ //! <b>Complexity</b>: Linear to the elements x contains.
+ basic_string& operator=(const basic_string& s)
+ {
+ if (&s != this)
+ this->assign(s.begin(), s.end());
+ return *this;
+ }
+
+ //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_string& operator=(boost::rv<basic_string> &ms)
+ {
+ basic_string &s = ms.get();
+ if (&s != this){
+ this->swap(s);
+ }
+ return *this;
+ }
+ #else
+ basic_string& operator=(basic_string && ms)
+ {
+ basic_string &s = ms;
+ if (&s != this){
+ this->swap(s);
+ }
+ return *this;
+ }
+ #endif
+
+ //! <b>Effects</b>: Assignment from a null-terminated c-string.
+ basic_string& operator=(const CharT* s)
+ { return this->assign(s, s + Traits::length(s)); }
+
+ //! <b>Effects</b>: Assignment from character.
+ basic_string& operator=(CharT c)
+ { return this->assign(static_cast<size_type>(1), c); }
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return this->priv_addr(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return this->priv_addr(); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return this->priv_addr() + this->priv_size(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return this->priv_addr() + this->priv_size(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return reverse_iterator(this->priv_addr() + this->priv_size()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin() const
+ { return const_reverse_iterator(this->priv_addr() + this->priv_size()); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return reverse_iterator(this->priv_addr()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return const_reverse_iterator(this->priv_addr()); }
+
+ //! <b>Effects</b>: Returns a copy of the internal allocator.
+ //!
+ //! <b>Throws</b>: If allocator's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return this->alloc(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return this->priv_size(); }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type length() const
+ { return this->size(); }
+
+ //! <b>Effects</b>: Returns the largest possible size of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return base_t::max_size(); }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are copy constructed from x.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type n, CharT c)
+ {
+ if (n <= size())
+ this->erase(this->begin() + n, this->end());
+ else
+ this->append(n - this->size(), c);
+ }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are default constructed.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type n)
+ { resize(n, this->priv_null()); }
+
+ //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
+ //! effect. Otherwise, it is a request for allocation of additional memory.
+ //! If the request is successful, then capacity() is greater than or equal to
+ //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
+ //!
+ //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
+ void reserve(size_type res_arg)
+ {
+ if (res_arg > this->max_size())
+ this->throw_length_error();
+
+ if (this->capacity() < res_arg){
+ size_type n = max_value(res_arg, this->size()) + 1;
+ size_type new_cap = this->next_capacity(n);
+ pointer new_start = this->allocation_command
+ (allocate_new, n, new_cap, new_cap).first;
+ size_type new_length = 0;
+
+ new_length += priv_uninitialized_copy
+ (this->priv_addr(), this->priv_addr() + this->priv_size(), new_start);
+ this->priv_construct_null(new_start + new_length);
+ this->deallocate_block();
+ this->is_short(false);
+ this->priv_addr(new_start);
+ this->priv_size(new_length);
+ this->priv_storage(new_cap);
+ }
+ }
+
+ //! <b>Effects</b>: Number of elements for which memory has been allocated.
+ //! capacity() is always greater than or equal to size().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type capacity() const
+ { return this->priv_capacity(); }
+
+ //! <b>Effects</b>: Erases all the elements of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in the vector.
+ void clear()
+ {
+ if (!empty()) {
+ Traits::assign(*this->priv_addr(), this->priv_null());
+ this->priv_size(0);
+ }
+ }
+
+ //! <b>Effects</b>: Returns true if the vector contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return !this->priv_size(); }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference operator[](size_type n)
+ { return *(this->priv_addr() + n); }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a const reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference operator[](size_type n) const
+ { return *(this->priv_addr() + n); }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: std::range_error if n >= size()
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference at(size_type n) {
+ if (n >= size())
+ this->throw_out_of_range();
+ return *(this->priv_addr() + n);
+ }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a const reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: std::range_error if n >= size()
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference at(size_type n) const {
+ if (n >= size())
+ this->throw_out_of_range();
+ return *(this->priv_addr() + n);
+ }
+
+ //! <b>Effects</b>: Appends string s to *this.
+ basic_string& operator+=(const basic_string& s)
+ { return this->append(s); }
+
+ //! <b>Effects</b>: Appends c-string s to *this.
+ basic_string& operator+=(const CharT* s)
+ { return this->append(s); }
+
+ //! <b>Effects</b>: Appends character c to *this.
+ basic_string& operator+=(CharT c)
+ { this->push_back(c); return *this; }
+
+ //! <b>Effects</b>: Appends string s to *this.
+ basic_string& append(const basic_string& s)
+ { return this->append(s.begin(), s.end()); }
+
+ //! <b>Effects</b>: Appends the range [pos, pos + n) from string s to *this.
+ basic_string& append(const basic_string& s, size_type pos, size_type n)
+ {
+ if (pos > s.size())
+ this->throw_out_of_range();
+ return this->append(s.begin() + pos,
+ s.begin() + pos + min_value(n, s.size() - pos));
+ }
+
+ //! <b>Effects</b>: Appends the range [s, s + n) from c-string s to *this.
+ basic_string& append(const CharT* s, size_type n)
+ { return this->append(s, s + n); }
+
+ //! <b>Effects</b>: Appends the c-string s to *this.
+ basic_string& append(const CharT* s)
+ { return this->append(s, s + Traits::length(s)); }
+
+ //! <b>Effects</b>: Appends the n times the character c to *this.
+ basic_string& append(size_type n, CharT c)
+ { return this->append(cvalue_iterator(c, n), cvalue_iterator()); }
+
+ //! <b>Effects</b>: Appends the range [first, last) *this.
+ template <class InputIter>
+ basic_string& append(InputIter first, InputIter last)
+ { this->insert(this->end(), first, last); return *this; }
+
+ //! <b>Effects</b>: Inserts a copy of c at the end of the vector.
+ void push_back(CharT c)
+ {
+ if (this->priv_size() < this->capacity()){
+ this->priv_construct_null(this->priv_addr() + (this->priv_size() + 1));
+ Traits::assign(this->priv_addr()[this->priv_size()], c);
+ this->priv_size(this->priv_size()+1);
+ }
+ else{
+ //No enough memory, insert a new object at the end
+ this->append((size_type)1, c);
+ }
+ }
+
+ //! <b>Effects</b>: Removes the last element from the vector.
+ void pop_back()
+ {
+ Traits::assign(this->priv_addr()[this->priv_size()-1], this->priv_null());
+ this->priv_size(this->priv_size()-1);;
+ }
+
+ //! <b>Effects</b>: Assigns the value s to *this.
+ basic_string& assign(const basic_string& s)
+ { return this->operator=(s); }
+
+ //! <b>Effects</b>: Moves the resources from ms *this.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_string& assign(boost::rv<basic_string> &ms)
+ { return this->operator=(ms);}
+ #else
+ basic_string& assign(basic_string && ms)
+ { return this->operator=(ms);}
+ #endif
+
+ //! <b>Effects</b>: Assigns the range [pos, pos + n) from s to *this.
+ basic_string& assign(const basic_string& s,
+ size_type pos, size_type n) {
+ if (pos > s.size())
+ this->throw_out_of_range();
+ return this->assign(s.begin() + pos,
+ s.begin() + pos + min_value(n, s.size() - pos));
+ }
+
+ //! <b>Effects</b>: Assigns the range [s, s + n) from s to *this.
+ basic_string& assign(const CharT* s, size_type n)
+ { return this->assign(s, s + n); }
+
+ //! <b>Effects</b>: Assigns the c-string s to *this.
+ basic_string& assign(const CharT* s)
+ { return this->assign(s, s + Traits::length(s)); }
+
+ //! <b>Effects</b>: Assigns the character c n-times to *this.
+ basic_string& assign(size_type n, CharT c)
+ { return this->assign(cvalue_iterator(c, n), cvalue_iterator()); }
+
+ //! <b>Effects</b>: Assigns the range [first, last) to *this.
+ template <class InputIter>
+ basic_string& assign(InputIter first, InputIter last)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InputIter, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ return this->priv_assign_dispatch(first, last, Result());
+ }
+
+ //! <b>Effects</b>: Assigns the range [f, l) to *this.
+ basic_string& assign(const CharT* f, const CharT* l)
+ {
+ const std::ptrdiff_t n = l - f;
+ if (static_cast<size_type>(n) <= size()) {
+ Traits::copy(detail::get_pointer(this->priv_addr()), f, n);
+ this->erase(this->priv_addr() + n, this->priv_addr() + this->priv_size());
+ }
+ else {
+ Traits::copy(detail::get_pointer(this->priv_addr()), f, this->priv_size());
+ this->append(f + this->priv_size(), l);
+ }
+ return *this;
+ }
+
+ //! <b>Effects</b>: Inserts the string s before pos.
+ basic_string& insert(size_type pos, const basic_string& s)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ if (this->size() > this->max_size() - s.size())
+ this->throw_length_error();
+ this->insert(this->priv_addr() + pos, s.begin(), s.end());
+ return *this;
+ }
+
+ //! <b>Effects</b>: Inserts the range [pos, pos + n) from string s before pos.
+ basic_string& insert(size_type pos, const basic_string& s,
+ size_type beg, size_type n)
+ {
+ if (pos > this->size() || beg > s.size())
+ this->throw_out_of_range();
+ size_type len = min_value(n, s.size() - beg);
+ if (this->size() > this->max_size() - len)
+ this->throw_length_error();
+ const CharT *beg_ptr = detail::get_pointer(s.begin()) + beg;
+ const CharT *end_ptr = beg_ptr + len;
+ this->insert(this->priv_addr() + pos, beg_ptr, end_ptr);
+ return *this;
+ }
+
+ //! <b>Effects</b>: Inserts the range [s, s + n) before pos.
+ basic_string& insert(size_type pos, const CharT* s, size_type n)
+ {
+ if (pos > this->size())
+ this->throw_out_of_range();
+ if (this->size() > this->max_size() - n)
+ this->throw_length_error();
+ this->insert(this->priv_addr() + pos, s, s + n);
+ return *this;
+ }
+
+ //! <b>Effects</b>: Inserts the c-string s before pos.
+ basic_string& insert(size_type pos, const CharT* s)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ size_type len = Traits::length(s);
+ if (this->size() > this->max_size() - len)
+ this->throw_length_error();
+ this->insert(this->priv_addr() + pos, s, s + len);
+ return *this;
+ }
+
+ //! <b>Effects</b>: Inserts the character c n-times before pos.
+ basic_string& insert(size_type pos, size_type n, CharT c)
+ {
+ if (pos > this->size())
+ this->throw_out_of_range();
+ if (this->size() > this->max_size() - n)
+ this->throw_length_error();
+ this->insert(this->priv_addr() + pos, n, c);
+ return *this;
+ }
+
+ //! <b>Effects</b>: Inserts the character c before position.
+ iterator insert(iterator position, CharT c)
+ {
+ size_type new_offset = position - this->priv_addr() + 1;
+ this->insert(position, cvalue_iterator(c, 1),
+ cvalue_iterator());
+ return this->priv_addr() + new_offset;
+ }
+
+ //! <b>Effects</b>: Inserts the character c n-times before position.
+ void insert(iterator position, std::size_t n, CharT c)
+ {
+ this->insert(position, cvalue_iterator(c, n),
+ cvalue_iterator());
+ }
+
+ //! <b>Effects</b>: Inserts the range [first, last) before position.
+ template <class InputIter>
+ void insert(iterator p, InputIter first, InputIter last)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InputIter, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_insert_dispatch(p, first, last, Result());
+ }
+
+ //! <b>Effects</b>: Inserts the range [pos, pos + n).
+ basic_string& erase(size_type pos = 0, size_type n = npos)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ erase(this->priv_addr() + pos, this->priv_addr() + pos + min_value(n, size() - pos));
+ return *this;
+ }
+
+ //! <b>Effects</b>: Erases the character pointed by position.
+ iterator erase(iterator position)
+ {
+ // The move includes the terminating null.
+ Traits::move(detail::get_pointer(position),
+ detail::get_pointer(position + 1),
+ this->priv_size() - (position - this->priv_addr()));
+ this->priv_size(this->priv_size()-1);
+ return position;
+ }
+
+ //! <b>Effects</b>: Erases the range [first, last).
+ iterator erase(iterator first, iterator last)
+ {
+ if (first != last) { // The move includes the terminating null.
+ size_type num_erased = last - first;
+ Traits::move(detail::get_pointer(first),
+ detail::get_pointer(last),
+ (this->priv_size() + 1)-(last - this->priv_addr()));
+ size_type new_length = this->priv_size() - num_erased;
+ this->priv_size(new_length);
+ }
+ return first;
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with the string s.
+ basic_string& replace(size_type pos, size_type n,
+ const basic_string& s)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ const size_type len = min_value(n, size() - pos);
+ if (this->size() - len >= this->max_size() - s.size())
+ this->throw_length_error();
+ return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len,
+ s.begin(), s.end());
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with a substring of s.
+ basic_string& replace(size_type pos1, size_type n1,
+ const basic_string& s,
+ size_type pos2, size_type n2)
+ {
+ if (pos1 > size() || pos2 > s.size())
+ this->throw_out_of_range();
+ const size_type len1 = min_value(n1, size() - pos1);
+ const size_type len2 = min_value(n2, s.size() - pos2);
+ if (this->size() - len1 >= this->max_size() - len2)
+ this->throw_length_error();
+ return this->replace(this->priv_addr() + pos1, this->priv_addr() + pos1 + len1,
+ s.priv_addr() + pos2, s.priv_addr() + pos2 + len2);
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with the first n1 characters of s.
+ basic_string& replace(size_type pos, size_type n1,
+ const CharT* s, size_type n2)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ const size_type len = min_value(n1, size() - pos);
+ if (n2 > this->max_size() || size() - len >= this->max_size() - n2)
+ this->throw_length_error();
+ return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len,
+ s, s + n2);
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with a null-terminated character array.
+ basic_string& replace(size_type pos, size_type n1,
+ const CharT* s)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ const size_type len = min_value(n1, size() - pos);
+ const size_type n2 = Traits::length(s);
+ if (n2 > this->max_size() || size() - len >= this->max_size() - n2)
+ this->throw_length_error();
+ return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len,
+ s, s + Traits::length(s));
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with n1 copies of c.
+ basic_string& replace(size_type pos, size_type n1,
+ size_type n2, CharT c)
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ const size_type len = min_value(n1, size() - pos);
+ if (n2 > this->max_size() || size() - len >= this->max_size() - n2)
+ this->throw_length_error();
+ return this->replace(this->priv_addr() + pos, this->priv_addr() + pos + len, n2, c);
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with the string s.
+ basic_string& replace(iterator first, iterator last,
+ const basic_string& s)
+ { return this->replace(first, last, s.begin(), s.end()); }
+
+ //! <b>Effects</b>: Replaces a substring of *this with the first n characters of s.
+ basic_string& replace(iterator first, iterator last,
+ const CharT* s, size_type n)
+ { return this->replace(first, last, s, s + n); }
+
+ //! <b>Effects</b>: Replaces a substring of *this with a null-terminated character array.
+ basic_string& replace(iterator first, iterator last,
+ const CharT* s)
+ { return this->replace(first, last, s, s + Traits::length(s)); }
+
+ //! <b>Effects</b>: Replaces a substring of *this with n copies of c.
+ basic_string& replace(iterator first, iterator last,
+ size_type n, CharT c)
+ {
+ const size_type len = static_cast<size_type>(last - first);
+ if (len >= n) {
+ Traits::assign(detail::get_pointer(first), n, c);
+ erase(first + n, last);
+ }
+ else {
+ Traits::assign(detail::get_pointer(first), len, c);
+ insert(last, n - len, c);
+ }
+ return *this;
+ }
+
+ //! <b>Effects</b>: Replaces a substring of *this with the range [f, l)
+ template <class InputIter>
+ basic_string& replace(iterator first, iterator last,
+ InputIter f, InputIter l)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InputIter, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ return this->priv_replace_dispatch(first, last, f, l, Result());
+ }
+
+ //! <b>Effects</b>: Copies a substring of *this to a buffer.
+ size_type copy(CharT* s, size_type n, size_type pos = 0) const
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ const size_type len = min_value(n, size() - pos);
+ Traits::copy(s, detail::get_pointer(this->priv_addr() + pos), len);
+ return len;
+ }
+
+ //! <b>Effects</b>: Swaps the contents of two strings.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_string> &x)
+ { this->swap(x.get()); }
+ void swap(basic_string& x)
+ #else
+ void swap(basic_string &&x)
+ #endif
+ { base_t::swap(x); }
+
+ //! <b>Returns</b>: Returns a pointer to a null-terminated array of characters
+ //! representing the string's contents. For any string s it is guaranteed
+ //! that the first s.size() characters in the array pointed to by s.c_str()
+ //! are equal to the character in s, and that s.c_str()[s.size()] is a null
+ //! character. Note, however, that it not necessarily the first null character.
+ //! Characters within a string are permitted to be null.
+ const CharT* c_str() const
+ { return detail::get_pointer(this->priv_addr()); }
+
+ //! <b>Returns</b>: Returns a pointer to an array of characters, not necessarily
+ //! null-terminated, representing the string's contents. data() is permitted,
+ //! but not required, to be identical to c_str(). The first size() characters
+ //! of that array are guaranteed to be identical to the characters in *this.
+ //! The return value of data() is never a null pointer, even if size() is zero.
+ const CharT* data() const
+ { return detail::get_pointer(this->priv_addr()); }
+
+ //! <b>Effects</b>: Searches for s as a substring of *this, beginning at
+ //! character pos of *this.
+ size_type find(const basic_string& s, size_type pos = 0) const
+ { return find(s.c_str(), pos, s.size()); }
+
+ //! <b>Effects</b>: Searches for a null-terminated character array as a
+ //! substring of *this, beginning at character pos of *this.
+ size_type find(const CharT* s, size_type pos = 0) const
+ { return find(s, pos, Traits::length(s)); }
+
+ //! <b>Effects</b>: Searches for the first n characters of s as a substring
+ //! of *this, beginning at character pos of *this.
+ size_type find(const CharT* s, size_type pos, size_type n) const
+ {
+ if (pos + n > size())
+ return npos;
+ else {
+ pointer finish = this->priv_addr() + this->priv_size();
+ const const_iterator result =
+ std::search(detail::get_pointer(this->priv_addr() + pos),
+ detail::get_pointer(finish),
+ s, s + n, Eq_traits<Traits>());
+ return result != finish ? result - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches for the character c, beginning at character
+ //! position pos.
+ size_type find(CharT c, size_type pos = 0) const
+ {
+ if (pos >= size())
+ return npos;
+ else {
+ pointer finish = this->priv_addr() + this->priv_size();
+ const const_iterator result =
+ std::find_if(this->priv_addr() + pos, finish,
+ std::bind2nd(Eq_traits<Traits>(), c));
+ return result != finish ? result - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches backward for s as a substring of *this,
+ //! beginning at character position min(pos, size())
+ size_type rfind(const basic_string& s, size_type pos = npos) const
+ { return rfind(s.c_str(), pos, s.size()); }
+
+ //! <b>Effects</b>: Searches backward for a null-terminated character array
+ //! as a substring of *this, beginning at character min(pos, size())
+ size_type rfind(const CharT* s, size_type pos = npos) const
+ { return rfind(s, pos, Traits::length(s)); }
+
+ //! <b>Effects</b>: Searches backward for the first n characters of s as a
+ //! substring of *this, beginning at character position min(pos, size()).
+ size_type rfind(const CharT* s, size_type pos, size_type n) const
+ {
+ const std::size_t len = size();
+
+ if (n > len)
+ return npos;
+ else if (n == 0)
+ return min_value(len, pos);
+ else {
+ const const_iterator last = begin() + min_value(len - n, pos) + n;
+ const const_iterator result = find_end(begin(), last,
+ s, s + n,
+ Eq_traits<Traits>());
+ return result != last ? result - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches backward for a null-terminated character array
+ //! as a substring of *this, beginning at character min(pos, size()).
+ size_type rfind(CharT c, size_type pos = npos) const
+ {
+ const size_type len = size();
+
+ if (len < 1)
+ return npos;
+ else {
+ const const_iterator last = begin() + min_value(len - 1, pos) + 1;
+ const_reverse_iterator rresult =
+ std::find_if(const_reverse_iterator(last), rend(),
+ std::bind2nd(Eq_traits<Traits>(), c));
+ return rresult != rend() ? (rresult.base() - 1) - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is equal to any character within s.
+ size_type find_first_of(const basic_string& s, size_type pos = 0) const
+ { return find_first_of(s.c_str(), pos, s.size()); }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is equal to any character within s.
+ size_type find_first_of(const CharT* s, size_type pos = 0) const
+ { return find_first_of(s, pos, Traits::length(s)); }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is equal to any character within the first n characters of s.
+ size_type find_first_of(const CharT* s, size_type pos,
+ size_type n) const
+ {
+ if (pos >= size())
+ return npos;
+ else {
+ pointer finish = this->priv_addr() + this->priv_size();
+ const_iterator result = std::find_first_of(this->priv_addr() + pos, finish,
+ s, s + n,
+ Eq_traits<Traits>());
+ return result != finish ? result - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is equal to c.
+ size_type find_first_of(CharT c, size_type pos = 0) const
+ { return find(c, pos); }
+
+ //! <b>Effects</b>: Searches backward within *this, beginning at min(pos, size()),
+ //! for the first character that is equal to any character within s.
+ size_type find_last_of(const basic_string& s,
+ size_type pos = npos) const
+ { return find_last_of(s.c_str(), pos, s.size()); }
+
+ //! <b>Effects</b>: Searches backward *this, beginning at min(pos, size()), for
+ //! the first character that is equal to any character within s.
+ size_type find_last_of(const CharT* s, size_type pos = npos) const
+ { return find_last_of(s, pos, Traits::length(s)); }
+
+ //! <b>Effects</b>: Searches backward within *this, beginning at min(pos, size()),
+ //! for the first character that is equal to any character within the first n
+ //! characters of s.
+ size_type find_last_of(const CharT* s, size_type pos, size_type n) const
+ {
+ const size_type len = size();
+
+ if (len < 1)
+ return npos;
+ else {
+ const const_iterator last = this->priv_addr() + min_value(len - 1, pos) + 1;
+ const const_reverse_iterator rresult =
+ std::find_first_of(const_reverse_iterator(last), rend(),
+ s, s + n,
+ Eq_traits<Traits>());
+ return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches backward *this, beginning at min(pos, size()), for
+ //! the first character that is equal to c.
+ size_type find_last_of(CharT c, size_type pos = npos) const
+ { return rfind(c, pos); }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is not equal to any character within s.
+ size_type find_first_not_of(const basic_string& s,
+ size_type pos = 0) const
+ { return find_first_not_of(s.c_str(), pos, s.size()); }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is not equal to any character within s.
+ size_type find_first_not_of(const CharT* s, size_type pos = 0) const
+ { return find_first_not_of(s, pos, Traits::length(s)); }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is not equal to any character within the first n
+ //! characters of s.
+ size_type find_first_not_of(const CharT* s, size_type pos,
+ size_type n) const
+ {
+ if (pos > size())
+ return npos;
+ else {
+ pointer finish = this->priv_addr() + this->priv_size();
+ const_iterator result = std::find_if(this->priv_addr() + pos, finish,
+ Not_within_traits<Traits>(s, s + n));
+ return result != finish ? result - this->priv_addr() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches within *this, beginning at pos, for the first
+ //! character that is not equal to c.
+ size_type find_first_not_of(CharT c, size_type pos = 0) const
+ {
+ if (pos > size())
+ return npos;
+ else {
+ pointer finish = this->priv_addr() + this->priv_size();
+ const_iterator result
+ = std::find_if(this->priv_addr() + pos, finish,
+ std::not1(std::bind2nd(Eq_traits<Traits>(), c)));
+ return result != finish ? result - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches backward within *this, beginning at min(pos, size()),
+ //! for the first character that is not equal to any character within s.
+ size_type find_last_not_of(const basic_string& s,
+ size_type pos = npos) const
+ { return find_last_not_of(s.c_str(), pos, s.size()); }
+
+ //! <b>Effects</b>: Searches backward *this, beginning at min(pos, size()),
+ //! for the first character that is not equal to any character within s.
+ size_type find_last_not_of(const CharT* s, size_type pos = npos) const
+ { return find_last_not_of(s, pos, Traits::length(s)); }
+
+ //! <b>Effects</b>: Searches backward within *this, beginning at min(pos, size()),
+ //! for the first character that is not equal to any character within the first
+ //! n characters of s.
+ size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const
+ {
+ const size_type len = size();
+
+ if (len < 1)
+ return npos;
+ else {
+ const const_iterator last = begin() + min_value(len - 1, pos) + 1;
+ const const_reverse_iterator rresult =
+ std::find_if(const_reverse_iterator(last), rend(),
+ Not_within_traits<Traits>(s, s + n));
+ return rresult != rend() ? (rresult.base() - 1) - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Searches backward *this, beginning at min(pos, size()),
+ //! for the first character that is not equal to c.
+ size_type find_last_not_of(CharT c, size_type pos = npos) const
+ {
+ const size_type len = size();
+
+ if (len < 1)
+ return npos;
+ else {
+ const const_iterator last = begin() + min_value(len - 1, pos) + 1;
+ const_reverse_iterator rresult =
+ std::find_if(const_reverse_iterator(last), rend(),
+ std::not1(std::bind2nd(Eq_traits<Traits>(), c)));
+ return rresult != rend() ? (rresult.base() - 1) - begin() : npos;
+ }
+ }
+
+ //! <b>Effects</b>: Returns a substring of *this.
+ basic_string substr(size_type pos = 0, size_type n = npos) const
+ {
+ if (pos > size())
+ this->throw_out_of_range();
+ return basic_string(this->priv_addr() + pos,
+ this->priv_addr() + pos + min_value(n, size() - pos), this->alloc());
+ }
+
+ //! <b>Effects</b>: Three-way lexicographical comparison of s and *this.
+ int compare(const basic_string& s) const
+ { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s.priv_addr(), s.priv_addr() + s.priv_size()); }
+
+ //! <b>Effects</b>: Three-way lexicographical comparison of s and a substring
+ //! of *this.
+ int compare(size_type pos1, size_type n1, const basic_string& s) const
+ {
+ if (pos1 > size())
+ this->throw_out_of_range();
+ return s_compare(this->priv_addr() + pos1,
+ this->priv_addr() + pos1 + min_value(n1, size() - pos1),
+ s.priv_addr(), s.priv_addr() + s.priv_size());
+ }
+
+ //! <b>Effects</b>: Three-way lexicographical comparison of a substring of s
+ //! and a substring of *this.
+ int compare(size_type pos1, size_type n1,
+ const basic_string& s,
+ size_type pos2, size_type n2) const {
+ if (pos1 > size() || pos2 > s.size())
+ this->throw_out_of_range();
+ return s_compare(this->priv_addr() + pos1,
+ this->priv_addr() + pos1 + min_value(n1, size() - pos1),
+ s.priv_addr() + pos2,
+ s.priv_addr() + pos2 + min_value(n2, size() - pos2));
+ }
+
+ //! <b>Effects</b>: Three-way lexicographical comparison of s and *this.
+ int compare(const CharT* s) const
+ { return s_compare(this->priv_addr(), this->priv_addr() + this->priv_size(), s, s + Traits::length(s)); }
+
+
+ //! <b>Effects</b>: Three-way lexicographical comparison of the first
+ //! min(len, traits::length(s) characters of s and a substring of *this.
+ int compare(size_type pos1, size_type n1, const CharT* s,
+ size_type n2 = npos) const
+ {
+ if (pos1 > size())
+ this->throw_out_of_range();
+ return s_compare(this->priv_addr() + pos1,
+ this->priv_addr() + pos1 + min_value(n1, size() - pos1),
+ s, s + n2);
+ }
+
+ /// @cond
+ private:
+ static int s_compare(const_pointer f1, const_pointer l1,
+ const_pointer f2, const_pointer l2)
+ {
+ const std::ptrdiff_t n1 = l1 - f1;
+ const std::ptrdiff_t n2 = l2 - f2;
+ const int cmp = Traits::compare(detail::get_pointer(f1),
+ detail::get_pointer(f2),
+ min_value(n1, n2));
+ return cmp != 0 ? cmp : (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0));
+ }
+
+ void priv_construct_null(pointer p)
+ { this->construct(p, 0); }
+
+ static CharT priv_null()
+ { return (CharT) 0; }
+
+ // Helper functions used by constructors. It is a severe error for
+ // any of them to be called anywhere except from within constructors.
+ void priv_terminate_string()
+ { this->priv_construct_null(this->priv_addr() + this->priv_size()); }
+
+ template <class InputIter>
+ void priv_range_initialize(InputIter f, InputIter l,
+ std::input_iterator_tag)
+ {
+ this->allocate_initial_block(InternalBufferChars);
+ this->priv_construct_null(this->priv_addr() + this->priv_size());
+ this->append(f, l);
+ }
+
+ template <class ForwardIter>
+ void priv_range_initialize(ForwardIter f, ForwardIter l,
+ std::forward_iterator_tag)
+ {
+ difference_type n = std::distance(f, l);
+ this->allocate_initial_block(max_value<difference_type>(n+1, InternalBufferChars));
+ priv_uninitialized_copy(f, l, this->priv_addr());
+ this->priv_size(n);
+ this->priv_terminate_string();
+ }
+
+ template <class InputIter>
+ void priv_range_initialize(InputIter f, InputIter l)
+ {
+ typedef typename std::iterator_traits<InputIter>::iterator_category Category;
+ this->priv_range_initialize(f, l, Category());
+ }
+
+ template <class Integer>
+ void priv_initialize_dispatch(Integer n, Integer x, detail::true_)
+ {
+ this->allocate_initial_block(max_value<difference_type>(n+1, InternalBufferChars));
+ priv_uninitialized_fill_n(this->priv_addr(), n, x);
+ this->priv_size(n);
+ this->priv_terminate_string();
+ }
+
+ template <class InputIter>
+ void priv_initialize_dispatch(InputIter f, InputIter l, detail::false_)
+ { this->priv_range_initialize(f, l); }
+
+ template<class FwdIt, class Count> inline
+ void priv_uninitialized_fill_n(FwdIt first, Count count, const CharT val)
+ {
+ //Save initial position
+ FwdIt init = first;
+
+ BOOST_TRY{
+ //Construct objects
+ for (; count--; ++first){
+ this->construct(first, val);
+ }
+ }
+ BOOST_CATCH(...){
+ //Call destructors
+ for (; init != first; ++init){
+ this->destroy(init);
+ }
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ template<class InpIt, class FwdIt> inline
+ size_type priv_uninitialized_copy(InpIt first, InpIt last, FwdIt dest)
+ {
+ //Save initial destination position
+ FwdIt dest_init = dest;
+ size_type constructed = 0;
+
+ BOOST_TRY{
+ //Try to build objects
+ for (; first != last; ++dest, ++first, ++constructed){
+ this->construct(dest, *first);
+ }
+ }
+ BOOST_CATCH(...){
+ //Call destructors
+ for (; constructed--; ++dest_init){
+ this->destroy(dest_init);
+ }
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ return (constructed);
+ }
+
+ template <class Integer>
+ basic_string& priv_assign_dispatch(Integer n, Integer x, detail::true_)
+ { return this->assign((size_type) n, (CharT) x); }
+
+ template <class InputIter>
+ basic_string& priv_assign_dispatch(InputIter f, InputIter l,
+ detail::false_)
+ {
+ size_type cur = 0;
+ CharT *ptr = detail::get_pointer(this->priv_addr());
+ while (f != l && cur != this->priv_size()) {
+ Traits::assign(*ptr, *f);
+ ++f;
+ ++cur;
+ ++ptr;
+ }
+ if (f == l)
+ this->erase(this->priv_addr() + cur, this->priv_addr() + this->priv_size());
+ else
+ this->append(f, l);
+ return *this;
+ }
+
+ template <class InputIter>
+ void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag)
+ {
+ for ( ; first != last; ++first, ++p) {
+ p = this->insert(p, *first);
+ }
+ }
+
+ template <class ForwardIter>
+ void priv_insert(iterator position, ForwardIter first,
+ ForwardIter last, std::forward_iterator_tag)
+ {
+ if (first != last) {
+ size_type n = std::distance(first, last);
+ size_type remaining = this->capacity() - this->priv_size();
+ const size_type old_size = this->size();
+ pointer old_start = this->priv_addr();
+ bool enough_capacity = false;
+ std::pair<pointer, bool> allocation_ret;
+ size_type new_cap = 0;
+
+ //Check if we have enough capacity
+ if (remaining >= n){
+ enough_capacity = true;
+ }
+ else {
+ //Otherwise expand current buffer or allocate new storage
+ new_cap = this->next_capacity(n);
+ allocation_ret = this->allocation_command
+ (allocate_new | expand_fwd | expand_bwd, old_size + n + 1,
+ new_cap, new_cap, old_start);
+
+ //Check forward expansion
+ if(old_start == allocation_ret.first){
+ enough_capacity = true;
+ this->priv_storage(new_cap);
+ }
+ }
+
+ //Reuse same buffer
+ if(enough_capacity){
+ const size_type elems_after =
+ this->priv_size() - (position - this->priv_addr());
+ size_type old_length = this->priv_size();
+ if (elems_after >= n) {
+ pointer pointer_past_last = this->priv_addr() + this->priv_size() + 1;
+ priv_uninitialized_copy(this->priv_addr() + (this->priv_size() - n + 1),
+ pointer_past_last, pointer_past_last);
+
+ this->priv_size(this->priv_size()+n);
+ Traits::move(detail::get_pointer(position + n),
+ detail::get_pointer(position),
+ (elems_after - n) + 1);
+ this->priv_copy(first, last, position);
+ }
+ else {
+ ForwardIter mid = first;
+ std::advance(mid, elems_after + 1);
+
+ priv_uninitialized_copy(mid, last, this->priv_addr() + this->priv_size() + 1);
+ this->priv_size(this->priv_size() + (n - elems_after));
+ priv_uninitialized_copy
+ (position, this->priv_addr() + old_length + 1,
+ this->priv_addr() + this->priv_size());
+ this->priv_size(this->priv_size() + elems_after);
+ this->priv_copy(first, mid, position);
+ }
+ }
+ else{
+ pointer new_start = allocation_ret.first;
+ if(!allocation_ret.second){
+ //Copy data to new buffer
+ size_type new_length = 0;
+ //This can't throw, since characters are POD
+ new_length += priv_uninitialized_copy
+ (this->priv_addr(), position, new_start);
+ new_length += priv_uninitialized_copy
+ (first, last, new_start + new_length);
+ new_length += priv_uninitialized_copy
+ (position, this->priv_addr() + this->priv_size(),
+ new_start + new_length);
+ this->priv_construct_null(new_start + new_length);
+
+ this->deallocate_block();
+ this->is_short(false);
+ this->priv_addr(new_start);
+ this->priv_size(new_length);
+ this->priv_storage(new_cap);
+ }
+ else{
+ //value_type is POD, so backwards expansion is much easier
+ //than with vector<T>
+ value_type *oldbuf = detail::get_pointer(old_start);
+ value_type *newbuf = detail::get_pointer(new_start);
+ value_type *pos = detail::get_pointer(position);
+ size_type before = pos - oldbuf;
+
+ //First move old data
+ Traits::move(newbuf, oldbuf, before);
+ Traits::move(newbuf + before + n, pos, old_size - before);
+ //Now initialize the new data
+ priv_uninitialized_copy(first, last, new_start + before);
+ this->priv_construct_null(new_start + (old_size + n));
+ this->is_short(false);
+ this->priv_addr(new_start);
+ this->priv_size(old_size + n);
+ this->priv_storage(new_cap);
+ }
+ }
+ }
+ }
+
+ template <class Integer>
+ void priv_insert_dispatch(iterator p, Integer n, Integer x,
+ detail::true_)
+ { insert(p, (size_type) n, (CharT) x); }
+
+ template <class InputIter>
+ void priv_insert_dispatch(iterator p, InputIter first, InputIter last,
+ detail::false_)
+ {
+ typedef typename std::iterator_traits<InputIter>::iterator_category Category;
+ priv_insert(p, first, last, Category());
+ }
+
+ template <class InputIterator>
+ void priv_copy(InputIterator first, InputIterator last, iterator result)
+ {
+ for ( ; first != last; ++first, ++result)
+ Traits::assign(*result, *first);
+ }
+
+ void priv_copy(const CharT* first, const CharT* last, CharT* result)
+ { Traits::copy(result, first, last - first); }
+
+ template <class Integer>
+ basic_string& priv_replace_dispatch(iterator first, iterator last,
+ Integer n, Integer x,
+ detail::true_)
+ { return this->replace(first, last, (size_type) n, (CharT) x); }
+
+ template <class InputIter>
+ basic_string& priv_replace_dispatch(iterator first, iterator last,
+ InputIter f, InputIter l,
+ detail::false_)
+ {
+ typedef typename std::iterator_traits<InputIter>::iterator_category Category;
+ return this->priv_replace(first, last, f, l, Category());
+ }
+
+
+ template <class InputIter>
+ basic_string& priv_replace(iterator first, iterator last,
+ InputIter f, InputIter l, std::input_iterator_tag)
+ {
+ for ( ; first != last && f != l; ++first, ++f)
+ Traits::assign(*first, *f);
+
+ if (f == l)
+ this->erase(first, last);
+ else
+ this->insert(last, f, l);
+ return *this;
+ }
+
+ template <class ForwardIter>
+ basic_string& priv_replace(iterator first, iterator last,
+ ForwardIter f, ForwardIter l,
+ std::forward_iterator_tag)
+ {
+ difference_type n = std::distance(f, l);
+ const difference_type len = last - first;
+ if (len >= n) {
+ this->priv_copy(f, l, first);
+ this->erase(first + n, last);
+ }
+ else {
+ ForwardIter m = f;
+ std::advance(m, len);
+ this->priv_copy(f, m, first);
+ this->insert(last, m, l);
+ }
+ return *this;
+ }
+ /// @endcond
+};
+
+template <class CharT, class Traits, class A>
+const typename basic_string<CharT,Traits,A>::size_type
+basic_string<CharT,Traits,A>::npos
+ = (typename basic_string<CharT,Traits,A>::size_type) -1;
+
+// ------------------------------------------------------------
+// Non-member functions.
+
+// Operator+
+
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A>
+operator+(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y)
+{
+ typedef basic_string<CharT,Traits,A> str_t;
+ typedef typename str_t::reserve_t reserve_t;
+ reserve_t reserve;
+ str_t result(reserve, x.size() + y.size(), x.alloc());
+ result.append(x);
+ result.append(y);
+ return result;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline boost::rv<basic_string<CharT,Traits,A> >&
+operator+(boost::rv<basic_string<CharT,Traits,A> > &mx,
+ const basic_string<CharT,Traits,A>& y)
+{
+ mx.get() += y;
+ return mx;
+}
+#else
+template <class CharT, class Traits, class A>
+basic_string<CharT,Traits,A> &&
+operator+(basic_string<CharT,Traits,A> && mx,
+ const basic_string<CharT,Traits,A>& y)
+{
+ mx += y;
+ return boost::move(mx);
+}
+#endif
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline boost::rv<basic_string<CharT,Traits,A> >&
+operator+(const basic_string<CharT,Traits,A>& x,
+ boost::rv<basic_string<CharT,Traits,A> > &my)
+{
+ typedef typename basic_string<CharT,Traits,A>::size_type size_type;
+ return my.get().replace(size_type(0), size_type(0), x);
+}
+#else
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A> &&
+operator+(const basic_string<CharT,Traits,A>& x,
+ basic_string<CharT,Traits,A> && my)
+{
+ typedef typename basic_string<CharT,Traits,A>::size_type size_type;
+ return my.replace(size_type(0), size_type(0), x);
+}
+#endif
+
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A>
+operator+(const CharT* s, const basic_string<CharT,Traits,A>& y)
+{
+ typedef basic_string<CharT,Traits,A> str_t;
+ typedef typename str_t::reserve_t reserve_t;
+ reserve_t reserve;
+ const std::size_t n = Traits::length(s);
+ str_t result(reserve, n + y.size());
+ result.append(s, s + n);
+ result.append(y);
+ return result;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline boost::rv<basic_string<CharT,Traits,A> >&
+operator+(const CharT* s,
+ boost::rv<basic_string<CharT,Traits,A> > &my)
+{
+ typedef typename basic_string<CharT,Traits,A>::size_type size_type;
+ return my.get().replace(size_type(0), size_type(0), s);
+}
+#else
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A> &&
+operator+(const CharT* s,
+ basic_string<CharT,Traits,A> && my)
+{
+ typedef typename basic_string<CharT,Traits,A>::size_type size_type;
+ return boost::move(my.get().replace(size_type(0), size_type(0), s));
+}
+#endif
+
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A>
+operator+(CharT c, const basic_string<CharT,Traits,A>& y)
+{
+ typedef basic_string<CharT,Traits,A> str_t;
+ typedef typename str_t::reserve_t reserve_t;
+ reserve_t reserve;
+ str_t result(reserve, 1 + y.size());
+ result.push_back(c);
+ result.append(y);
+ return result;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline boost::rv<basic_string<CharT,Traits,A> >&
+operator+(CharT c, boost::rv<basic_string<CharT,Traits,A> > &my)
+{
+ typedef typename basic_string<CharT,Traits,A>::size_type size_type;
+ return my.get().replace(size_type(0), size_type(0), &c, &c + 1);
+}
+#else
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A> &&
+operator+(CharT c,
+ basic_string<CharT,Traits,A> && my)
+{
+ typedef typename basic_string<CharT,Traits,A>::size_type size_type;
+ return my.replace(size_type(0), size_type(0), &c, &c + 1);
+}
+#endif
+
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A>
+operator+(const basic_string<CharT,Traits,A>& x, const CharT* s)
+{
+ typedef basic_string<CharT,Traits,A> str_t;
+ typedef typename str_t::reserve_t reserve_t;
+ reserve_t reserve;
+ const std::size_t n = Traits::length(s);
+ str_t result(reserve, x.size() + n, x.alloc());
+ result.append(x);
+ result.append(s, s + n);
+ return result;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline boost::rv<basic_string<CharT,Traits,A> >&
+operator+(boost::rv<basic_string<CharT,Traits,A> > &mx, const CharT* s)
+{
+ mx.get() += s;
+ return mx;
+}
+#else
+template <class CharT, class Traits, class A>
+basic_string<CharT,Traits,A> &&
+operator+(basic_string<CharT,Traits,A> && mx, const CharT* s)
+{
+ mx += s;
+ return boost::move(mx);
+}
+#endif
+
+template <class CharT, class Traits, class A>
+inline basic_string<CharT,Traits,A>
+operator+(const basic_string<CharT,Traits,A>& x, const CharT c)
+{
+ typedef basic_string<CharT,Traits,A> str_t;
+ typedef typename str_t::reserve_t reserve_t;
+ reserve_t reserve;
+ str_t result(reserve, x.size() + 1, x.alloc());
+ result.append(x);
+ result.push_back(c);
+ return result;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline boost::rv<basic_string<CharT,Traits,A> >&
+operator+(boost::rv<basic_string<CharT,Traits,A> > &mx, const CharT c)
+{
+ mx.get() += c;
+ return mx;
+}
+#else
+template <class CharT, class Traits, class A>
+basic_string<CharT,Traits,A> &&
+operator+(basic_string<CharT,Traits,A> && mx, const CharT c)
+{
+ mx += c;
+ return boost::move(mx);
+}
+#endif
+
+// Operator== and operator!=
+
+template <class CharT, class Traits, class A>
+inline bool
+operator==(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y)
+{
+ return x.size() == y.size() &&
+ Traits::compare(x.data(), y.data(), x.size()) == 0;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator==(const CharT* s, const basic_string<CharT,Traits,A>& y)
+{
+ std::size_t n = Traits::length(s);
+ return n == y.size() && Traits::compare(s, y.data(), n) == 0;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator==(const basic_string<CharT,Traits,A>& x, const CharT* s)
+{
+ std::size_t n = Traits::length(s);
+ return x.size() == n && Traits::compare(x.data(), s, n) == 0;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator!=(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y)
+ { return !(x == y); }
+
+template <class CharT, class Traits, class A>
+inline bool
+operator!=(const CharT* s, const basic_string<CharT,Traits,A>& y)
+ { return !(s == y); }
+
+template <class CharT, class Traits, class A>
+inline bool
+operator!=(const basic_string<CharT,Traits,A>& x, const CharT* s)
+ { return !(x == s); }
+
+
+// Operator< (and also >, <=, and >=).
+
+template <class CharT, class Traits, class A>
+inline bool
+operator<(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y)
+{
+ return x.compare(y) < 0;
+// return basic_string<CharT,Traits,A>
+// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator<(const CharT* s, const basic_string<CharT,Traits,A>& y)
+{
+ return y.compare(s) > 0;
+// std::size_t n = Traits::length(s);
+// return basic_string<CharT,Traits,A>
+// ::s_compare(s, s + n, y.begin(), y.end()) < 0;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator<(const basic_string<CharT,Traits,A>& x,
+ const CharT* s)
+{
+ return x.compare(s) < 0;
+// std::size_t n = Traits::length(s);
+// return basic_string<CharT,Traits,A>
+// ::s_compare(x.begin(), x.end(), s, s + n) < 0;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator>(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y) {
+ return y < x;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator>(const CharT* s, const basic_string<CharT,Traits,A>& y) {
+ return y < s;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator>(const basic_string<CharT,Traits,A>& x, const CharT* s)
+{
+ return s < x;
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator<=(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y)
+{
+ return !(y < x);
+}
+
+template <class CharT, class Traits, class A>
+inline bool
+operator<=(const CharT* s, const basic_string<CharT,Traits,A>& y)
+ { return !(y < s); }
+
+template <class CharT, class Traits, class A>
+inline bool
+operator<=(const basic_string<CharT,Traits,A>& x, const CharT* s)
+ { return !(s < x); }
+
+template <class CharT, class Traits, class A>
+inline bool
+operator>=(const basic_string<CharT,Traits,A>& x,
+ const basic_string<CharT,Traits,A>& y)
+ { return !(x < y); }
+
+template <class CharT, class Traits, class A>
+inline bool
+operator>=(const CharT* s, const basic_string<CharT,Traits,A>& y)
+ { return !(s < y); }
+
+template <class CharT, class Traits, class A>
+inline bool
+operator>=(const basic_string<CharT,Traits,A>& x, const CharT* s)
+ { return !(x < s); }
+
+// Swap.
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+inline void swap(basic_string<CharT,Traits,A>& x, basic_string<CharT,Traits,A>& y)
+{ x.swap(y); }
+
+template <class CharT, class Traits, class A>
+inline void swap(boost::rv<basic_string<CharT,Traits,A> > &mx, basic_string<CharT,Traits,A>& y)
+{ mx.get().swap(y); }
+
+template <class CharT, class Traits, class A>
+inline void swap(basic_string<CharT,Traits,A>& x, boost::rv<basic_string<CharT,Traits,A> > &my)
+{ x.swap(my.get()); }
+#else
+template <class CharT, class Traits, class A>
+inline void swap(basic_string<CharT,Traits,A> && x, basic_string<CharT,Traits,A> &&y)
+{ x.swap(y); }
+#endif
+
+/// @cond
+// I/O.
+namespace detail {
+
+template <class CharT, class Traits>
+inline bool
+interprocess_string_fill(std::basic_ostream<CharT, Traits>& os,
+ std::basic_streambuf<CharT, Traits>* buf,
+ std::size_t n)
+{
+ CharT f = os.fill();
+ std::size_t i;
+ bool ok = true;
+
+ for (i = 0; i < n; i++)
+ ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof());
+ return ok;
+}
+
+} //namespace detail {
+/// @endcond
+
+template <class CharT, class Traits, class A>
+std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& os,
+ #ifndef BOOST_HAS_RVALUE_REFS
+ const basic_string<CharT,Traits,A>& s)
+ #else
+ const basic_string<CharT,Traits,A>&&s)
+ #endif
+{
+ typename std::basic_ostream<CharT, Traits>::sentry sentry(os);
+ bool ok = false;
+
+ if (sentry) {
+ ok = true;
+ std::size_t n = s.size();
+ std::size_t pad_len = 0;
+ const bool left = (os.flags() & std::ios::left) != 0;
+ const std::size_t w = os.width(0);
+ std::basic_streambuf<CharT, Traits>* buf = os.rdbuf();
+
+ if (w != 0 && n < w)
+ pad_len = w - n;
+
+ if (!left)
+ ok = detail::interprocess_string_fill(os, buf, pad_len);
+
+ ok = ok &&
+ buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n);
+
+ if (left)
+ ok = ok && detail::interprocess_string_fill(os, buf, pad_len);
+ }
+
+ if (!ok)
+ os.setstate(std::ios_base::failbit);
+
+ return os;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& os,
+ boost::rv<basic_string<CharT,Traits,A> > &ms)
+{ return os << ms.get(); }
+#endif
+
+
+template <class CharT, class Traits, class A>
+std::basic_istream<CharT, Traits>&
+operator>>(std::basic_istream<CharT, Traits>& is,
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_string<CharT,Traits,A>& s)
+ #else
+ basic_string<CharT,Traits,A>&&s)
+ #endif
+{
+ typename std::basic_istream<CharT, Traits>::sentry sentry(is);
+
+ if (sentry) {
+ std::basic_streambuf<CharT, Traits>* buf = is.rdbuf();
+ const std::ctype<CharT>& ctype = std::use_facet<std::ctype<CharT> >(is.getloc());
+
+ s.clear();
+ std::size_t n = is.width(0);
+ if (n == 0)
+ n = static_cast<std::size_t>(-1);
+ else
+ s.reserve(n);
+
+ while (n-- > 0) {
+ typename Traits::int_type c1 = buf->sbumpc();
+
+ if (Traits::eq_int_type(c1, Traits::eof())) {
+ is.setstate(std::ios_base::eofbit);
+ break;
+ }
+ else {
+ CharT c = Traits::to_char_type(c1);
+
+ if (ctype.is(std::ctype<CharT>::space, c)) {
+ if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof()))
+ is.setstate(std::ios_base::failbit);
+ break;
+ }
+ else
+ s.push_back(c);
+ }
+ }
+
+ // If we have read no characters, then set failbit.
+ if (s.size() == 0)
+ is.setstate(std::ios_base::failbit);
+ }
+ else
+ is.setstate(std::ios_base::failbit);
+
+ return is;
+}
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class CharT, class Traits, class A>
+std::basic_istream<CharT, Traits>&
+operator>>(std::basic_istream<CharT, Traits>& is,
+ boost::rv<basic_string<CharT,Traits,A> > &ms)
+{ return is >> ms.get(); }
+#endif
+
+template <class CharT, class Traits, class A>
+std::basic_istream<CharT, Traits>&
+getline(std::istream& is,
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_string<CharT,Traits,A>& s,
+ #else
+ basic_string<CharT,Traits,A>&&s,
+ #endif
+ CharT delim)
+{
+ std::size_t nread = 0;
+ typename std::basic_istream<CharT, Traits>::sentry sentry(is, true);
+ if (sentry) {
+ std::basic_streambuf<CharT, Traits>* buf = is.rdbuf();
+ s.clear();
+
+ int c1;
+ while (nread < s.max_size()) {
+ int c1 = buf->sbumpc();
+ if (Traits::eq_int_type(c1, Traits::eof())) {
+ is.setstate(std::ios_base::eofbit);
+ break;
+ }
+ else {
+ ++nread;
+ CharT c = Traits::to_char_type(c1);
+ if (!Traits::eq(c, delim))
+ s.push_back(c);
+ else
+ break; // Character is extracted but not appended.
+ }
+ }
+ }
+ if (nread == 0 || nread >= s.max_size())
+ is.setstate(std::ios_base::failbit);
+
+ return is;
+}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+template <class CharT, class Traits, class A>
+std::basic_istream<CharT, Traits>&
+getline(std::istream& is, boost::rv<basic_string<CharT,Traits,A> > &ms,
+ CharT delim)
+{ return getline(is, ms.get(), delim); }
+#endif
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class CharT, class Traits, class A>
+inline std::basic_istream<CharT, Traits>&
+getline(std::basic_istream<CharT, Traits>& is,
+ basic_string<CharT,Traits,A>& s)
+{
+ return getline(is, s, '\n');
+}
+
+template <class CharT, class Traits, class A>
+std::basic_istream<CharT, Traits>&
+getline(std::istream& is, boost::rv<basic_string<CharT,Traits,A> > &ms)
+{ return getline(is, ms.get()); }
+#else
+template <class CharT, class Traits, class A>
+std::basic_istream<CharT, Traits>&
+getline(std::istream& is,
+ basic_string<CharT,Traits,A> && ms)
+{ return getline(is, ms); }
+#endif
+
+template <class Ch, class A>
+inline std::size_t hash_value(basic_string<Ch, std::char_traits<Ch>, A> const& v)
+{
+ return hash_range(v.begin(), v.end());
+}
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class C, class T, class A>
+struct has_trivial_destructor_after_move<basic_string<C, T, A> >
+{
+ enum { value = has_trivial_destructor<A>::value };
+};
+/// @endcond
+
+}} //namespace boost { namespace interprocess
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_STRING_HPP
Added: sandbox/boost/interprocess/containers/vector.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/containers/vector.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1964 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's stl_vector.h file. Modified by Ion Gaztanaga.
+// Renaming, isolating and porting to generic algorithms. Pointer typedef
+// set to allocator::pointer to allow placing it in shared memory.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 1994
+// Hewlett-Packard Company
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. Hewlett-Packard Company makes no
+// representations about the suitability of this software for any
+// purpose. It is provided "as is" without express or implied warranty.
+//
+//
+// Copyright (c) 1996
+// Silicon Graphics Computer Systems, Inc.
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. Silicon Graphics makes no
+// representations about the suitability of this software for any
+// purpose. It is provided "as is" without express or implied warranty.
+
+#ifndef BOOST_INTERPROCESS_VECTOR_HPP
+#define BOOST_INTERPROCESS_VECTOR_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>
+#include <memory>
+#include <algorithm>
+#include <stdexcept>
+#include <iterator>
+#include <utility>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
+#include <boost/type_traits/has_trivial_copy.hpp>
+#include <boost/type_traits/has_trivial_assign.hpp>
+#include <boost/type_traits/has_nothrow_copy.hpp>
+#include <boost/type_traits/has_nothrow_assign.hpp>
+#include <boost/interprocess/detail/version_type.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/iterators.hpp>
+#include <boost/interprocess/detail/algorithms.hpp>
+#include <boost/interprocess/detail/min_max.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/advanced_insert_int.hpp>
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+
+namespace detail {
+
+//! Const vector_iterator used to iterate through a vector.
+template <class Pointer>
+class vector_const_iterator
+ : public std::iterator<std::random_access_iterator_tag
+ ,const typename std::iterator_traits<Pointer>::value_type
+ ,typename std::iterator_traits<Pointer>::difference_type
+ ,typename pointer_to_other
+ <Pointer
+ ,const typename std::iterator_traits<Pointer>::value_type
+ >::type
+ ,const typename std::iterator_traits<Pointer>::value_type &>
+{
+ public:
+ typedef const typename std::iterator_traits<Pointer>::value_type value_type;
+ typedef typename std::iterator_traits<Pointer>::difference_type difference_type;
+ typedef typename pointer_to_other<Pointer, value_type>::type pointer;
+ typedef value_type& reference;
+
+ /// @cond
+ protected:
+ Pointer m_ptr;
+
+ public:
+ Pointer get_ptr() const { return m_ptr; }
+ explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){}
+ /// @endcond
+
+ public:
+
+ //Constructors
+ vector_const_iterator() : m_ptr(0){}
+
+ //Pointer like operators
+ reference operator*() const
+ { return *m_ptr; }
+
+ const value_type * operator->() const
+ { return detail::get_pointer(m_ptr); }
+
+ reference operator[](difference_type off) const
+ { return m_ptr[off]; }
+
+ //Increment / Decrement
+ vector_const_iterator& operator++()
+ { ++m_ptr; return *this; }
+
+ vector_const_iterator operator++(int)
+ { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); }
+
+ vector_const_iterator& operator--()
+ { --m_ptr; return *this; }
+
+ vector_const_iterator operator--(int)
+ { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); }
+
+ //Arithmetic
+ vector_const_iterator& operator+=(difference_type off)
+ { m_ptr += off; return *this; }
+
+ vector_const_iterator operator+(difference_type off) const
+ { return vector_const_iterator(m_ptr+off); }
+
+ friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right)
+ { return vector_const_iterator(off + right.m_ptr); }
+
+ vector_const_iterator& operator-=(difference_type off)
+ { m_ptr -= off; return *this; }
+
+ vector_const_iterator operator-(difference_type off) const
+ { return vector_const_iterator(m_ptr-off); }
+
+ difference_type operator-(const vector_const_iterator& right) const
+ { return m_ptr - right.m_ptr; }
+
+ //Comparison operators
+ bool operator== (const vector_const_iterator& r) const
+ { return m_ptr == r.m_ptr; }
+
+ bool operator!= (const vector_const_iterator& r) const
+ { return m_ptr != r.m_ptr; }
+
+ bool operator< (const vector_const_iterator& r) const
+ { return m_ptr < r.m_ptr; }
+
+ bool operator<= (const vector_const_iterator& r) const
+ { return m_ptr <= r.m_ptr; }
+
+ bool operator> (const vector_const_iterator& r) const
+ { return m_ptr > r.m_ptr; }
+
+ bool operator>= (const vector_const_iterator& r) const
+ { return m_ptr >= r.m_ptr; }
+};
+
+//! Iterator used to iterate through a vector
+template <class Pointer>
+class vector_iterator
+ : public vector_const_iterator<Pointer>
+{
+ public:
+ explicit vector_iterator(Pointer ptr)
+ : vector_const_iterator<Pointer>(ptr)
+ {}
+
+ public:
+ typedef typename std::iterator_traits<Pointer>::value_type value_type;
+ typedef typename vector_const_iterator<Pointer>::difference_type difference_type;
+ typedef Pointer pointer;
+ typedef value_type& reference;
+
+ //Constructors
+ vector_iterator()
+ {}
+
+ //Pointer like operators
+ reference operator*() const
+ { return *this->m_ptr; }
+
+ value_type* operator->() const
+ { return detail::get_pointer(this->m_ptr); }
+
+ reference operator[](difference_type off) const
+ { return this->m_ptr[off]; }
+
+ //Increment / Decrement
+ vector_iterator& operator++()
+ { ++this->m_ptr; return *this; }
+
+ vector_iterator operator++(int)
+ { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); }
+
+ vector_iterator& operator--()
+ { --this->m_ptr; return *this; }
+
+ vector_iterator operator--(int)
+ { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); }
+
+ // Arithmetic
+ vector_iterator& operator+=(difference_type off)
+ { this->m_ptr += off; return *this; }
+
+ vector_iterator operator+(difference_type off) const
+ { return vector_iterator(this->m_ptr+off); }
+
+ friend vector_iterator operator+(difference_type off, const vector_iterator& right)
+ { return vector_iterator(off + right.m_ptr); }
+
+ vector_iterator& operator-=(difference_type off)
+ { this->m_ptr -= off; return *this; }
+
+ vector_iterator operator-(difference_type off) const
+ { return vector_iterator(this->m_ptr-off); }
+
+ difference_type operator-(const vector_const_iterator<Pointer>& right) const
+ { return static_cast<const vector_const_iterator<Pointer>&>(*this) - right; }
+};
+
+template <class T, class A>
+struct vector_value_traits
+{
+ typedef T value_type;
+ typedef A allocator_type;
+ static const bool trivial_dctr = boost::has_trivial_destructor<value_type>::value;
+ static const bool trivial_dctr_after_move =
+ has_trivial_destructor_after_move<value_type>::value || trivial_dctr;
+ static const bool trivial_copy = has_trivial_copy<value_type>::value;
+ static const bool nothrow_copy = has_nothrow_copy<value_type>::value;
+ static const bool trivial_assign = has_trivial_assign<value_type>::value;
+ static const bool nothrow_assign = has_nothrow_assign<value_type>::value;
+
+ //This is the anti-exception array destructor
+ //to deallocate values already constructed
+ typedef typename detail::if_c
+ <trivial_dctr
+ ,detail::null_scoped_destructor_n<allocator_type>
+ ,detail::scoped_destructor_n<allocator_type>
+ >::type OldArrayDestructor;
+ //This is the anti-exception array destructor
+ //to destroy objects created with copy construction
+ typedef typename detail::if_c
+ <nothrow_copy
+ ,detail::null_scoped_destructor_n<allocator_type>
+ ,detail::scoped_destructor_n<allocator_type>
+ >::type UCopiedArrayDestructor;
+ //This is the anti-exception array deallocator
+ typedef typename detail::if_c
+ <nothrow_copy
+ ,detail::null_scoped_array_deallocator<allocator_type>
+ ,detail::scoped_array_deallocator<allocator_type>
+ >::type UCopiedArrayDeallocator;
+};
+
+//!This struct deallocates and allocated memory
+template <class A>
+struct vector_alloc_holder
+{
+ typedef typename A::pointer pointer;
+ typedef typename A::size_type size_type;
+ typedef typename A::value_type value_type;
+ typedef vector_value_traits<value_type, A> value_traits;
+
+ //Constructor, does not throw
+ vector_alloc_holder(const A &a)
+ : members_(a)
+ {}
+
+ //Constructor, does not throw
+ vector_alloc_holder(const vector_alloc_holder<A> &h)
+ : members_(h.alloc())
+ {}
+
+ //Destructor
+ ~vector_alloc_holder()
+ {
+ this->prot_destroy_all();
+ this->prot_deallocate();
+ }
+
+ typedef detail::integral_constant<unsigned, 1> allocator_v1;
+ typedef detail::integral_constant<unsigned, 2> allocator_v2;
+ typedef detail::integral_constant<unsigned,
+ boost::interprocess::detail::version<A>::value> alloc_version;
+ std::pair<pointer, bool>
+ allocation_command(allocation_type command,
+ size_type limit_size,
+ size_type preferred_size,
+ size_type &received_size, const pointer &reuse = 0)
+ {
+ return allocation_command(command, limit_size, preferred_size,
+ received_size, reuse, alloc_version());
+ }
+
+ std::pair<pointer, bool>
+ allocation_command(allocation_type command,
+ size_type limit_size,
+ size_type preferred_size,
+ size_type &received_size,
+ const pointer &reuse,
+ allocator_v1)
+ {
+ (void)limit_size;
+ (void)reuse;
+ if(!(command & allocate_new))
+ return std::pair<pointer, bool>(pointer(0), 0);
+ received_size = preferred_size;
+ return std::make_pair(this->alloc().allocate(received_size), false);
+ }
+
+ std::pair<pointer, bool>
+ allocation_command(allocation_type command,
+ size_type limit_size,
+ size_type preferred_size,
+ size_type &received_size,
+ const pointer &reuse,
+ allocator_v2)
+ {
+ return this->alloc().allocation_command
+ (command, limit_size, preferred_size, received_size, reuse);
+ }
+
+ size_type next_capacity(size_type additional_objects) const
+ { return get_next_capacity(this->alloc().max_size(), this->members_.m_capacity, additional_objects); }
+
+ struct members_holder
+ : public A
+ {
+ private:
+ members_holder(const members_holder&);
+
+ public:
+ members_holder(const A &alloc)
+ : A(alloc), m_start(0), m_size(0), m_capacity(0)
+ {}
+
+ pointer m_start;
+ size_type m_size;
+ size_type m_capacity;
+ } members_;
+
+ protected:
+ void prot_deallocate()
+ {
+ if(!this->members_.m_capacity) return;
+ this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
+ this->members_.m_start = 0;
+ this->members_.m_size = 0;
+ this->members_.m_capacity = 0;
+ }
+
+ void destroy(value_type* p)
+ {
+ if(!value_traits::trivial_dctr)
+ detail::get_pointer(p)->~value_type();
+ }
+
+ void destroy_n(value_type* p, size_type n)
+ {
+ if(!value_traits::trivial_dctr)
+ for(; n--; ++p) p->~value_type();
+ }
+
+ void prot_destroy_all()
+ {
+ this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size);
+ this->members_.m_size = 0;
+ }
+
+ A &alloc()
+ { return members_; }
+
+ const A &alloc() const
+ { return members_; }
+};
+
+} //namespace detail {
+/// @endcond
+
+//! A vector is a sequence that supports random access to elements, constant
+//! time insertion and removal of elements at the end, and linear time insertion
+//! and removal of elements at the beginning or in the middle. The number of
+//! elements in a vector may vary dynamically; memory management is automatic.
+//! boost::interprocess::vector is similar to std::vector but it's compatible
+//! with shared memory and memory mapped files.
+template <class T, class A>
+class vector : private detail::vector_alloc_holder<A>
+{
+ /// @cond
+ typedef vector<T, A> self_t;
+ typedef detail::vector_alloc_holder<A> base_t;
+ /// @endcond
+ public:
+ //! The type of object, T, stored in the vector
+ typedef T value_type;
+ //! Pointer to T
+ typedef typename A::pointer pointer;
+ //! Const pointer to T
+ typedef typename A::const_pointer const_pointer;
+ //! Reference to T
+ typedef typename A::reference reference;
+ //! Const reference to T
+ typedef typename A::const_reference const_reference;
+ //! An unsigned integral type
+ typedef typename A::size_type size_type;
+ //! A signed integral type
+ typedef typename A::difference_type difference_type;
+ //! The allocator type
+ typedef A allocator_type;
+ //! The random access iterator
+ typedef detail::vector_iterator<pointer> iterator;
+ //! The random access const_iterator
+ typedef detail::vector_const_iterator<pointer> const_iterator;
+
+ //! Iterator used to iterate backwards through a vector.
+ typedef std::reverse_iterator<iterator>
+ reverse_iterator;
+ //! Const iterator used to iterate backwards through a vector.
+ typedef std::reverse_iterator<const_iterator>
+ const_reverse_iterator;
+ //! The stored allocator type
+ typedef allocator_type stored_allocator_type;
+
+ /// @cond
+ private:
+ typedef detail::advanced_insert_aux_int<T, T*> advanced_insert_aux_int_t;
+ typedef detail::vector_value_traits<value_type, A> value_traits;
+
+ typedef typename base_t::allocator_v1 allocator_v1;
+ typedef typename base_t::allocator_v2 allocator_v2;
+ typedef typename base_t::alloc_version alloc_version;
+
+ typedef constant_iterator<T, difference_type> cvalue_iterator;
+ typedef repeat_iterator<T, difference_type> repeat_it;
+ typedef boost::move_iterator<repeat_it> repeat_move_it;
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(vector)
+
+ //! <b>Effects</b>: Constructs a vector taking the allocator as parameter.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ explicit vector(const A& a = A())
+ : base_t(a)
+ {}
+
+ //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
+ //! and inserts n default contructed values.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's default or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ vector(size_type n)
+ : base_t(allocator_type())
+ { this->resize(n); }
+
+ //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
+ //! and inserts n copies of value.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's default or copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ vector(size_type n, const T& value, const allocator_type& a = allocator_type())
+ : base_t(a)
+ { this->insert(this->cend(), n, value); }
+
+ //! <b>Effects</b>: Copy constructs a vector.
+ //!
+ //! <b>Postcondition</b>: x == *this.
+ //!
+ //! <b>Complexity</b>: Linear to the elements x contains.
+ vector(const vector<T, A>& x)
+ : base_t((base_t&)x)
+ { *this = x; }
+
+ //! <b>Effects</b>: Move constructor. Moves mx's resources to *this.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ vector(boost::rv<vector<T, A> > &mx)
+ : base_t(mx.get())
+ { this->swap(mx.get()); }
+ #else
+ vector(vector<T, A> && mx)
+ : base_t(boost::move(mx))
+ { this->swap(mx); }
+ #endif
+
+ //! <b>Effects</b>: Constructs a vector that will use a copy of allocator a
+ //! and inserts a copy of the range [first, last) in the vector.
+ //!
+ //! <b>Throws</b>: If allocator_type's default constructor or copy constructor
+ //! throws or T's constructor taking an dereferenced InIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to the range [first, last).
+ template <class InIt>
+ vector(InIt first, InIt last, const allocator_type& a = allocator_type())
+ : base_t(a)
+ { this->assign(first, last); }
+
+ //! <b>Effects</b>: Destroys the vector. All stored values are destroyed
+ //! and used memory is deallocated.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements.
+ ~vector()
+ {} //vector_alloc_holder clears the data
+
+ //! <b>Effects</b>: Returns an iterator to the first element contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator begin()
+ { return iterator(this->members_.m_start); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator begin() const
+ { return const_iterator(this->members_.m_start); }
+
+ //! <b>Effects</b>: Returns an iterator to the end of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ iterator end()
+ { return iterator(this->members_.m_start + this->members_.m_size); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator end() const
+ { return this->cend(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the beginning
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rbegin()
+ { return reverse_iterator(this->end()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rbegin()const
+ { return this->crbegin(); }
+
+ //! <b>Effects</b>: Returns a reverse_iterator pointing to the end
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reverse_iterator rend()
+ { return reverse_iterator(this->begin()); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator rend() const
+ { return this->crend(); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the first element contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cbegin() const
+ { return const_iterator(this->members_.m_start); }
+
+ //! <b>Effects</b>: Returns a const_iterator to the end of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_iterator cend() const
+ { return const_iterator(this->members_.m_start + this->members_.m_size); }
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the beginning
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crbegin()const
+ { return const_reverse_iterator(this->end());}
+
+ //! <b>Effects</b>: Returns a const_reverse_iterator pointing to the end
+ //! of the reversed vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reverse_iterator crend() const
+ { return const_reverse_iterator(this->begin()); }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference front()
+ { return *this->members_.m_start; }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a const reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference front() const
+ { return *this->members_.m_start; }
+
+ //! <b>Requires</b>: !empty()
+ //!
+ //! <b>Effects</b>: Returns a reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference back()
+ { return this->members_.m_start[this->members_.m_size - 1]; }
+
+ //! <b>Effects</b>: Returns a const reference to the first element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference back() const
+ { return this->members_.m_start[this->members_.m_size - 1]; }
+
+ //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range.
+ //! For a non-empty vector, data() == &front().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ pointer data()
+ { return this->members_.m_start; }
+
+ //! <b>Returns</b>: A pointer such that [data(),data() + size()) is a valid range.
+ //! For a non-empty vector, data() == &front().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_pointer data() const
+ { return this->members_.m_start; }
+
+ //! <b>Effects</b>: Returns the number of the elements contained in the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type size() const
+ { return this->members_.m_size; }
+
+ //! <b>Effects</b>: Returns the largest possible size of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type max_size() const
+ { return this->alloc().max_size(); }
+
+ //! <b>Effects</b>: Number of elements for which memory has been allocated.
+ //! capacity() is always greater than or equal to size().
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ size_type capacity() const
+ { return this->members_.m_capacity; }
+
+ //! <b>Effects</b>: Returns true if the vector contains no elements.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ bool empty() const
+ { return !this->members_.m_size; }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference operator[](size_type n)
+ { return this->members_.m_start[n]; }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a const reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference operator[](size_type n) const
+ { return this->members_.m_start[n]; }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: std::range_error if n >= size()
+ //!
+ //! <b>Complexity</b>: Constant.
+ reference at(size_type n)
+ { this->priv_check_range(n); return this->members_.m_start[n]; }
+
+ //! <b>Requires</b>: size() < n.
+ //!
+ //! <b>Effects</b>: Returns a const reference to the nth element
+ //! from the beginning of the container.
+ //!
+ //! <b>Throws</b>: std::range_error if n >= size()
+ //!
+ //! <b>Complexity</b>: Constant.
+ const_reference at(size_type n) const
+ { this->priv_check_range(n); return this->members_.m_start[n]; }
+
+ //! <b>Effects</b>: Returns a copy of the internal allocator.
+ //!
+ //! <b>Throws</b>: If allocator's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ allocator_type get_allocator() const
+ { return this->alloc(); }
+
+ const stored_allocator_type &get_stored_allocator() const
+ { return this->alloc(); }
+
+ stored_allocator_type &get_stored_allocator()
+ { return this->alloc(); }
+
+ //! <b>Effects</b>: If n is less than or equal to capacity(), this call has no
+ //! effect. Otherwise, it is a request for allocation of additional memory.
+ //! If the request is successful, then capacity() is greater than or equal to
+ //! n; otherwise, capacity() is unchanged. In either case, size() is unchanged.
+ //!
+ //! <b>Throws</b>: If memory allocation allocation throws or T's copy constructor throws.
+ void reserve(size_type new_cap)
+ {
+ if (this->capacity() < new_cap){
+ //There is not enough memory, allocate a new
+ //buffer or expand the old one.
+ bool same_buffer_start;
+ size_type real_cap = 0;
+ std::pair<pointer, bool> ret =
+ this->allocation_command
+ (allocate_new | expand_fwd | expand_bwd,
+ new_cap, new_cap, real_cap, this->members_.m_start);
+
+ //Check for forward expansion
+ same_buffer_start = ret.second && this->members_.m_start == ret.first;
+ if(same_buffer_start){
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_expand_fwd;
+ #endif
+ this->members_.m_capacity = real_cap;
+ }
+ //If there is no forward expansion, move objects
+ else{
+ //We will reuse insert code, so create a dummy input iterator
+ T *dummy_it(detail::get_pointer(this->members_.m_start));
+ detail::advanced_insert_aux_proxy<T, move_iterator<T*>, T*>
+ proxy(boost::make_move_iterator(dummy_it), boost::make_move_iterator(dummy_it));
+ //Backwards (and possibly forward) expansion
+ if(ret.second){
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_expand_bwd;
+ #endif
+ this->priv_range_insert_expand_backwards
+ ( detail::get_pointer(ret.first)
+ , real_cap
+ , detail::get_pointer(this->members_.m_start)
+ , 0
+ , proxy);
+ }
+ //New buffer
+ else{
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_alloc;
+ #endif
+ this->priv_range_insert_new_allocation
+ ( detail::get_pointer(ret.first)
+ , real_cap
+ , detail::get_pointer(this->members_.m_start)
+ , 0
+ , proxy);
+ }
+ }
+ }
+ }
+
+ //! <b>Effects</b>: Makes *this contain the same elements as x.
+ //!
+ //! <b>Postcondition</b>: this->size() == x.size(). *this contains a copy
+ //! of each of x's elements.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in x.
+ vector<T, A>& operator=(const vector<T, A>& x)
+ {
+ if (&x != this){
+ this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size);
+ }
+ return *this;
+ }
+
+ //! <b>Effects</b>: Move assignment. All mx's values are transferred to *this.
+ //!
+ //! <b>Postcondition</b>: x.empty(). *this contains a the elements x had
+ //! before the function.
+ //!
+ //! <b>Throws</b>: If allocator_type's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ vector<T, A>& operator=(boost::rv<vector<T, A> > &mx)
+ {
+ vector<T, A> &x = mx.get();
+ #else
+ vector<T, A>& operator=(vector<T, A> && x)
+ {
+ #endif
+ if (&x != this){
+ this->swap(x);
+ x.clear();
+ }
+ return *this;
+ }
+
+ //! <b>Effects</b>: Assigns the n copies of val to *this.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ void assign(size_type n, const value_type& val)
+ { this->assign(cvalue_iterator(val, n), cvalue_iterator()); }
+
+ //! <b>Effects</b>: Assigns the the range [first, last) to *this.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's constructor from dereferencing InpIt throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ template <class InIt>
+ void assign(InIt first, InIt last)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_assign_dispatch(first, last, Result());
+ }
+
+ //! <b>Effects</b>: Inserts a copy of x at the end of the vector.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or
+ //! T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ void push_back(const T& x)
+ {
+ if (this->members_.m_size < this->members_.m_capacity){
+ //There is more memory, just construct a new object at the end
+ new((void*)(detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x);
+ ++this->members_.m_size;
+ }
+ else{
+ this->insert(this->cend(), x);
+ }
+ }
+
+ //! <b>Effects</b>: Constructs a new element in the end of the vector
+ //! and moves the resources of mx to this new element.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void push_back(boost::rv<T> &mx)
+ {
+ value_type &x = mx.get();
+ #else
+ void push_back(T && x)
+ {
+ #endif
+ if (this->members_.m_size < this->members_.m_capacity){
+ //There is more memory, just construct a new object at the end
+ new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(boost::move(x));
+ ++this->members_.m_size;
+ }
+ else{
+ this->insert(this->cend(), boost::move(x));
+ }
+ }
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... in the end of the vector.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: Amortized constant time.
+ template<class ...Args>
+ void emplace_back(Args &&...args)
+ {
+ T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size;
+ if (this->members_.m_size < this->members_.m_capacity){
+ //There is more memory, just construct a new object at the end
+ new((void*)(back_pos))value_type(boost::forward_constructor<Args>(args)...);
+ ++this->members_.m_size;
+ }
+ else{
+ detail::advanced_insert_aux_emplace<T, T*, Args...> proxy
+ (boost::forward_constructor<Args>(args)...);
+ priv_range_insert(back_pos, 1, proxy);
+ }
+ }
+
+ //! <b>Requires</b>: position must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Inserts an object of type T constructed with
+ //! std::forward<Args>(args)... before position
+ //!
+ //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
+ //!
+ //! <b>Complexity</b>: If position is end(), amortized constant time
+ //! Linear time otherwise.
+ template<class ...Args>
+ iterator emplace(const_iterator position, Args && ...args)
+ {
+ //Just call more general insert(pos, size, value) and return iterator
+ size_type pos_n = position - cbegin();
+ detail::advanced_insert_aux_emplace<T, T*, Args...> proxy
+ (boost::forward_constructor<Args>(args)...);
+ priv_range_insert(position.get_ptr(), 1, proxy);
+ return iterator(this->members_.m_start + pos_n);
+ }
+
+ #else
+
+ void emplace_back()
+ {
+ T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size;
+ if (this->members_.m_size < this->members_.m_capacity){
+ //There is more memory, just construct a new object at the end
+ new((void*)(back_pos))value_type();
+ ++this->members_.m_size;
+ }
+ else{
+ detail::advanced_insert_aux_emplace<value_type, T*> proxy;
+ priv_range_insert(back_pos, 1, proxy);
+ }
+ }
+
+ iterator emplace(const_iterator position)
+ {
+ size_type pos_n = position - cbegin();
+ detail::advanced_insert_aux_emplace<value_type, T*> proxy;
+ priv_range_insert(detail::get_pointer(position.get_ptr()), 1, proxy);
+ return iterator(this->members_.m_start + pos_n);
+ }
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ void emplace_back(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ T* back_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size; \
+ if (this->members_.m_size < this->members_.m_capacity){ \
+ new((void*)(back_pos))value_type \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ ++this->members_.m_size; \
+ } \
+ else{ \
+ detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
+ <value_type, T*, BOOST_PP_ENUM_PARAMS(n, P)> \
+ proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ priv_range_insert(back_pos, 1, proxy); \
+ } \
+ } \
+ \
+ template<BOOST_PP_ENUM_PARAMS(n, class P)> \
+ iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ { \
+ size_type pos_n = pos - cbegin(); \
+ detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \
+ <value_type, T*, BOOST_PP_ENUM_PARAMS(n, P)> \
+ proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \
+ priv_range_insert(detail::get_pointer(pos.get_ptr()), 1, proxy); \
+ return iterator(this->members_.m_start + pos_n); \
+ } \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+
+ #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ //! <b>Effects</b>: Swaps the contents of *this and x.
+ //! If this->allocator_type() != x.allocator_type()
+ //! allocators are also swapped.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<vector> &x)
+ { this->swap(x.get()); }
+ void swap(vector& x)
+ #else
+ void swap(vector &&x)
+ #endif
+ {
+ allocator_type &this_al = this->alloc(), &other_al = x.alloc();
+ //Just swap internals
+ detail::do_swap(this->members_.m_start, x.members_.m_start);
+ detail::do_swap(this->members_.m_size, x.members_.m_size);
+ detail::do_swap(this->members_.m_capacity, x.members_.m_capacity);
+
+ if (this_al != other_al){
+ detail::do_swap(this_al, other_al);
+ }
+ }
+
+ //! <b>Requires</b>: position must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a copy of x before position.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or x's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: If position is end(), amortized constant time
+ //! Linear time otherwise.
+ iterator insert(const_iterator position, const T& x)
+ {
+ //Just call more general insert(pos, size, value) and return iterator
+ size_type pos_n = position - cbegin();
+ this->insert(position, (size_type)1, x);
+ return iterator(this->members_.m_start + pos_n);
+ }
+
+ //! <b>Requires</b>: position must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a new element before position with mx's resources.
+ //!
+ //! <b>Throws</b>: If memory allocation throws.
+ //!
+ //! <b>Complexity</b>: If position is end(), amortized constant time
+ //! Linear time otherwise.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ iterator insert(const_iterator position, boost::rv<T> &mx)
+ {
+ value_type &x = mx.get();
+ #else
+ iterator insert(const_iterator position, T &&x)
+ {
+ #endif
+ //Just call more general insert(pos, size, value) and return iterator
+ size_type pos_n = position - cbegin();
+ this->insert(position
+ ,repeat_move_it(repeat_it(x, 1))
+ ,repeat_move_it(repeat_it()));
+ return iterator(this->members_.m_start + pos_n);
+ }
+
+ //! <b>Requires</b>: pos must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert a copy of the [first, last) range before pos.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, T's constructor from a
+ //! dereferenced InpIt throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to std::distance [first, last).
+ template <class InIt>
+ void insert(const_iterator pos, InIt first, InIt last)
+ {
+ //Dispatch depending on integer/iterator
+ const bool aux_boolean = detail::is_convertible<InIt, std::size_t>::value;
+ typedef detail::bool_<aux_boolean> Result;
+ this->priv_insert_dispatch(pos, first, last, Result());
+ }
+
+ //! <b>Requires</b>: pos must be a valid iterator of *this.
+ //!
+ //! <b>Effects</b>: Insert n copies of x before pos.
+ //!
+ //! <b>Throws</b>: If memory allocation throws or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to n.
+ void insert(const_iterator p, size_type n, const T& x)
+ { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); }
+
+ //! <b>Effects</b>: Removes the last element from the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Constant time.
+ void pop_back()
+ {
+ //Destroy last element
+ --this->members_.m_size;
+ this->destroy(detail::get_pointer(this->members_.m_start) + this->members_.m_size);
+ }
+
+ //! <b>Effects</b>: Erases the element at position pos.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the elements between pos and the
+ //! last element. Constant if pos is the first or the last element.
+ iterator erase(const_iterator position)
+ {
+ T *pos = detail::get_pointer(position.get_ptr());
+ T *beg = detail::get_pointer(this->members_.m_start);
+ boost::move(pos + 1, beg + this->members_.m_size, pos);
+ --this->members_.m_size;
+ //Destroy last element
+ base_t::destroy(detail::get_pointer(this->members_.m_start) + this->members_.m_size);
+ return iterator(position.get_ptr());
+ }
+
+ //! <b>Effects</b>: Erases the elements pointed by [first, last).
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the distance between first and last.
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ if (first != last){ // worth doing, copy down over hole
+ T* end_pos = detail::get_pointer(this->members_.m_start) + this->members_.m_size;
+ T* ptr = detail::get_pointer(boost::move
+ (detail::get_pointer(last.get_ptr())
+ ,end_pos
+ ,detail::get_pointer(first.get_ptr())
+ ));
+ size_type destroyed = (end_pos - ptr);
+ this->destroy_n(ptr, destroyed);
+ this->members_.m_size -= destroyed;
+ }
+ return iterator(first.get_ptr());
+ }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are copy constructed from x.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type new_size, const T& x)
+ {
+ pointer finish = this->members_.m_start + this->members_.m_size;
+ if (new_size < size()){
+ //Destroy last elements
+ this->erase(const_iterator(this->members_.m_start + new_size), this->end());
+ }
+ else{
+ //Insert new elements at the end
+ this->insert(const_iterator(finish), new_size - this->size(), x);
+ }
+ }
+
+ //! <b>Effects</b>: Inserts or erases elements at the end such that
+ //! the size becomes n. New elements are default constructed.
+ //!
+ //! <b>Throws</b>: If memory allocation throws, or T's copy constructor throws.
+ //!
+ //! <b>Complexity</b>: Linear to the difference between size() and new_size.
+ void resize(size_type new_size)
+ {
+ if (new_size < this->size()){
+ //Destroy last elements
+ this->erase(const_iterator(this->members_.m_start + new_size), this->end());
+ }
+ else{
+ size_type n = new_size - this->size();
+ this->reserve(new_size);
+ detail::default_construct_aux_proxy<T, T*, size_type> proxy(n);
+ priv_range_insert(this->cend().get_ptr(), n, proxy);
+ }
+ }
+
+ //! <b>Effects</b>: Erases all the elements of the vector.
+ //!
+ //! <b>Throws</b>: Nothing.
+ //!
+ //! <b>Complexity</b>: Linear to the number of elements in the vector.
+ void clear()
+ { this->prot_destroy_all(); }
+
+ /// @cond
+
+ //! <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()
+ { priv_shrink_to_fit(alloc_version()); }
+
+ private:
+ void priv_shrink_to_fit(allocator_v1)
+ {
+ if(this->members_.m_capacity){
+ if(!size()){
+ this->prot_deallocate();
+ }
+ else{
+ //This would not work with stateful allocators
+ vector<T, A>(*this).swap(*this);
+ }
+ }
+ }
+
+ void priv_shrink_to_fit(allocator_v2)
+ {
+ if(this->members_.m_capacity){
+ if(!size()){
+ this->prot_deallocate();
+ }
+ else{
+ size_type received_size;
+ if(this->alloc().allocation_command
+ ( shrink_in_place | nothrow_allocation
+ , this->capacity(), this->size()
+ , received_size, this->members_.m_start).first){
+ this->members_.m_capacity = received_size;
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_shrink;
+ #endif
+ }
+ }
+ }
+ }
+
+ template <class FwdIt>
+ void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag)
+ {
+ if(first != last){
+ const size_type n = std::distance(first, last);
+ detail::advanced_insert_aux_proxy<T, FwdIt, T*> proxy(first, last);
+ priv_range_insert(pos, n, proxy);
+ }
+ }
+
+ void priv_range_insert(pointer pos, const size_type n, advanced_insert_aux_int_t &interf)
+ {
+ //Check if we have enough memory or try to expand current memory
+ size_type remaining = this->members_.m_capacity - this->members_.m_size;
+ bool same_buffer_start;
+ std::pair<pointer, bool> ret;
+ size_type real_cap = this->members_.m_capacity;
+
+ //Check if we already have room
+ if (n <= remaining){
+ same_buffer_start = true;
+ }
+ else{
+ //There is not enough memory, allocate a new
+ //buffer or expand the old one.
+ size_type new_cap = this->next_capacity(n);
+ ret = this->allocation_command
+ (allocate_new | expand_fwd | expand_bwd,
+ this->members_.m_size + n, new_cap, real_cap, this->members_.m_start);
+
+ //Check for forward expansion
+ same_buffer_start = ret.second && this->members_.m_start == ret.first;
+ if(same_buffer_start){
+ this->members_.m_capacity = real_cap;
+ }
+ }
+
+ //If we had room or we have expanded forward
+ if (same_buffer_start){
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_expand_fwd;
+ #endif
+ this->priv_range_insert_expand_forward
+ (detail::get_pointer(pos), n, interf);
+ }
+ //Backwards (and possibly forward) expansion
+ else if(ret.second){
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_expand_bwd;
+ #endif
+ this->priv_range_insert_expand_backwards
+ ( detail::get_pointer(ret.first)
+ , real_cap
+ , detail::get_pointer(pos)
+ , n
+ , interf);
+ }
+ //New buffer
+ else{
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ ++this->num_alloc;
+ #endif
+ this->priv_range_insert_new_allocation
+ ( detail::get_pointer(ret.first)
+ , real_cap
+ , detail::get_pointer(pos)
+ , n
+ , interf);
+ }
+ }
+
+ void priv_range_insert_expand_forward(T* pos, size_type n, advanced_insert_aux_int_t &interf)
+ {
+ //There is enough memory
+ T* old_finish = detail::get_pointer(this->members_.m_start) + this->members_.m_size;
+ const size_type elems_after = old_finish - pos;
+
+ if (elems_after > n){
+ //New elements can be just copied.
+ //Move to uninitialized memory last objects
+ boost::uninitialized_move(old_finish - n, old_finish, old_finish);
+ this->members_.m_size += n;
+ //Copy previous to last objects to the initialized end
+ boost::move_backward(pos, old_finish - n, old_finish);
+ //Insert new objects in the pos
+ interf.copy_all_to(pos);
+ }
+ else {
+ //The new elements don't fit in the [pos, end()) range. Copy
+ //to the beginning of the unallocated zone the last new elements.
+ interf.uninitialized_copy_some_and_update(old_finish, elems_after, false);
+ this->members_.m_size += n - elems_after;
+ //Copy old [pos, end()) elements to the uninitialized memory
+ boost::uninitialized_move
+ ( pos, old_finish, detail::get_pointer(this->members_.m_start) + this->members_.m_size);
+ this->members_.m_size += elems_after;
+ //Copy first new elements in pos
+ interf.copy_all_to(pos);
+ }
+ }
+
+ void priv_range_insert_new_allocation
+ (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf)
+ {
+ T* new_finish = new_start;
+ T *old_finish;
+ //Anti-exception rollbacks
+ typename value_traits::UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap);
+ typename value_traits::UCopiedArrayDestructor constructed_values_destroyer(new_start, 0u);
+
+ //Initialize with [begin(), pos) old buffer
+ //the start of the new buffer
+ new_finish = boost::uninitialized_move
+ (detail::get_pointer(this->members_.m_start), pos, old_finish = new_finish);
+ constructed_values_destroyer.increment_size(new_finish - old_finish);
+ //Initialize new objects, starting from previous point
+ interf.uninitialized_copy_all_to(old_finish = new_finish);
+ new_finish += n;
+ constructed_values_destroyer.increment_size(new_finish - old_finish);
+ //Initialize from the rest of the old buffer,
+ //starting from previous point
+ new_finish = boost::uninitialized_move
+ ( pos, detail::get_pointer(this->members_.m_start) + this->members_.m_size, new_finish);
+ //All construction successful, disable rollbacks
+ constructed_values_destroyer.release();
+ scoped_alloc.release();
+ //Destroy and deallocate old elements
+ //If there is allocated memory, destroy and deallocate
+ if(this->members_.m_start != 0){
+ if(!value_traits::trivial_dctr_after_move)
+ this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size);
+ this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
+ }
+ this->members_.m_start = new_start;
+ this->members_.m_size = new_finish - new_start;
+ this->members_.m_capacity = new_cap;
+ }
+
+ void priv_range_insert_expand_backwards
+ (T* new_start, size_type new_capacity,
+ T* pos, const size_type n, advanced_insert_aux_int_t &interf)
+ {
+ //Backup old data
+ T* old_start = detail::get_pointer(this->members_.m_start);
+ T* old_finish = old_start + this->members_.m_size;
+ size_type old_size = this->members_.m_size;
+
+ //We can have 8 possibilities:
+ const size_type elemsbefore = (size_type)(pos - old_start);
+ const size_type s_before = (size_type)(old_start - new_start);
+
+ //Update the vector buffer information to a safe state
+ this->members_.m_start = new_start;
+ this->members_.m_capacity = new_capacity;
+ this->members_.m_size = 0;
+
+ //If anything goes wrong, this object will destroy
+ //all the old objects to fulfill previous vector state
+ typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size);
+ //Check if s_before is big enough to hold the beginning of old data + new data
+ if(difference_type(s_before) >= difference_type(elemsbefore + n)){
+ //Copy first old values before pos, after that the new objects
+ boost::uninitialized_move(old_start, pos, new_start);
+ this->members_.m_size = elemsbefore;
+ interf.uninitialized_copy_all_to(new_start + elemsbefore);
+ this->members_.m_size += n;
+ //Check if s_before is so big that even copying the old data + new data
+ //there is a gap between the new data and the old data
+ if(s_before >= (old_size + n)){
+ //Old situation:
+ // _________________________________________________________
+ //| raw_mem | old_begin | old_end |
+ //| __________________________________|___________|_________|
+ //
+ //New situation:
+ // _________________________________________________________
+ //| old_begin | new | old_end | raw_mem |
+ //|___________|__________|_________|________________________|
+ //
+ //Now initialize the rest of memory with the last old values
+ boost::uninitialized_move
+ (pos, old_finish, new_start + elemsbefore + n);
+ //All new elements correctly constructed, avoid new element destruction
+ this->members_.m_size = old_size + n;
+ //Old values destroyed automatically with "old_values_destroyer"
+ //when "old_values_destroyer" goes out of scope unless the have trivial
+ //destructor after move.
+ if(value_traits::trivial_dctr_after_move)
+ old_values_destroyer.release();
+ }
+ //s_before is so big that divides old_end
+ else{
+ //Old situation:
+ // __________________________________________________
+ //| raw_mem | old_begin | old_end |
+ //| ___________________________|___________|_________|
+ //
+ //New situation:
+ // __________________________________________________
+ //| old_begin | new | old_end | raw_mem |
+ //|___________|__________|_________|_________________|
+ //
+ //Now initialize the rest of memory with the last old values
+ //All new elements correctly constructed, avoid new element destruction
+ size_type raw_gap = s_before - (elemsbefore + n);
+ //Now initialize the rest of s_before memory with the
+ //first of elements after new values
+ boost::uninitialized_move(pos, pos + raw_gap, new_start + elemsbefore + n);
+ //Update size since we have a contiguous buffer
+ this->members_.m_size = old_size + s_before;
+ //All new elements correctly constructed, avoid old element destruction
+ old_values_destroyer.release();
+ //Now copy remaining last objects in the old buffer begin
+ T *to_destroy = boost::move(pos + raw_gap, old_finish, old_start);
+ //Now destroy redundant elements except if they were moved and
+ //they have trivial destructor after move
+ size_type n_destroy = old_finish - to_destroy;
+ if(!value_traits::trivial_dctr_after_move)
+ this->destroy_n(to_destroy, n_destroy);
+ this->members_.m_size -= n_destroy;
+ }
+ }
+ else{
+ //Check if we have to do the insertion in two phases
+ //since maybe s_before is not big enough and
+ //the buffer was expanded both sides
+ //
+ //Old situation:
+ // _________________________________________________
+ //| raw_mem | old_begin + old_end | raw_mem |
+ //|_________|_____________________|_________________|
+ //
+ //New situation with do_after:
+ // _________________________________________________
+ //| old_begin + new + old_end | raw_mem |
+ //|___________________________________|_____________|
+ //
+ //New without do_after:
+ // _________________________________________________
+ //| old_begin + new + old_end | raw_mem |
+ //|____________________________|____________________|
+ //
+ bool do_after = n > s_before;
+
+ //Now we can have two situations: the raw_mem of the
+ //beginning divides the old_begin, or the new elements:
+ if (s_before <= elemsbefore) {
+ //The raw memory divides the old_begin group:
+ //
+ //If we need two phase construction (do_after)
+ //new group is divided in new = new_beg + new_end groups
+ //In this phase only new_beg will be inserted
+ //
+ //Old situation:
+ // _________________________________________________
+ //| raw_mem | old_begin | old_end | raw_mem |
+ //|_________|___________|_________|_________________|
+ //
+ //New situation with do_after(1):
+ //This is not definitive situation, the second phase
+ //will include
+ // _________________________________________________
+ //| old_begin | new_beg | old_end | raw_mem |
+ //|___________|_________|_________|_________________|
+ //
+ //New situation without do_after:
+ // _________________________________________________
+ //| old_begin | new | old_end | raw_mem |
+ //|___________|_____|_________|_____________________|
+ //
+ //Copy the first part of old_begin to raw_mem
+ T *start_n = old_start + difference_type(s_before);
+ boost::uninitialized_move(old_start, start_n, new_start);
+ //The buffer is all constructed until old_end,
+ //release destroyer and update size
+ old_values_destroyer.release();
+ this->members_.m_size = old_size + s_before;
+ //Now copy the second part of old_begin overwriting himself
+ T* next = boost::move(start_n, pos, old_start);
+ if(do_after){
+ //Now copy the new_beg elements
+ interf.copy_some_and_update(next, s_before, true);
+ }
+ else{
+ //Now copy the all the new elements
+ interf.copy_all_to(next);
+ T* move_start = next + n;
+ //Now displace old_end elements
+ T* move_end = boost::move(pos, old_finish, move_start);
+ //Destroy remaining moved elements from old_end except if
+ //they have trivial destructor after being moved
+ difference_type n_destroy = s_before - n;
+ if(!value_traits::trivial_dctr_after_move)
+ this->destroy_n(move_end, n_destroy);
+ this->members_.m_size -= n_destroy;
+ }
+ }
+ else {
+ //If we have to expand both sides,
+ //we will play if the first new values so
+ //calculate the upper bound of new values
+
+ //The raw memory divides the new elements
+ //
+ //If we need two phase construction (do_after)
+ //new group is divided in new = new_beg + new_end groups
+ //In this phase only new_beg will be inserted
+ //
+ //Old situation:
+ // _______________________________________________________
+ //| raw_mem | old_begin | old_end | raw_mem |
+ //|_______________|___________|_________|_________________|
+ //
+ //New situation with do_after():
+ // ____________________________________________________
+ //| old_begin | new_beg | old_end | raw_mem |
+ //|___________|_______________|_________|______________|
+ //
+ //New situation without do_after:
+ // ______________________________________________________
+ //| old_begin | new | old_end | raw_mem |
+ //|___________|_____|_________|__________________________|
+ //
+ //First copy whole old_begin and part of new to raw_mem
+ boost::uninitialized_move(old_start, pos, new_start);
+ this->members_.m_size = elemsbefore;
+
+ const size_type mid_n = difference_type(s_before) - elemsbefore;
+ interf.uninitialized_copy_some_and_update(new_start + elemsbefore, mid_n, true);
+ this->members_.m_size = old_size + s_before;
+ //The buffer is all constructed until old_end,
+ //release destroyer and update size
+ old_values_destroyer.release();
+
+ if(do_after){
+ //Copy new_beg part
+ interf.copy_some_and_update(old_start, s_before - mid_n, true);
+ }
+ else{
+ //Copy all new elements
+ interf.copy_all_to(old_start);
+ T* move_start = old_start + (n-mid_n);
+ //Displace old_end
+ T* move_end = boost::move(pos, old_finish, move_start);
+ //Destroy remaining moved elements from old_end except if they
+ //have trivial destructor after being moved
+ difference_type n_destroy = s_before - n;
+ if(!value_traits::trivial_dctr_after_move)
+ this->destroy_n(move_end, n_destroy);
+ this->members_.m_size -= n_destroy;
+ }
+ }
+
+ //This is only executed if two phase construction is needed
+ //This can be executed without exception handling since we
+ //have to just copy and append in raw memory and
+ //old_values_destroyer has been released in phase 1.
+ if(do_after){
+ //The raw memory divides the new elements
+ //
+ //Old situation:
+ // ______________________________________________________
+ //| raw_mem | old_begin | old_end | raw_mem |
+ //|______________|___________|____________|______________|
+ //
+ //New situation with do_after(1):
+ // _______________________________________________________
+ //| old_begin + new_beg | new_end |old_end | raw_mem |
+ //|__________________________|_________|________|_________|
+ //
+ //New situation with do_after(2):
+ // ______________________________________________________
+ //| old_begin + new | old_end |raw |
+ //|_______________________________________|_________|____|
+ //
+ const size_type n_after = n - s_before;
+ const difference_type elemsafter = old_size - elemsbefore;
+
+ //We can have two situations:
+ if (elemsafter > difference_type(n_after)){
+ //The raw_mem from end will divide displaced old_end
+ //
+ //Old situation:
+ // ______________________________________________________
+ //| raw_mem | old_begin | old_end | raw_mem |
+ //|______________|___________|____________|______________|
+ //
+ //New situation with do_after(1):
+ // _______________________________________________________
+ //| old_begin + new_beg | new_end |old_end | raw_mem |
+ //|__________________________|_________|________|_________|
+ //
+ //First copy the part of old_end raw_mem
+ T* finish_n = old_finish - difference_type(n_after);
+ boost::uninitialized_move(finish_n, old_finish, old_finish);
+ this->members_.m_size += n_after;
+ //Displace the rest of old_end to the new position
+ boost::move_backward(pos, finish_n, old_finish);
+ //Now overwrite with new_end
+ //The new_end part is [first + (n - n_after), last)
+ interf.copy_all_to(pos);
+ }
+ else {
+ //The raw_mem from end will divide new_end part
+ //
+ //Old situation:
+ // _____________________________________________________________
+ //| raw_mem | old_begin | old_end | raw_mem |
+ //|______________|___________|____________|_____________________|
+ //
+ //New situation with do_after(2):
+ // _____________________________________________________________
+ //| old_begin + new_beg | new_end |old_end | raw_mem |
+ //|__________________________|_______________|________|_________|
+ //
+ size_type mid_last_dist = n_after - elemsafter;
+ //First initialize data in raw memory
+ //The new_end part is [first + (n - n_after), last)
+ interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false);
+ this->members_.m_size += mid_last_dist;
+ boost::uninitialized_move(pos, old_finish, old_finish + mid_last_dist);
+ this->members_.m_size += n_after - mid_last_dist;
+ //Now copy the part of new_end over constructed elements
+ interf.copy_all_to(pos);
+ }
+ }
+ }
+ }
+
+ template <class InIt>
+ void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag)
+ {
+ for(;first != last; ++first){
+ this->insert(pos, boost::move(value_type(*first)));
+ }
+ }
+
+ template <class InIt>
+ void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag)
+ {
+ //Overwrite all elements we can from [first, last)
+ iterator cur = begin();
+ for ( ; first != last && cur != end(); ++cur, ++first){
+ *cur = *first;
+ }
+
+ if (first == last){
+ //There are no more elements in the sequence, erase remaining
+ this->erase(cur, cend());
+ }
+ else{
+ //There are more elements in the range, insert the remaining ones
+ this->insert(this->cend(), first, last);
+ }
+ }
+
+ template <class FwdIt>
+ void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag)
+ {
+ size_type n = std::distance(first, last);
+ //Check if we have enough memory or try to expand current memory
+ size_type remaining = this->members_.m_capacity - this->members_.m_size;
+ bool same_buffer_start;
+ std::pair<pointer, bool> ret;
+ size_type real_cap = this->members_.m_capacity;
+
+ if (n <= remaining){
+ same_buffer_start = true;
+ }
+ else{
+ //There is not enough memory, allocate a new buffer
+ size_type new_cap = this->next_capacity(n);
+ ret = this->allocation_command
+ (allocate_new | expand_fwd | expand_bwd,
+ this->size() + n, new_cap, real_cap, this->members_.m_start);
+ same_buffer_start = ret.second && this->members_.m_start == ret.first;
+ if(same_buffer_start){
+ this->members_.m_capacity = real_cap;
+ }
+ }
+
+ if(same_buffer_start){
+ T *start = detail::get_pointer(this->members_.m_start);
+ if (this->size() >= n){
+ //There is memory, but there are more old elements than new ones
+ //Overwrite old elements with new ones
+ // iG std::copy(first, last, start);
+ std::copy(first, last, start);
+ //Destroy remaining old elements
+ this->destroy_n(start + n, this->members_.m_size - n);
+ this->members_.m_size = n;
+ }
+ else{
+ //There is memory, but there are less old elements than new ones
+ //First overwrite some old elements with new ones
+ FwdIt mid = first;
+ std::advance(mid, this->size());
+ // iG T *end = std::copy(first, mid, start);
+ T *end = std::copy(first, mid, start);
+ //Initialize the remaining new elements in the uninitialized memory
+ // iG std::uninitialized_copy(mid, last, end);
+ boost::uninitialized_copy_or_move(mid, last, end);
+ this->members_.m_size = n;
+ }
+ }
+ else if(!ret.second){
+ typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap);
+ // iG std::uninitialized_copy(first, last, detail::get_pointer(ret.first));
+ boost::uninitialized_copy_or_move(first, last, detail::get_pointer(ret.first));
+ scoped_alloc.release();
+ //Destroy and deallocate old buffer
+ if(this->members_.m_start != 0){
+ this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size);
+ this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity);
+ }
+ this->members_.m_start = ret.first;
+ this->members_.m_size = n;
+ this->members_.m_capacity = real_cap;
+ }
+ else{
+ //Backwards expansion
+ //If anything goes wrong, this object will destroy old objects
+ T *old_start = detail::get_pointer(this->members_.m_start);
+ size_type old_size = this->members_.m_size;
+ typename value_traits::OldArrayDestructor old_values_destroyer(old_start, old_size);
+ //If something goes wrong size will be 0
+ //but holding the whole buffer
+ this->members_.m_size = 0;
+ this->members_.m_start = ret.first;
+ this->members_.m_capacity = real_cap;
+
+ //Backup old buffer data
+ size_type old_offset = old_start - detail::get_pointer(ret.first);
+ size_type first_count = min_value(n, old_offset);
+
+ FwdIt mid = first;
+ std::advance(mid, first_count);
+ // iG std::uninitialized_copy(first, mid, detail::get_pointer(ret.first));
+ boost::uninitialized_copy_or_move(first, mid, detail::get_pointer(ret.first));
+
+ if(old_offset > n){
+ //All old elements will be destroyed by "old_values_destroyer"
+ this->members_.m_size = n;
+ }
+ else{
+ //We have constructed objects from the new begin until
+ //the old end so release the rollback destruction
+ old_values_destroyer.release();
+ this->members_.m_start = ret.first;
+ this->members_.m_size = first_count + old_size;
+ //Now overwrite the old values
+ size_type second_count = min_value(old_size, n - first_count);
+ FwdIt mid2 = mid;
+ std::advance(mid2, second_count);
+ // iG std::copy(mid, mid2, old_start);
+ std::copy(mid, mid2, old_start);
+
+ //Check if we still have to append elements in the
+ //uninitialized end
+ if(second_count == old_size){
+ // iG std::copy(mid2, last, old_start + old_size);
+ std::copy(mid2, last, old_start + old_size);
+ }
+ else{
+ //We have to destroy some old values
+ this->destroy_n
+ (old_start + second_count, old_size - second_count);
+ this->members_.m_size = n;
+ }
+ this->members_.m_size = n;
+ }
+ }
+ }
+
+ template <class Integer>
+ void priv_assign_dispatch(Integer n, Integer val, detail::true_)
+ { this->assign((size_type) n, (T) val); }
+
+ template <class InIt>
+ void priv_assign_dispatch(InIt first, InIt last, detail::false_)
+ {
+ //Dispatch depending on integer/iterator
+ typedef typename std::iterator_traits<InIt>::iterator_category ItCat;
+ this->priv_assign_aux(first, last, ItCat());
+ }
+
+ template <class Integer>
+ void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, detail::true_)
+ { this->insert(pos, (size_type)n, (T)val); }
+
+ template <class InIt>
+ void priv_insert_dispatch(const_iterator pos, InIt first,
+ InIt last, detail::false_)
+ {
+ //Dispatch depending on integer/iterator
+ typedef typename std::iterator_traits<InIt>::iterator_category ItCat;
+ this->priv_range_insert(pos.get_ptr(), first, last, ItCat());
+ }
+
+ void priv_check_range(size_type n) const
+ {
+ //If n is out of range, throw an out_of_range exception
+ if (n >= size())
+ throw std::out_of_range("vector::at");
+ }
+
+ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
+ public:
+ unsigned int num_expand_fwd;
+ unsigned int num_expand_bwd;
+ unsigned int num_shrink;
+ unsigned int num_alloc;
+ void reset_alloc_stats()
+ { num_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; }
+ #endif
+ /// @endcond
+};
+
+template <class T, class A>
+inline bool
+operator==(const vector<T, A>& x, const vector<T, A>& y)
+{
+ //Check first size and each element if needed
+ return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin());
+}
+
+template <class T, class A>
+inline bool
+operator!=(const vector<T, A>& x, const vector<T, A>& y)
+{
+ //Check first size and each element if needed
+ return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin());
+}
+
+template <class T, class A>
+inline bool
+operator<(const vector<T, A>& x, const vector<T, A>& y)
+{
+ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+}
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+template <class T, class A>
+inline void swap(vector<T, A>& x, vector<T, A>& y)
+{ x.swap(y); }
+
+template <class T, class A>
+inline void swap(boost::rv<vector<T, A> > &x, vector<T, A>& y)
+{ x.get().swap(y); }
+
+template <class T, class A>
+inline void swap(vector<T, A> &x, boost::rv<vector<T, A> > &y)
+{ x.swap(y.get()); }
+#else
+template <class T, class A>
+inline void swap(vector<T, A>&&x, vector<T, A>&&y)
+{ x.swap(y); }
+#endif
+
+/// @cond
+
+//!has_trivial_destructor_after_move<> == true_type
+//!specialization for optimizations
+template <class T, class A>
+struct has_trivial_destructor_after_move<vector<T, A> >
+{
+ enum { value = has_trivial_destructor<A>::value };
+};
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_VECTOR_HPP
+
Added: sandbox/boost/interprocess/creation_tags.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/creation_tags.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/advanced_insert_int.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/advanced_insert_int.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,395 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_ADVANCED_INSERT_INT_HPP
+#define BOOST_INTERPROCESS_ADVANCED_INSERT_INT_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/move_semantics/move.hpp>
+#include <iterator> //std::iterator_traits
+#include <algorithm> //std::copy, std::uninitialized_copy
+#include <new> //placement new
+#include <cassert>
+
+namespace boost { namespace interprocess { namespace 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::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::uninitialized_copy_or_move(first_, mid, pos);
+ first_ = mid;
+ }
+ else{
+ boost::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(detail::get_pointer(&*p))T();
+ }
+ }
+ catch(...){
+ while(i--){
+ 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 { namespace detail {
+
+#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+#include <boost/interprocess/detail/variadic_templates_tools.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <typeinfo>
+//#include <iostream> //For debugging purposes
+
+namespace boost {
+namespace interprocess {
+namespace 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::forward_constructor<Args>(get<IdxPack>(args_))...);
+ *p = boost::move(object);
+ used_ = true;
+ }
+ }
+
+ template<int ...IdxPack>
+ void priv_uninitialized_copy_all_to(const index_tuple<IdxPack...>&, Iterator p)
+ {
+ if(!used_){
+ new(detail::get_pointer(&*p))T(boost::forward_constructor<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(detail::get_pointer(&*p))T(boost::forward_constructor<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::forward_constructor<Args>(get<IdxPack>(args_))...);
+ *p = boost::move(object);
+ used_ = true;
+ }
+ }
+ }
+ tuple<Args&&...> args_;
+ bool used_;
+};
+
+}}} //namespace boost { namespace interprocess { namespace detail {
+
+#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+#include <boost/interprocess/detail/preprocessor.hpp>
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+template<class T>
+struct value_init_helper
+{
+ value_init_helper()
+ : m_t()
+ {}
+
+ T m_t;
+};
+
+//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_helper<T>v;
+ *p = boost::move(v.m_t);
+ used_ = true;
+ }
+ }
+
+ virtual void uninitialized_copy_all_to(Iterator p)
+ {
+ if(!used_){
+ new(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(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_helper<T>v;
+ *p = boost::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_INTERPROCESS_PP_PARAM_LIST, _) ) \
+ : used_(false), BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_INIT, _) {} \
+ \
+ virtual void copy_all_to(Iterator p) \
+ { \
+ if(!used_){ \
+ T v(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \
+ *p = boost::move(v); \
+ used_ = true; \
+ } \
+ } \
+ \
+ virtual void uninitialized_copy_all_to(Iterator p) \
+ { \
+ if(!used_){ \
+ new(detail::get_pointer(&*p))T \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_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(detail::get_pointer(&*p))T \
+ (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_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_INTERPROCESS_PP_MEMBER_FORWARD, _)); \
+ *p = boost::move(v); \
+ used_ = true; \
+ } \
+ } \
+ } \
+ \
+ bool used_; \
+ 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()
+
+}}} //namespace boost { namespace interprocess { namespace detail {
+
+#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP
Added: sandbox/boost/interprocess/detail/algorithms.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/algorithms.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,205 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_ALGORITHMS_HPP
+#define BOOST_INTERPROCESS_DETAIL_ALGORITHMS_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/iterators.hpp>
+#include <boost/interprocess/detail/type_traits.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 <cstring>
+
+namespace boost {
+namespace interprocess {
+
+#if !defined(BOOST_HAS_RVALUE_REFS) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR)
+
+template<class T>
+struct has_own_construct_from_it
+{
+ static const bool value = false;
+};
+
+namespace detail {
+
+template<class T, class InpIt>
+inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_)
+{
+ T::construct(dest, *source);
+}
+
+template<class T, class InpIt>
+inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_)
+{
+ new((void*)dest)T(*source);
+}
+
+} //namespace detail {
+
+template<class T, class InpIt>
+inline void construct_in_place(T* dest, InpIt source)
+{
+ typedef detail::bool_<has_own_construct_from_it<T>::value> boolean_t;
+ 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 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, 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, 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, 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, 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(detail::get_pointer(&*dest), first);
+ }
+ }
+ BOOST_CATCH(...){
+ //Call destructors
+ new_count = count - new_count;
+ for (; new_count--; ++dest_init){
+ 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, 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, 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){
+ detail::get_pointer(&*result)->~value_type();
+ }
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+}
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP
+
Added: sandbox/boost/interprocess/detail/atomic.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/atomic.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/detail/cast_tags.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/cast_tags.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/config_begin.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/config_begin.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/detail/config_end.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/config_end.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/file_wrapper.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/file_wrapper.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,216 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/move_semantics/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_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
+ #ifndef BOOST_HAS_RVALUE_REFS
+ file_wrapper(boost::rv<file_wrapper> &moved)
+ { this->swap(moved.get()); }
+ #else
+ file_wrapper(file_wrapper &&moved)
+ { this->swap(moved); }
+ #endif
+
+ //!Moves the ownership of "moved"'s file to *this.
+ //!After the call, "moved" does not represent any file.
+ //!Does not throw
+ #ifndef BOOST_HAS_RVALUE_REFS
+ file_wrapper &operator=(boost::rv<file_wrapper> &moved)
+ {
+ file_wrapper tmp(moved);
+ this->swap(tmp);
+ return *this;
+ }
+ #else
+ file_wrapper &operator=(file_wrapper &&moved)
+ {
+ file_wrapper tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+ #endif
+
+ //!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
Added: sandbox/boost/interprocess/detail/in_place_interface.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/in_place_interface.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/detail/interprocess_tester.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/interprocess_tester.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/intersegment_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/intersegment_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1041 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_INTERSEGMENT_PTR_HPP
+#define BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/math_functions.hpp>
+#include <boost/interprocess/detail/cast_tags.hpp>
+#include <boost/assert.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/containers/flat_map.hpp>
+#include <boost/interprocess/containers/vector.hpp> //vector
+#include <boost/interprocess/containers/set.hpp> //set
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <climits>
+#include <iterator>
+#include <boost/static_assert.hpp> //BOOST_STATIC_ASSERT
+#include <climits> //CHAR_BIT
+#include <boost/integer/static_log2.hpp>
+#include <cassert> //assert
+#include <boost/interprocess/detail/multi_segment_services.hpp>
+
+//!\file
+//!
+namespace boost {
+
+//Predeclarations
+template <class T>
+struct has_trivial_constructor;
+
+template <class T>
+struct has_trivial_destructor;
+
+namespace interprocess {
+
+template <class T>
+struct is_multisegment_ptr;
+
+struct intersegment_base
+{
+ typedef intersegment_base self_t;
+ BOOST_STATIC_ASSERT((sizeof(std::size_t) == sizeof(void*)));
+ BOOST_STATIC_ASSERT((sizeof(void*)*CHAR_BIT == 32 || sizeof(void*)*CHAR_BIT == 64));
+ static const std::size_t size_t_bits = (sizeof(void*)*CHAR_BIT == 32) ? 32 : 64;
+ static const std::size_t ctrl_bits = 2;
+ static const std::size_t align_bits = 12;
+ static const std::size_t align = std::size_t(1) << align_bits;
+ static const std::size_t max_segment_size_bits = size_t_bits - 2;
+ static const std::size_t max_segment_size = std::size_t(1) << max_segment_size_bits;
+
+ static const std::size_t begin_bits = max_segment_size_bits - align_bits;
+ static const std::size_t pow_size_bits_helper = static_log2<max_segment_size_bits>::value;
+ static const std::size_t pow_size_bits =
+ (max_segment_size_bits == (std::size_t(1) << pow_size_bits_helper)) ?
+ pow_size_bits_helper : pow_size_bits_helper + 1;
+ static const std::size_t frc_size_bits =
+ size_t_bits - ctrl_bits - begin_bits - pow_size_bits;
+
+ BOOST_STATIC_ASSERT(((size_t_bits - pow_size_bits - frc_size_bits) >= ctrl_bits ));
+
+ static const std::size_t relative_size_bits =
+ size_t_bits - max_segment_size_bits - ctrl_bits;
+
+ static const std::size_t is_pointee_outside = 0;
+ static const std::size_t is_in_stack = 1;
+ static const std::size_t is_relative = 2;
+ static const std::size_t is_segmented = 3;
+ static const std::size_t is_max_mode = 4;
+
+ intersegment_base()
+ {
+ this->set_mode(is_pointee_outside);
+ this->set_null();
+ }
+
+ struct relative_addressing
+ {
+ std::size_t ctrl : 2;
+ std::size_t pow : pow_size_bits;
+ std::size_t frc : frc_size_bits;
+ std::size_t beg : begin_bits;
+ std::ptrdiff_t off : sizeof(ptrdiff_t)*CHAR_BIT - 2;
+ std::ptrdiff_t bits : 2;
+ };
+
+ struct direct_addressing
+ {
+ std::size_t ctrl : 2;
+ std::size_t dummy : sizeof(std::size_t)*CHAR_BIT - 2;
+ void * addr;
+ };
+
+ struct segmented_addressing
+ {
+ std::size_t ctrl : 2;
+ std::size_t segment : sizeof(std::size_t)*CHAR_BIT - 2;
+ std::size_t off : sizeof(std::size_t)*CHAR_BIT - 2;
+ std::size_t bits : 2;
+ };
+
+ union members_t{
+ relative_addressing relative;
+ direct_addressing direct;
+ segmented_addressing segmented;
+ } members;
+
+ BOOST_STATIC_ASSERT(sizeof(members_t) == 2*sizeof(std::size_t));
+
+ void *relative_calculate_begin_addr() const
+ {
+ const std::size_t mask = ~(align - 1);
+ std::size_t beg = this->members.relative.beg;
+ return reinterpret_cast<void*>((((std::size_t)this) & mask) - (beg << align_bits));
+ }
+
+ void relative_set_begin_from_base(void *addr)
+ {
+ assert(addr < static_cast<void*>(this));
+ std::size_t off = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(addr);
+ members.relative.beg = off >> align_bits;
+ }
+
+ //!Obtains the address pointed by the
+ //!object
+ std::size_t relative_size() const
+ {
+ std::size_t pow = members.relative.pow;
+ std::size_t size = (std::size_t(1u) << pow);
+ assert(pow >= frc_size_bits);
+ size |= members.relative.frc << (pow - frc_size_bits);
+ return size;
+ }
+
+ static std::size_t calculate_size(std::size_t orig_size, std::size_t &pow, std::size_t &frc)
+ {
+ if(orig_size < align)
+ orig_size = align;
+ orig_size = detail::get_rounded_size_po2(orig_size, align);
+ pow = detail::floor_log2(orig_size);
+ std::size_t low_size = (std::size_t(1) << pow);
+ std::size_t diff = orig_size - low_size;
+ assert(pow >= frc_size_bits);
+ std::size_t rounded = detail::get_rounded_size_po2
+ (diff, (1u << (pow - frc_size_bits)));
+ if(rounded == low_size){
+ ++pow;
+ frc = 0;
+ rounded = 0;
+ }
+ else{
+ frc = rounded >> (pow - frc_size_bits);
+ }
+ assert(((frc << (pow - frc_size_bits)) & (align-1))==0);
+ return low_size + rounded;
+ }
+
+ std::size_t get_mode()const
+ { return members.direct.ctrl; }
+
+ void set_mode(std::size_t mode)
+ {
+ assert(mode < is_max_mode);
+ members.direct.ctrl = mode;
+ }
+
+ //!Returns true if object represents
+ //!null pointer
+ bool is_null() const
+ {
+ return (this->get_mode() < is_relative) &&
+ !members.direct.dummy &&
+ !members.direct.addr;
+ }
+
+ //!Sets the object to represent
+ //!the null pointer
+ void set_null()
+ {
+ if(this->get_mode() >= is_relative){
+ this->set_mode(is_pointee_outside);
+ }
+ members.direct.dummy = 0;
+ members.direct.addr = 0;
+ }
+
+ static std::size_t round_size(std::size_t orig_size)
+ {
+ std::size_t pow, frc;
+ return calculate_size(orig_size, pow, frc);
+ }
+};
+
+
+
+//!Configures intersegment_ptr with the capability to address:
+//!2^(sizeof(std::size_t)*CHAR_BIT/2) segment groups
+//!2^(sizeof(std::size_t)*CHAR_BIT/2) segments per group.
+//!2^(sizeof(std::size_t)*CHAR_BIT/2)-1 bytes maximum per segment.
+//!The mapping is implemented through flat_maps synchronized with mutexes.
+template <class Mutex>
+struct flat_map_intersegment
+ : public intersegment_base
+{
+ typedef flat_map_intersegment<Mutex> self_t;
+
+ void set_from_pointer(const volatile void *ptr)
+ { this->set_from_pointer(const_cast<const void *>(ptr)); }
+
+ //!Obtains the address pointed
+ //!by the object
+ void *get_pointer() const
+ {
+ if(is_null()){
+ return 0;
+ }
+ switch(this->get_mode()){
+ case is_relative:
+ return const_cast<char*>(reinterpret_cast<const char*>(this)) + members.relative.off;
+ break;
+ case is_segmented:
+ {
+ segment_info_t segment_info;
+ std::size_t offset;
+ void *this_base;
+ get_segment_info_and_offset(this, segment_info, offset, this_base);
+ char *base = static_cast<char*>(segment_info.group->address_of(this->members.segmented.segment));
+ return base + this->members.segmented.off;
+ }
+ break;
+ case is_in_stack:
+ case is_pointee_outside:
+ return members.direct.addr;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+
+ //!Calculates the distance between two basic_intersegment_ptr-s.
+ //!This only works with two basic_intersegment_ptr pointing
+ //!to the same segment. Otherwise undefined
+ std::ptrdiff_t diff(const self_t &other) const
+ { return static_cast<char*>(this->get_pointer()) - static_cast<char*>(other.get_pointer()); }
+
+ //!Returns true if both point to
+ //!the same object
+ bool equal(const self_t &y) const
+ { return this->get_pointer() == y.get_pointer(); }
+
+ //!Returns true if *this is less than other.
+ //!This only works with two basic_intersegment_ptr pointing
+ //!to the same segment group. Otherwise undefined. Never throws
+ bool less(const self_t &y) const
+ { return this->get_pointer() < y.get_pointer(); }
+
+ void swap(self_t &other)
+ {
+ void *ptr_this = this->get_pointer();
+ void *ptr_other = other.get_pointer();
+ other.set_from_pointer(ptr_this);
+ this->set_from_pointer(ptr_other);
+ }
+
+ //!Sets the object internals to represent the
+ //!address pointed by ptr
+ void set_from_pointer(const void *ptr)
+ {
+ if(!ptr){
+ this->set_null();
+ return;
+ }
+
+ std::size_t mode = this->get_mode();
+ if(mode == is_in_stack){
+ members.direct.addr = const_cast<void*>(ptr);
+ return;
+ }
+ if(mode == is_relative){
+ char *beg_addr = static_cast<char*>(this->relative_calculate_begin_addr());
+ std::size_t seg_size = this->relative_size();
+ if(ptr >= beg_addr && ptr < (beg_addr + seg_size)){
+ members.relative.off = static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this);
+ return;
+ }
+ }
+ std::size_t ptr_offset;
+ std::size_t this_offset;
+ segment_info_t ptr_info;
+ segment_info_t this_info;
+ void *ptr_base;
+ void *this_base;
+ get_segment_info_and_offset(this, this_info, this_offset, this_base);
+
+ if(!this_info.group){
+ this->set_mode(is_in_stack);
+ this->members.direct.addr = const_cast<void*>(ptr);
+ }
+ else{
+ get_segment_info_and_offset(ptr, ptr_info, ptr_offset, ptr_base);
+
+ if(ptr_info.group != this_info.group){
+ this->set_mode(is_pointee_outside);
+ this->members.direct.addr = const_cast<void*>(ptr);
+ }
+ else if(ptr_info.id == this_info.id){
+ this->set_mode(is_relative);
+ members.relative.off = (static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
+ this->relative_set_begin_from_base(this_base);
+ std::size_t pow, frc;
+ std::size_t s = calculate_size(this_info.size, pow, frc);
+ (void)s;
+ assert(this_info.size == s);
+ this->members.relative.pow = pow;
+ this->members.relative.frc = frc;
+ }
+ else{
+ this->set_mode(is_segmented);
+ this->members.segmented.segment = ptr_info.id;
+ this->members.segmented.off = ptr_offset;
+ }
+ }
+ }
+
+ //!Sets the object internals to represent the address pointed
+ //!by another flat_map_intersegment
+ void set_from_other(const self_t &other)
+ {
+ this->set_from_pointer(other.get_pointer());
+ }
+
+ //!Increments internal
+ //!offset
+ void inc_offset(std::ptrdiff_t bytes)
+ {
+ this->set_from_pointer(static_cast<char*>(this->get_pointer()) + bytes);
+ }
+
+ //!Decrements internal
+ //!offset
+ void dec_offset(std::ptrdiff_t bytes)
+ {
+ this->set_from_pointer(static_cast<char*>(this->get_pointer()) - bytes);
+ }
+
+ //////////////////////////////////////
+ //////////////////////////////////////
+ //////////////////////////////////////
+
+ flat_map_intersegment()
+ : intersegment_base()
+ {}
+
+ ~flat_map_intersegment()
+ {}
+
+ private:
+
+ class segment_group_t
+ {
+ struct segment_data
+ {
+ void *addr;
+ std::size_t size;
+ };
+ vector<segment_data> m_segments;
+ multi_segment_services &m_ms_services;
+
+ public:
+ segment_group_t(multi_segment_services &ms_services)
+ : m_ms_services(ms_services)
+ {}
+
+ void push_back(void *addr, std::size_t size)
+ {
+ segment_data d = { addr, size };
+ m_segments.push_back(d);
+ }
+
+ void pop_back()
+ {
+ assert(!m_segments.empty());
+ m_segments.erase(--m_segments.end());
+ }
+
+
+ void *address_of(std::size_t segment_id)
+ {
+ assert(segment_id < (std::size_t)m_segments.size());
+ return m_segments[segment_id].addr;
+ }
+
+ void clear_segments()
+ { m_segments.clear(); }
+
+ std::size_t get_size() const
+ { return m_segments.size(); }
+
+ multi_segment_services &get_multi_segment_services() const
+ { return m_ms_services; }
+
+ friend bool operator< (const segment_group_t&l, const segment_group_t &r)
+ { return &l.m_ms_services < &r.m_ms_services; }
+ };
+
+ struct segment_info_t
+ {
+ std::size_t size;
+ std::size_t id;
+ segment_group_t *group;
+ segment_info_t()
+ : size(0), id(0), group(0)
+ {}
+ };
+
+ typedef set<segment_group_t> segment_groups_t;
+
+ typedef boost::interprocess::flat_map
+ <const void *
+ ,segment_info_t
+ ,std::less<const void *> > ptr_to_segment_info_t;
+
+ struct mappings_t : Mutex
+ {
+ //!Mutex to preserve integrity in multi-threaded
+ //!enviroments
+ typedef Mutex mutex_type;
+ //!Maps base addresses and segment information
+ //!(size and segment group and id)*
+
+ ptr_to_segment_info_t m_ptr_to_segment_info;
+
+ ~mappings_t()
+ {
+ //Check that all mappings have been erased
+ assert(m_ptr_to_segment_info.empty());
+ }
+ };
+
+ //Static members
+ static mappings_t s_map;
+ static segment_groups_t s_groups;
+ public:
+
+ typedef segment_group_t* segment_group_id;
+
+ //!Returns the segment and offset
+ //!of an address
+ static void get_segment_info_and_offset(const void *ptr, segment_info_t &segment, std::size_t &offset, void *&base)
+ {
+ //------------------------------------------------------------------
+ boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
+ //------------------------------------------------------------------
+ base = 0;
+ if(s_map.m_ptr_to_segment_info.empty()){
+ segment = segment_info_t();
+ offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
+ return;
+ }
+ //Find the first base address greater than ptr
+ typename ptr_to_segment_info_t::iterator it
+ = s_map.m_ptr_to_segment_info.upper_bound(ptr);
+ if(it == s_map.m_ptr_to_segment_info.begin()){
+ segment = segment_info_t();
+ offset = reinterpret_cast<const char*>(ptr) - static_cast<const char *>(0);
+ }
+ //Go to the previous one
+ --it;
+ char * segment_base = const_cast<char*>(reinterpret_cast<const char*>(it->first));
+ std::size_t segment_size = it->second.size;
+
+ if(segment_base <= reinterpret_cast<const char*>(ptr) &&
+ (segment_base + segment_size) >= reinterpret_cast<const char*>(ptr)){
+ segment = it->second;
+ offset = reinterpret_cast<const char*>(ptr) - segment_base;
+ base = segment_base;
+ }
+ else{
+ segment = segment_info_t();
+ offset = reinterpret_cast<const char*>(ptr) - static_cast<const char*>(0);
+ }
+ }
+
+ //!Associates a segment defined by group/id with a base address and size.
+ //!Returns false if the group is not found or there is an error
+ static void insert_mapping(segment_group_id group_id, void *ptr, std::size_t size)
+ {
+ //------------------------------------------------------------------
+ boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
+ //------------------------------------------------------------------
+
+ typedef typename ptr_to_segment_info_t::value_type value_type;
+ typedef typename ptr_to_segment_info_t::iterator iterator;
+ typedef std::pair<iterator, bool> it_b_t;
+
+ segment_info_t info;
+ info.group = group_id;
+ info.size = size;
+ info.id = group_id->get_size();
+
+ it_b_t ret = s_map.m_ptr_to_segment_info.insert(value_type(ptr, info));
+ assert(ret.second);
+
+ value_eraser<ptr_to_segment_info_t> v_eraser(s_map.m_ptr_to_segment_info, ret.first);
+ group_id->push_back(ptr, size);
+ v_eraser.release();
+ }
+
+ static bool erase_last_mapping(segment_group_id group_id)
+ {
+ //------------------------------------------------------------------
+ boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
+ //------------------------------------------------------------------
+ if(!group_id->get_size()){
+ return false;
+ }
+ else{
+ void *addr = group_id->address_of(group_id->get_size()-1);
+ group_id->pop_back();
+ std::size_t erased = s_map.m_ptr_to_segment_info.erase(addr);
+ (void)erased;
+ assert(erased);
+ return true;
+ }
+ }
+
+ static segment_group_id new_segment_group(multi_segment_services *services)
+ {
+ { //------------------------------------------------------------------
+ boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
+ //------------------------------------------------------------------
+ typedef typename segment_groups_t::iterator iterator;
+ std::pair<iterator, bool> ret =
+ s_groups.insert(segment_group_t(*services));
+ assert(ret.second);
+ return &*ret.first;
+ }
+ }
+
+ static bool delete_group(segment_group_id id)
+ {
+ { //------------------------------------------------------------------
+ boost::interprocess::scoped_lock<typename mappings_t::mutex_type> lock(s_map);
+ //------------------------------------------------------------------
+ bool success = 1u == s_groups.erase(segment_group_t(*id));
+ if(success){
+ typedef typename ptr_to_segment_info_t::iterator ptr_to_segment_info_it;
+ ptr_to_segment_info_it it(s_map.m_ptr_to_segment_info.begin());
+ while(it != s_map.m_ptr_to_segment_info.end()){
+ if(it->second.group == id){
+ it = s_map.m_ptr_to_segment_info.erase(it);
+ }
+ else{
+ ++it;
+ }
+ }
+ }
+ return success;
+ }
+ }
+};
+
+//!Static map-segment_info associated with
+//!flat_map_intersegment<>
+template <class Mutex>
+typename flat_map_intersegment<Mutex>::mappings_t
+ flat_map_intersegment<Mutex>::s_map;
+
+//!Static segment group container associated with
+//!flat_map_intersegment<>
+template <class Mutex>
+typename flat_map_intersegment<Mutex>::segment_groups_t
+ flat_map_intersegment<Mutex>::s_groups;
+
+//!A smart pointer that can point to a pointee that resides in another memory
+//!memory mapped or shared memory segment.
+template <class T>
+class intersegment_ptr : public flat_map_intersegment<interprocess_mutex>
+{
+ typedef flat_map_intersegment<interprocess_mutex> PT;
+ typedef intersegment_ptr<T> self_t;
+ typedef PT base_t;
+
+ void unspecified_bool_type_func() const {}
+ typedef void (self_t::*unspecified_bool_type)() const;
+
+ public:
+ typedef T * pointer;
+ typedef typename detail::add_reference<T>::type reference;
+ typedef T value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ public: //Public Functions
+
+ //!Constructor from raw pointer (allows "0" pointer conversion).
+ //!Never throws.
+ intersegment_ptr(pointer ptr = 0)
+ { base_t::set_from_pointer(ptr); }
+
+ //!Constructor from other pointer.
+ //!Never throws.
+ template <class U>
+ intersegment_ptr(U *ptr){ base_t::set_from_pointer(pointer(ptr)); }
+
+ //!Constructor from other intersegment_ptr
+ //!Never throws
+ intersegment_ptr(const intersegment_ptr& ptr)
+ { base_t::set_from_other(ptr); }
+
+ //!Constructor from other intersegment_ptr. If pointers of pointee types are
+ //!convertible, intersegment_ptrs will be convertibles. Never throws.
+ template<class T2>
+ intersegment_ptr(const intersegment_ptr<T2> &ptr)
+ { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); }
+
+ //!Emulates static_cast operator.
+ //!Never throws.
+ template<class U>
+ intersegment_ptr(const intersegment_ptr<U> &r, detail::static_cast_tag)
+ { base_t::set_from_pointer(static_cast<T*>(r.get())); }
+
+ //!Emulates const_cast operator.
+ //!Never throws.
+ template<class U>
+ intersegment_ptr(const intersegment_ptr<U> &r, detail::const_cast_tag)
+ { base_t::set_from_pointer(const_cast<T*>(r.get())); }
+
+ //!Emulates dynamic_cast operator.
+ //!Never throws.
+ template<class U>
+ intersegment_ptr(const intersegment_ptr<U> &r, detail::dynamic_cast_tag)
+ { base_t::set_from_pointer(dynamic_cast<T*>(r.get())); }
+
+ //!Emulates reinterpret_cast operator.
+ //!Never throws.
+ template<class U>
+ intersegment_ptr(const intersegment_ptr<U> &r, detail::reinterpret_cast_tag)
+ { base_t::set_from_pointer(reinterpret_cast<T*>(r.get())); }
+
+ //!Obtains raw pointer from offset.
+ //!Never throws.
+ pointer get()const
+ { return static_cast<pointer>(base_t::get_pointer()); }
+
+ //!Pointer-like -> operator. It can return 0 pointer.
+ //!Never throws.
+ pointer operator->() const
+ { return self_t::get(); }
+
+ //!Dereferencing operator, if it is a null intersegment_ptr behavior
+ //!is undefined. Never throws.
+ reference operator* () const
+ { return *(self_t::get()); }
+
+ //!Indexing operator.
+ //!Never throws.
+ reference operator[](std::ptrdiff_t idx) const
+ { return self_t::get()[idx]; }
+
+ //!Assignment from pointer (saves extra conversion).
+ //!Never throws.
+ intersegment_ptr& operator= (pointer from)
+ { base_t::set_from_pointer(from); return *this; }
+
+ //!Assignment from other intersegment_ptr.
+ //!Never throws.
+ intersegment_ptr& operator= (const intersegment_ptr &ptr)
+ { base_t::set_from_other(ptr); return *this; }
+
+ //!Assignment from related intersegment_ptr. If pointers of pointee types
+ //!are assignable, intersegment_ptrs will be assignable. Never throws.
+ template <class T2>
+ intersegment_ptr& operator= (const intersegment_ptr<T2> & ptr)
+ {
+ pointer p(ptr.get()); (void)p;
+ base_t::set_from_other(ptr); return *this;
+ }
+
+ //!intersegment_ptr + std::ptrdiff_t.
+ //!Never throws.
+ intersegment_ptr operator+ (std::ptrdiff_t idx) const
+ {
+ intersegment_ptr result (*this);
+ result.inc_offset(idx*sizeof(T));
+ return result;
+ }
+
+ //!intersegment_ptr - std::ptrdiff_t.
+ //!Never throws.
+ intersegment_ptr operator- (std::ptrdiff_t idx) const
+ {
+ intersegment_ptr result (*this);
+ result.dec_offset(idx*sizeof(T));
+ return result;
+ }
+
+ //!intersegment_ptr += std::ptrdiff_t.
+ //!Never throws.
+ intersegment_ptr &operator+= (std::ptrdiff_t offset)
+ { base_t::inc_offset(offset*sizeof(T)); return *this; }
+
+ //!intersegment_ptr -= std::ptrdiff_t.
+ //!Never throws.
+ intersegment_ptr &operator-= (std::ptrdiff_t offset)
+ { base_t::dec_offset(offset*sizeof(T)); return *this; }
+
+ //!++intersegment_ptr.
+ //!Never throws.
+ intersegment_ptr& operator++ (void)
+ { base_t::inc_offset(sizeof(T)); return *this; }
+
+ //!intersegment_ptr++.
+ //!Never throws.
+ intersegment_ptr operator++ (int)
+ { intersegment_ptr temp(*this); ++*this; return temp; }
+
+ //!--intersegment_ptr.
+ //!Never throws.
+ intersegment_ptr& operator-- (void)
+ { base_t::dec_offset(sizeof(T)); return *this; }
+
+ //!intersegment_ptr--.
+ //!Never throws.
+ intersegment_ptr operator-- (int)
+ { intersegment_ptr temp(*this); --*this; return temp; }
+
+ //!Safe bool conversion operator.
+ //!Never throws.
+ operator unspecified_bool_type() const
+ { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; }
+
+ //!Not operator. Not needed in theory, but improves portability.
+ //!Never throws.
+ bool operator! () const
+ { return base_t::is_null(); }
+
+ //!Swaps two intersegment_ptr-s. More efficient than std::swap.
+ //!Never throws.
+ void swap(intersegment_ptr &other)
+ { base_t::swap(other); }
+
+ //!Calculates the distance between two intersegment_ptr-s.
+ //!This only works with two basic_intersegment_ptr pointing
+ //!to the same segment. Otherwise undefined
+ template <class T2>
+ ptrdiff_t _diff(const intersegment_ptr<T2> &other) const
+ { return base_t::diff(other); }
+
+ //!Returns true if both point to the
+ //!same object
+ template <class T2>
+ bool _equal(const intersegment_ptr<T2>&other) const
+ { return base_t::equal(other); }
+
+ //!Returns true if *this is less than other.
+ //!This only works with two basic_intersegment_ptr pointing
+ //!to the same segment group. Otherwise undefined. Never throws
+ template <class T2>
+ bool _less(const intersegment_ptr<T2> &other) const
+ { return base_t::less(other); }
+};
+
+//!Compares the equality of two intersegment_ptr-s.
+//!Never throws.
+template <class T1, class T2> inline
+bool operator ==(const intersegment_ptr<T1> &left,
+ const intersegment_ptr<T2> &right)
+{
+ //Make sure both pointers can be compared
+ bool e = typename intersegment_ptr<T1>::pointer(0) ==
+ typename intersegment_ptr<T2>::pointer(0);
+ (void)e;
+ return left._equal(right);
+}
+
+//!Returns true if *this is less than other.
+//!This only works with two basic_intersegment_ptr pointing
+//!to the same segment group. Otherwise undefined. Never throws
+template <class T1, class T2> inline
+bool operator <(const intersegment_ptr<T1> &left,
+ const intersegment_ptr<T2> &right)
+{
+ //Make sure both pointers can be compared
+ bool e = typename intersegment_ptr<T1>::pointer(0) <
+ typename intersegment_ptr<T2>::pointer(0);
+ (void)e;
+ return left._less(right);
+}
+
+template<class T1, class T2> inline
+bool operator!= (const intersegment_ptr<T1> &pt1,
+ const intersegment_ptr<T2> &pt2)
+{ return !(pt1 ==pt2); }
+
+//!intersegment_ptr<T1> <= intersegment_ptr<T2>.
+//!Never throws.
+template<class T1, class T2> inline
+bool operator<= (const intersegment_ptr<T1> &pt1,
+ const intersegment_ptr<T2> &pt2)
+{ return !(pt1 > pt2); }
+
+//!intersegment_ptr<T1> > intersegment_ptr<T2>.
+//!Never throws.
+template<class T1, class T2> inline
+bool operator> (const intersegment_ptr<T1> &pt1,
+ const intersegment_ptr<T2> &pt2)
+{ return (pt2 < pt1); }
+
+//!intersegment_ptr<T1> >= intersegment_ptr<T2>.
+//!Never throws.
+template<class T1, class T2> inline
+bool operator>= (const intersegment_ptr<T1> &pt1,
+ const intersegment_ptr<T2> &pt2)
+{ return !(pt1 < pt2); }
+
+//!operator<<
+template<class E, class T, class U> inline
+std::basic_ostream<E, T> & operator<<
+ (std::basic_ostream<E, T> & os, const intersegment_ptr<U> & p)
+{ return os << p.get(); }
+
+//!operator>>
+template<class E, class T, class U> inline
+std::basic_istream<E, T> & operator>>
+ (std::basic_istream<E, T> & os, intersegment_ptr<U> & p)
+{ U * tmp; return os >> tmp; p = tmp; }
+
+//!std::ptrdiff_t + intersegment_ptr.
+//!The result is another pointer of the same segment
+template<class T> inline
+intersegment_ptr<T> operator+
+ (std::ptrdiff_t diff, const intersegment_ptr<T>& right)
+{ return right + diff; }
+
+//!intersegment_ptr - intersegment_ptr.
+//!This only works with two intersegment_ptr-s that point to the
+//!same segment
+template <class T, class T2> inline
+std::ptrdiff_t operator- (const intersegment_ptr<T> &pt,
+ const intersegment_ptr<T2> &pt2)
+{ return pt._diff(pt2)/sizeof(T); }
+
+//! swap specialization
+template<class T> inline
+void swap (boost::interprocess::intersegment_ptr<T> &pt,
+ boost::interprocess::intersegment_ptr<T> &pt2)
+{ pt.swap(pt2); }
+
+//!get_pointer() enables boost::mem_fn to recognize intersegment_ptr.
+//!Never throws.
+template<class T> inline
+T * get_pointer(boost::interprocess::intersegment_ptr<T> const & p)
+{ return p.get(); }
+
+//!Simulation of static_cast between pointers.
+//!Never throws.
+template<class T, class U> inline
+boost::interprocess::intersegment_ptr<T> static_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
+{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::static_cast_tag()); }
+
+//!Simulation of const_cast between pointers.
+//!Never throws.
+template<class T, class U> inline
+boost::interprocess::intersegment_ptr<T> const_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
+{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::const_cast_tag()); }
+
+//!Simulation of dynamic_cast between pointers.
+//!Never throws.
+template<class T, class U> inline
+boost::interprocess::intersegment_ptr<T> dynamic_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
+{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::dynamic_cast_tag()); }
+
+//!Simulation of reinterpret_cast between pointers.
+//!Never throws.
+template<class T, class U> inline
+boost::interprocess::intersegment_ptr<T> reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr<U> &r)
+{ return boost::interprocess::intersegment_ptr<T>(r, boost::interprocess::detail::reinterpret_cast_tag()); }
+
+//!Trait class to detect if an smart pointer has
+//!multi-segment addressing capabilities.
+template <class T>
+struct is_multisegment_ptr
+ <boost::interprocess::intersegment_ptr<T> >
+{
+ static const bool value = true;
+};
+
+} //namespace interprocess {
+
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+//!get_pointer() enables boost::mem_fn to recognize intersegment_ptr.
+//!Never throws.
+template<class T> inline
+T * get_pointer(boost::interprocess::intersegment_ptr<T> const & p)
+{ return p.get(); }
+#endif
+
+//!has_trivial_constructor<> == true_type specialization
+//!for optimizations
+template <class T>
+struct has_trivial_constructor
+ < boost::interprocess::intersegment_ptr<T> >
+ : public true_type{};
+
+//!has_trivial_destructor<> == true_type specialization
+//!for optimizations
+template <class T>
+struct has_trivial_destructor
+ < boost::interprocess::intersegment_ptr<T> >
+ : public true_type{};
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#if 0
+
+//bits
+//-> is_segmented
+//-> is_relative
+//-> is_in_stack
+//-> is_pointee_outside
+
+//Data
+
+
+
+
+//segmented:
+//
+// std::size_t ctrl : CTRL_BITS;
+// std::size_t segment : MAX_SEGMENT_BITS;
+// std::size_t offset;
+
+//RELATIVE_SIZE_BITS = SIZE_T_BITS -
+// MAX_SEGMENT_BITS -
+// CTRL_BITS 10 10
+//MAX_SEGMENT_SIZE = SIZE_T_BITS - ALIGN_BITS 20 52
+
+//SIZE_T_BITS - 1 - ALIGN_BITS 19 51
+//POW_SIZE_BITS = upper_log2
+// (SIZE_T_BITS - 1 - ALIGN_BITS) 5 6
+//FRC_SIZE_BITS = SIZE_T_BITS - CTRL_BITS
+// MAX_SEGMENT_SIZE_ALIGNBITS - POW_SIZE_BITS 6 5
+
+//relative:
+//
+// std::size_t ctrl : CTRL_BITS; 2 2
+// std::size_t size_pow : POW_SIZE_BITS 5 6
+// std::size_t size_frc : FRC_SIZE_BITS; 6 5
+// std::size_t start : MAX_SEGMENT_SIZE_ALIGNBITS;19 51
+// std::ptrdiff_t distance : SIZE_T_BITS; 32 64
+
+//direct:
+//
+// std::size_t ctrl : CTRL_BITS; 2 2
+// std::size_t dummy : SIZE_T_BITS - CTRL_BITS 30 62
+// void *addr : SIZE_T_BITS; 32 64
+
+//32 bits systems:
+//Page alignment: 2**12
+//
+
+//!Obtains the address pointed by the
+//!object
+void *get_pointer() const
+{
+ if(this->is_pointee_outside() || this->is_in_stack()){
+ return raw_address();
+ }
+ else if(this->is_relative()){
+ return (const_cast<char*>(reinterpret_cast<const char*>(this))) + this->relative_pointee_offset();
+ }
+ else{
+ group_manager *m = get_segment_group_manager(addr);
+ char *base = static_cast<char*>(m->get_id_address(this->segmented_id()));
+ return base + this->segmented_offset();
+ }
+}
+
+void set_from_pointer(const void *ptr)
+{
+ if(!ptr){
+ this->set_pointee_outside();
+ this->raw_address(ptr);
+ }
+ else if(this->is_in_stack()){
+ this->raw_address(ptr);
+ }
+ else if(this->is_relative() &&
+ ( (ptr >= this->relative_start())
+ &&(ptr < this->relative_start() + this->relative_size()))
+ ){
+ this->relative_offset(ptr - this);
+ }
+ else{
+ segment_info_t ptr_info = get_id_from_addr(ptr);
+ segment_info_t this_info = get_id_from_addr(this);
+ if(ptr_info.segment_group != this_info.segment_group){
+ if(!ptr_info.segment_group){
+ this->set_in_stack();
+ }
+ else{
+ this->set_pointee_outside();
+ }
+ }
+ else if(ptr_info.segment_id == this_info.segment_id){
+ set_relative();
+ this->relative_size (ptr_info.size);
+ this->relative_offset(static_cast<const char*>(ptr) - reinterpret_cast<const char*>(this));
+ this->relative_start (ptr_info.base);
+ }
+ }
+}
+
+void set_from_other(const self_t &other)
+{ this->set_from_pointer(other.get_pointer()); }
+
+#endif
+
+#endif //#ifndef BOOST_INTERPROCESS_INTERSEGMENT_PTR_HPP
+
Added: sandbox/boost/interprocess/detail/iterators.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/iterators.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,475 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_ITERATORS_HPP
+#define BOOST_INTERPROCESS_DETAIL_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 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 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_ITERATORS_HPP
+
Added: sandbox/boost/interprocess/detail/managed_memory_impl.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/managed_memory_impl.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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 (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::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
+
Added: sandbox/boost/interprocess/detail/managed_multi_shared_memory.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/managed_multi_shared_memory.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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 ®ion, bool last) const
+ {
+ if(last) mp_frontend->destroy_impl();
+ else mp_frontend->close_impl();
+ }
+ self_t * const mp_frontend;
+ };
+
+ typedef detail::basic_managed_memory_impl
+ <CharType, MemoryAlgorithm, IndexType> base_t;
+
+ //Friend declarations
+ friend struct basic_managed_multi_shared_memory::create_open_func;
+ friend struct basic_managed_multi_shared_memory::close_func;
+ friend class basic_managed_multi_shared_memory::group_services;
+
+ typedef list<managed_impl> shmem_list_t;
+
+ basic_managed_multi_shared_memory *get_this_pointer()
+ { return this; }
+
+ public:
+
+ basic_managed_multi_shared_memory(create_only_t,
+ const char *name,
+ std::size_t size)
+ : m_group_services(get_this_pointer())
+ {
+ priv_open_or_create(create_open_func::DoCreate,name, size);
+ }
+
+ basic_managed_multi_shared_memory(open_or_create_t,
+ const char *name,
+ std::size_t size)
+ : m_group_services(get_this_pointer())
+ {
+ priv_open_or_create(create_open_func::DoOpenOrCreate, name, size);
+ }
+
+ basic_managed_multi_shared_memory(open_only_t, const char *name)
+ : m_group_services(get_this_pointer())
+ {
+ priv_open_or_create(create_open_func::DoOpen, name, 0);
+ }
+
+ ~basic_managed_multi_shared_memory()
+ { this->priv_close(); }
+
+ private:
+ bool priv_open_or_create(typename create_open_func::type_t type,
+ const char *name,
+ std::size_t size)
+ {
+ if(!m_shmem_list.empty())
+ return false;
+ typename void_pointer::segment_group_id group = 0;
+ BOOST_TRY{
+ m_root_name = name;
+ //Insert multi segment services and get a group identifier
+ group = void_pointer::new_segment_group(&m_group_services);
+ size = void_pointer::round_size(size);
+ m_group_services.set_group(group);
+ m_group_services.set_min_segment_size(size);
+
+ if(group){
+ if(this->priv_new_segment(type, size, 0)){
+ return true;
+ }
+ }
+ }
+ BOOST_CATCH(const std::bad_alloc&){
+ }
+ BOOST_CATCH_END
+ if(group){
+ void_pointer::delete_group(group);
+ }
+ return false;
+ }
+
+ bool priv_new_segment(typename create_open_func::type_t type,
+ std::size_t size,
+ const void *addr)
+ {
+ BOOST_TRY{
+ //Get the number of groups of this multi_segment group
+ std::size_t segment_id = m_shmem_list.size();
+ //Format the name of the shared memory: append segment number.
+ boost::interprocess::basic_ovectorstream<boost::interprocess::string> formatter;
+ //Pre-reserve string size
+ std::size_t str_size = m_root_name.length()+10;
+ if(formatter.vector().size() < str_size){
+ //This can throw.
+ formatter.reserve(str_size);
+ }
+ //Format segment's name
+ formatter << m_root_name
+ << static_cast<unsigned int>(segment_id) << std::ends;
+ //This functor will be executed when constructing
+ create_open_func func(this, type, segment_id);
+ const char *name = formatter.vector().c_str();
+ //This can throw.
+ managed_impl mshm;
+
+ switch(type){
+ case create_open_func::DoCreate:
+ {
+ managed_impl shm(create_only, name, size, read_write, addr, func);
+ mshm = boost::move(shm);
+ }
+ break;
+
+ case create_open_func::DoOpen:
+ {
+ managed_impl shm(open_only, name,read_write, addr, func);
+ mshm = boost::move(shm);
+ }
+ break;
+
+ case create_open_func::DoOpenOrCreate:
+ {
+ managed_impl shm(open_or_create, name, size, read_write, addr, func);
+ mshm = boost::move(shm);
+ }
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ //This can throw.
+ m_shmem_list.push_back(boost::move(mshm));
+ return true;
+ }
+ BOOST_CATCH(const std::bad_alloc&){
+ }
+ BOOST_CATCH_END
+ return false;
+ }
+
+ //!Frees resources. Never throws.
+ void priv_close()
+ {
+ if(!m_shmem_list.empty()){
+ bool ret;
+ //Obtain group identifier
+ segment_group_id group = m_group_services.get_group();
+ //Erase main segment and its resources
+ shmem_list_t::iterator itbeg = m_shmem_list.begin(),
+ itend = m_shmem_list.end(),
+ it = itbeg;
+ //(*itbeg)->close_with_func(close_func(this));
+ //Delete group. All mappings are erased too.
+ ret = void_pointer::delete_group(group);
+ assert(ret);
+ m_shmem_list.clear();
+ }
+ }
+
+ private:
+ shmem_list_t m_shmem_list;
+ group_services m_group_services;
+ std::string m_root_name;
+};
+
+typedef basic_managed_multi_shared_memory
+ < char
+ , rbtree_best_fit<mutex_family, intersegment_ptr<void> >
+ , iset_index>
+ managed_multi_shared_memory;
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP
+
Added: sandbox/boost/interprocess/detail/managed_open_or_create_impl.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/managed_open_or_create_impl.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,444 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/move_semantics/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_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);
+ }
+
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ managed_open_or_create_impl(boost::rv<managed_open_or_create_impl> &moved)
+ { this->swap(moved.get()); }
+ #else
+ managed_open_or_create_impl(managed_open_or_create_impl &&moved)
+ { this->swap(moved); }
+ #endif
+
+ //!Move assignment. If *this owns a memory mapped region, it will be
+ //!destroyed and it will take ownership of "other"'s memory mapped region.
+ #ifndef BOOST_HAS_RVALUE_REFS
+ managed_open_or_create_impl &operator=(boost::rv<managed_open_or_create_impl> &moved)
+ {
+ managed_open_or_create_impl tmp(moved);
+ this->swap(tmp);
+ return *this;
+ }
+
+ #else
+ managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved)
+ {
+ managed_open_or_create_impl tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+ #endif
+
+ ~managed_open_or_create_impl()
+ {}
+
+ std::size_t get_user_size() const
+ { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; }
+
+ void *get_user_address() const
+ { return 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
Added: sandbox/boost/interprocess/detail/math_functions.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/math_functions.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/detail/min_max.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/min_max.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/mpl.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/mpl.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/multi_segment_services.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/multi_segment_services.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,46 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
+#define BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+
+/*!\file
+ Describes a named shared memory allocation user class.
+*/
+
+namespace boost {
+
+namespace interprocess {
+
+class multi_segment_services
+{
+ public:
+ virtual std::pair<void *, std::size_t> create_new_segment(std::size_t mem) = 0;
+ virtual bool update_segments () = 0;
+ virtual ~multi_segment_services() = 0;
+};
+
+inline multi_segment_services::~multi_segment_services()
+{}
+
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP
Added: sandbox/boost/interprocess/detail/named_proxy.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/named_proxy.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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/move_semantics/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::forward_constructor<Args>(get<IdxPack>(args_))...); }
+
+ template<int ...IdxPack>
+ void construct(void *mem, detail::false_, const index_tuple<IdxPack...>&)
+ { new((void*)mem)T(boost::forward_constructor<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::forward_constructor<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 rvalues 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
Added: sandbox/boost/interprocess/detail/os_file_functions.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/os_file_functions.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,443 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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>
+# 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{
+ 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 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 delete_file_on_reboot_if_possible(const char *filename)
+{ return winapi::move_file_ex(filename, 0, winapi::movefile_delay_until_reboot); }
+
+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 file_handle_t 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)
+{ return hnd; }
+
+inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd)
+{ return hnd; }
+
+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 delete_file_on_reboot_if_possible(const char *)
+{ //Function not implemented in POSIX functions
+ return false;
+}
+
+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); }
+
+#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
Added: sandbox/boost/interprocess/detail/os_thread_functions.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/os_thread_functions.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,136 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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 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_t p, pthread_t t)
+ : pid(p), tid(t)
+ {}
+ pid_t pid;
+ pthread_t 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
Added: sandbox/boost/interprocess/detail/pointer_type.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/pointer_type.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/posix_time_types_wrk.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/posix_time_types_wrk.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/preprocessor.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/preprocessor.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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::forward_constructor< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \
+//!
+
+#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \
+boost::forward_constructor< 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
Added: sandbox/boost/interprocess/detail/ptime_wrk.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/ptime_wrk.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+
Added: sandbox/boost/interprocess/detail/segment_manager_helper.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/segment_manager_helper.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,479 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org/libs/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
+#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/in_place_interface.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <cstddef> //std::size_t
+#include <string> //char_traits
+#include <new> //std::nothrow
+#include <utility> //std::pair
+#ifndef BOOST_NO_EXCEPTIONS
+#include <exception>
+#endif
+
+//!\file
+//!Describes the object placed in a memory segment that provides
+//!named object allocation capabilities.
+
+namespace boost{
+namespace interprocess{
+
+template<class MemoryManager>
+class segment_manager_base;
+
+//!An integer that describes the type of the
+//!instance constructed in memory
+enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type };
+
+namespace detail{
+
+template<class MemoryAlgorithm>
+class mem_algo_deallocator
+{
+ void * m_ptr;
+ MemoryAlgorithm & m_algo;
+
+ public:
+ mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo)
+ : m_ptr(ptr), m_algo(algo)
+ {}
+
+ void release()
+ { m_ptr = 0; }
+
+ ~mem_algo_deallocator()
+ { if(m_ptr) m_algo.deallocate(m_ptr); }
+};
+
+/// @cond
+struct block_header
+{
+ std::size_t m_value_bytes;
+ unsigned short m_num_char;
+ unsigned char m_value_alignment;
+ unsigned char m_alloc_type_sizeof_char;
+
+ block_header(std::size_t value_bytes
+ ,std::size_t value_alignment
+ ,std::size_t allocation_type
+ ,std::size_t sizeof_char
+ ,std::size_t num_char
+ )
+ : m_value_bytes(value_bytes)
+ , m_num_char(num_char)
+ , m_value_alignment(value_alignment)
+ , m_alloc_type_sizeof_char
+ ( ((unsigned char)allocation_type << 5u) |
+ ((unsigned char)sizeof_char & 0x1F) )
+ {};
+
+
+ template<class T>
+ block_header &operator= (const T& )
+ { return *this; }
+
+ std::size_t total_size() const
+ {
+ if(allocation_type() != anonymous_type){
+ return name_offset() + (m_num_char+1)*sizeof_char();
+ }
+ else{
+ return value_offset() + m_value_bytes;
+ }
+ }
+
+ std::size_t value_bytes() const
+ { return m_value_bytes; }
+
+ template<class Header>
+ std::size_t total_size_with_header() const
+ {
+ return get_rounded_size
+ ( sizeof(Header)
+ , detail::alignment_of<block_header>::value)
+ + total_size();
+ }
+
+ std::size_t allocation_type() const
+ { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }
+
+ std::size_t sizeof_char() const
+ { return m_alloc_type_sizeof_char & (unsigned char)0x1F; }
+
+ template<class CharType>
+ CharType *name() const
+ {
+ return 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 detail::
+ pointer_to_other<VoidPointer, const CharT>::type const_char_ptr_t;
+ typedef CharT char_type;
+
+ private:
+ //Offset pointer to the object's name
+ const_char_ptr_t mp_str;
+ //Length of the name buffer (null NOT included)
+ std::size_t m_len;
+ public:
+
+ //!Constructor of the key
+ index_key (const char_type *name, std::size_t length)
+ : mp_str(name), m_len(length) {}
+
+ //!Less than function for index ordering
+ bool operator < (const index_key & right) const
+ {
+ return (m_len < right.m_len) ||
+ (m_len == right.m_len &&
+ std::char_traits<char_type>::compare
+ (detail::get_pointer(mp_str)
+ ,detail::get_pointer(right.mp_str), m_len) < 0);
+ }
+
+ //!Equal to function for index ordering
+ bool operator == (const index_key & right) const
+ {
+ return m_len == right.m_len &&
+ std::char_traits<char_type>::compare
+ (detail::get_pointer(mp_str),
+ detail::get_pointer(right.mp_str), m_len) == 0;
+ }
+
+ void name(const CharT *name)
+ { mp_str = name; }
+
+ void name_length(std::size_t len)
+ { m_len = len; }
+
+ const CharT *name() const
+ { return detail::get_pointer(mp_str); }
+
+ std::size_t name_length() const
+ { return m_len; }
+};
+
+//!The index_data stores a pointer to a buffer and the element count needed
+//!to know how many destructors must be called when calling destroy
+template<class VoidPointer>
+struct index_data
+{
+ typedef VoidPointer void_pointer;
+ void_pointer m_ptr;
+ index_data(void *ptr) : m_ptr(ptr){}
+
+ void *value() const
+ { return 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 {
+
+}} //namespace boost { namespace interprocess
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
+
Added: sandbox/boost/interprocess/detail/tmp_dir_helpers.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/tmp_dir_helpers.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,157 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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)
+# include <boost/interprocess/detail/win32_api.hpp>
+#endif
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+#if (defined BOOST_INTERPROCESS_WINDOWS)
+
+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/";
+
+ 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;
+ tmp_name += bootstamp;
+ tmp_name += '/';
+ 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);
+ }
+ }
+
+ //Obtain bootstamp string
+ 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;
+
+ //Create a new subdirectory with the bootstamp
+ std::string root_tmp_name = tmp_name;
+ tmp_name += '/';
+ 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);
+
+ //Add filename
+ tmp_name += '/';
+ tmp_name += filename;
+}
+
+#else //POSIX SYSTEMS
+
+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/";
+ tmp_name += filename;
+}
+
+inline void create_tmp_dir_and_get_filename(const char *filename, std::string &tmp_name)
+{
+ const char *tmp_path = get_temporary_path();
+ if(!tmp_path){
+ error_info err = system_error_code();
+ throw interprocess_exception(err);
+ }
+
+ tmp_name = tmp_path;
+ tmp_name += "/boost_interprocess";
+
+ //Create the temporary directory.
+ //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);
+ }
+ }
+
+ //Add filename
+ tmp_name += '/';
+ tmp_name += filename;
+}
+
+#endif
+
+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
Added: sandbox/boost/interprocess/detail/type_traits.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/type_traits.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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>
+
Added: sandbox/boost/interprocess/detail/utilities.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/utilities.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,910 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/move_semantics/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 <boost/move_semantics/move.hpp>
+#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
+#include <boost/interprocess/detail/preprocessor.hpp>
+#endif
+#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); }
+
+ scoped_deallocator(scoped_deallocator &);
+ scoped_deallocator& operator=(scoped_deallocator &);
+
+ public:
+
+ BOOST_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()); }
+
+ #ifdef BOOST_HAS_RVALUE_REFS
+ scoped_deallocator(scoped_deallocator &&o)
+ : m_ptr(o.m_ptr), m_alloc(o.m_alloc)
+ {
+ #else
+ scoped_deallocator(boost::rv<scoped_deallocator> &mo)
+ : m_ptr(mo.get().m_ptr), m_alloc(mo.get().m_alloc)
+ {
+ scoped_deallocator &o = mo.get();
+ #endif
+ o.release();
+ }
+
+ pointer get() const
+ { return m_ptr; }
+
+ 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_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_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::move(c_));
+ }
+};
+
+template <class A>
+class allocator_multialloc_chain_array_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_array_deallocator(A &a)
+ : a_(a), c_()
+ {}
+
+ chain_builder get_chain_builder()
+ { return chain_builder(a_, c_); }
+
+ ~allocator_multialloc_chain_array_deallocator()
+ {
+ if(!c_.empty())
+ a_.deallocate_many(boost::move(c_));
+ }
+};
+
+//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;
+}
+
+
+template <class T1, class T2>
+struct pair
+{
+ BOOST_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)
+ {}
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template <class D, class S>
+ pair(boost::rv<std::pair<D, S> > &p)
+ : first(boost::move(p.get().first)), second(boost::move(p.get().second))
+ {}
+ #else
+ template <class D, class S>
+ pair(std::pair<D, S> && p)
+ : first(boost::move(p.first)), second(boost::move(p.second))
+ {}
+ #endif
+
+ 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)
+ {}
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ pair(boost::rv<pair<T1, T2> > &p)
+ : first(boost::move(p.get().first)), second(boost::move(p.get().second))
+ {}
+ #else
+ pair(pair<T1, T2> && p)
+ : first(boost::move(p.first)), second(boost::move(p.second))
+ {}
+ #endif
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template <class D, class S>
+ pair(boost::rv<pair<D, S> > &p)
+ : first(boost::move(p.get().first)), second(boost::move(p.get().second))
+ {}
+
+ #else
+
+ template <class D, class S>
+ pair(pair<D, S> && p)
+ : first(boost::move(p.first)), second(boost::move(p.second))
+ {}
+ #endif
+
+ #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
+
+ template<class U, class ...Args>
+ pair(U &&u, Args &&... args)
+ : first(boost::forward_constructor<U>(u))
+ , second(boost::forward_constructor<Args>(args)...)
+ {}
+
+ #else
+
+ template<class U>
+ pair( BOOST_INTERPROCESS_PARAM(U, u)
+ , typename detail::disable_if
+ < detail::is_same<U, boost::rv<pair> > >::type* = 0)
+ : first(boost::forward_constructor<U>(const_cast<U&>(u)))
+ {}
+
+ #define BOOST_PP_LOCAL_MACRO(n) \
+ template<class U, BOOST_PP_ENUM_PARAMS(n, class P)> \
+ pair(BOOST_INTERPROCESS_PARAM(U, u) \
+ ,BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \
+ : first(boost::forward_constructor<U>(const_cast<U&>(u))) \
+ , second(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \
+ {} \
+ //!
+ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS)
+ #include BOOST_PP_LOCAL_ITERATE()
+ #endif
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ pair& operator=(boost::rv<pair<T1, T2> > &p)
+ {
+ first = boost::move(p.get().first);
+ second = boost::move(p.get().second);
+ return *this;
+ }
+ #else
+ pair& operator=(pair<T1, T2> &&p)
+ {
+ first = boost::move(p.first);
+ second = boost::move(p.second);
+ return *this;
+ }
+ #endif
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ pair& operator=(boost::rv<std::pair<T1, T2> > &p)
+ {
+ first = boost::move(p.get().first);
+ second = boost::move(p.get().second);
+ return *this;
+ }
+ #else
+ pair& operator=(std::pair<T1, T2> &&p)
+ {
+ first = boost::move(p.first);
+ second = boost::move(p.second);
+ return *this;
+ }
+ #endif
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ template <class D, class S>
+ pair& operator=(boost::rv<std::pair<D, S> > &p)
+ {
+ first = boost::move(p.get().first);
+ second = boost::move(p.get().second);
+ return *this;
+ }
+ #else
+ template <class D, class S>
+ pair& operator=(std::pair<D, S> &&p)
+ {
+ first = boost::move(p.first);
+ second = boost::move(p.second);
+ return *this;
+ }
+ #endif
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ void swap(boost::rv<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_HAS_RVALUE_REFS
+template <class T1, class T2>
+inline void swap(boost::rv<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, boost::rv<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
+
+namespace detail {
+
+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 MultiallocationChain, class T>
+class transform_multiallocation_chain
+{
+ private:
+
+ MultiallocationChain holder_;
+ typedef typename MultiallocationChain::void_pointer void_pointer;
+ typedef typename detail::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*>(detail::get_pointer(p)));
+ }
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(transform_multiallocation_chain)
+
+ typedef transform_iterator
+ < typename MultiallocationChain::iterator
+ , 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_()
+ {}
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ transform_multiallocation_chain(boost::rv<transform_multiallocation_chain> &other)
+ #else
+ transform_multiallocation_chain(transform_multiallocation_chain &&other)
+ #endif
+ : holder_()
+ { this->swap(other); }
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ transform_multiallocation_chain(boost::rv<MultiallocationChain> &other)
+ #else
+ transform_multiallocation_chain(MultiallocationChain &&other)
+ #endif
+ : holder_(boost::move(other))
+ {}
+
+ #ifndef BOOST_HAS_RVALUE_REFS
+ transform_multiallocation_chain& operator=(boost::rv<transform_multiallocation_chain> &other)
+ #else
+ transform_multiallocation_chain& operator=(transform_multiallocation_chain &&other)
+ #endif
+ {
+ transform_multiallocation_chain tmp(boost::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::move(holder_));
+ }
+};
+
+template<class T>
+struct value_init
+{
+ value_init()
+ : m_t()
+ {}
+
+ T m_t;
+};
+
+} //namespace detail {
+
+///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
+
Added: sandbox/boost/interprocess/detail/variadic_templates_tools.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/variadic_templates_tools.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/detail/version_type.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/version_type.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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/interprocess for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This code comes from N1953 document by Howard E. Hinnant
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP
+#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP
+
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+
+
+namespace boost{
+namespace interprocess{
+namespace detail{
+
+//using namespace boost;
+
+template <class T, unsigned V>
+struct version_type
+ : public detail::integral_constant<unsigned, V>
+{
+ typedef T type;
+
+ version_type(const version_type<T, 0>&);
+};
+
+namespace impl{
+
+template <class T,
+ bool = 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 detail::integral_constant<unsigned, impl::version<T>::value>
+{
+};
+
+} //namespace detail{
+} //namespace interprocess{
+} //namespace boost{
+
+#endif //#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP
Added: sandbox/boost/interprocess/detail/win32_api.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/win32_api.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,884 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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)
+{
+ 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;
+}
+
+} //namespace winapi
+} //namespace interprocess
+} //namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifdef BOOST_INTERPROCESS_WIN32_SYNC_PRIMITIVES_HPP
Added: sandbox/boost/interprocess/detail/workaround.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/detail/workaround.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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_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
+ //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 __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
+// C++0x features are only enabled when -std=c++0x or -std=gnu++0x are
+// passed on the command line, which in turn defines
+// __GXX_EXPERIMENTAL_CXX0X__. Note: __GXX_EXPERIMENTAL_CPP0X__ is
+// defined by some very early development versions of GCC 4.3; we will
+// remove this part of the check in the near future.
+# if defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_HAS_RVALUE_REFS
+# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES
+# if defined(__GLIBCPP__) || defined(__GLIBCXX__)
+# define BOOST_INTERPROCESS_RVALUE_PAIR
+# endif
+# endif
+#endif
+
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_INTERPROCESS_VARIADIC_TEMPLATES)
+#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
Added: sandbox/boost/interprocess/errors.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/errors.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,229 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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
+};
+
+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 }
+ #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
Added: sandbox/boost/interprocess/exceptions.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/exceptions.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/file_mapping.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/file_mapping.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,201 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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/move_semantics/move.hpp>
+#include <string> //std::string
+#include <cstdio> //std::remove
+#include <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_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
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ file_mapping(boost::rv<file_mapping> &moved)
+ : m_handle(file_handle_t(detail::invalid_file()))
+ { this->swap(moved); }
+ #else
+ file_mapping(file_mapping &&moved)
+ : m_handle(file_handle_t(detail::invalid_file()))
+ { this->swap(moved); }
+ #endif
+
+ //!Moves the ownership of "moved"'s file mapping to *this.
+ //!After the call, "moved" does not represent any file mapping.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ file_mapping &operator=(boost::rv<file_mapping> &moved)
+ #else
+ file_mapping &operator=(file_mapping &&moved)
+ #endif
+ {
+ file_mapping tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Swaps to file_mappings.
+ //!Does not throw.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<file_mapping> &moved)
+ { this->swap(moved.get()); }
+ void swap(file_mapping &other);
+ #else
+ void swap(file_mapping &&other);
+ #endif
+
+ //!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;
+
+ /// @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(); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+inline void file_mapping::swap(file_mapping &other)
+#else
+inline void file_mapping::swap(file_mapping &&other)
+#endif
+{
+ 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;
+}
+
+///@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 call std::remove(name) 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()
+ { std::remove(m_name); }
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP
Added: sandbox/boost/interprocess/indexes/flat_map_index.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/indexes/flat_map_index.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/indexes/iset_index.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/indexes/iset_index.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/indexes/iunordered_set_index.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/indexes/iunordered_set_index.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
+ (try_shrink_in_place | 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
+ (shrink_in_place | 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
+ (expand_fwd | 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
Added: sandbox/boost/interprocess/indexes/map_index.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/indexes/map_index.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/indexes/null_index.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/indexes/null_index.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/indexes/unordered_map_index.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/indexes/unordered_map_index.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/interprocess_fwd.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/interprocess_fwd.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,482 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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;
+
+#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;
+
+//////////////////////////////////////////////////////////////////////////////
+// Containers
+//////////////////////////////////////////////////////////////////////////////
+
+//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 {
+
+//#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_FWD_HPP
+
Added: sandbox/boost/interprocess/ipc/message_queue.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/ipc/message_queue.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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
Added: sandbox/boost/interprocess/managed_external_buffer.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/managed_external_buffer.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,123 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MANAGED_EXTERNAL_BUFFER_HPP
+#define BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <cassert>
+
+//!\file
+//!Describes a named user memory allocation user class.
+
+namespace boost {
+namespace interprocess {
+
+//!A basic user memory named object creation class. Inherits all
+//!basic functionality from
+//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
+template
+ <
+ class CharType,
+ class AllocationAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_external_buffer
+ : public detail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
+{
+ /// @cond
+ typedef detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType> base_t;
+ basic_managed_external_buffer(basic_managed_external_buffer&);
+ basic_managed_external_buffer & operator=(basic_managed_external_buffer&);
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(basic_managed_external_buffer)
+
+ //!Default constructor. Does nothing.
+ //!Useful in combination with move semantics
+ basic_managed_external_buffer()
+ {}
+
+ //!Creates and places the segment manager. This can throw
+ basic_managed_external_buffer
+ (create_only_t, void *addr, std::size_t size)
+ {
+ //Check if alignment is correct
+ assert((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - std::size_t(1u)))));
+ if(!base_t::create_impl(addr, size)){
+ throw interprocess_exception();
+ }
+ }
+
+ //!Creates and places the segment manager. This can throw
+ basic_managed_external_buffer
+ (open_only_t, void *addr, std::size_t size)
+ {
+ //Check if alignment is correct
+ assert((0 == (((std::size_t)addr) & (AllocationAlgorithm::Alignment - std::size_t(1u)))));
+ if(!base_t::open_impl(addr, size)){
+ throw interprocess_exception();
+ }
+ }
+
+ //!Moves the ownership of "moved"'s managed memory to *this. Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_external_buffer(boost::rv<basic_managed_external_buffer> &moved)
+ #else
+ basic_managed_external_buffer(basic_managed_external_buffer &&moved)
+ #endif
+ {
+ this->swap(moved);
+ }
+
+ //!Moves the ownership of "moved"'s managed memory to *this. Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_external_buffer &operator=(boost::rv<basic_managed_external_buffer> &moved)
+ #else
+ basic_managed_external_buffer &operator=(basic_managed_external_buffer &&moved)
+ #endif
+ {
+ basic_managed_external_buffer tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ void grow(std::size_t extra_bytes)
+ { base_t::grow(extra_bytes); }
+
+ //!Swaps the ownership of the managed heap memories managed by *this and other.
+ //!Never throws.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_managed_external_buffer> &moved)
+ { this->swap(moved.get()); }
+ void swap(basic_managed_external_buffer &other)
+ #else
+ void swap(basic_managed_external_buffer &&other)
+ #endif
+ { base_t::swap(other); }
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_EXTERNAL_BUFFER_HPP
+
Added: sandbox/boost/interprocess/managed_heap_memory.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/managed_heap_memory.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,160 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MANAGED_HEAP_MEMORY_HPP
+#define BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <vector>
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+
+//!\file
+//!Describes a named heap memory allocation user class.
+
+namespace boost {
+namespace interprocess {
+
+//!A basic heap memory named object creation class. Initializes the
+//!heap memory segment. Inherits all basic functionality from
+//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
+template
+ <
+ class CharType,
+ class AllocationAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_heap_memory
+ : public detail::basic_managed_memory_impl <CharType, AllocationAlgorithm, IndexType>
+{
+ /// @cond
+ private:
+
+ typedef detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType> base_t;
+ basic_managed_heap_memory(basic_managed_heap_memory&);
+ basic_managed_heap_memory & operator=(basic_managed_heap_memory&);
+ /// @endcond
+
+ public: //functions
+ BOOST_ENABLE_MOVE_EMULATION(basic_managed_heap_memory)
+
+ //!Default constructor. Does nothing.
+ //!Useful in combination with move semantics
+ basic_managed_heap_memory(){}
+
+ //!Destructor. Liberates the heap memory holding the managed data.
+ //!Never throws.
+ ~basic_managed_heap_memory()
+ { this->priv_close(); }
+
+ //!Creates heap memory and initializes the segment manager.
+ //!This can throw.
+ basic_managed_heap_memory(std::size_t size)
+ : m_heapmem(size, char(0))
+ {
+ if(!base_t::create_impl(&m_heapmem[0], size)){
+ this->priv_close();
+ throw interprocess_exception();
+ }
+ }
+
+ //!Moves the ownership of "moved"'s managed memory to *this. Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_heap_memory(boost::rv<basic_managed_heap_memory> &moved)
+ #else
+ basic_managed_heap_memory(basic_managed_heap_memory &&moved)
+ #endif
+ {
+ this->swap(moved);
+ }
+
+ //!Moves the ownership of "moved"'s managed memory to *this. Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_heap_memory &operator=(boost::rv<basic_managed_heap_memory> &moved)
+ #else
+ basic_managed_heap_memory &operator=(basic_managed_heap_memory &&moved)
+ #endif
+ {
+ basic_managed_heap_memory tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Tries to resize internal heap memory so that
+ //!we have room for more objects.
+ //!WARNING: If memory is reallocated, all the objects will
+ //!be binary-copied to the new buffer. To be able to use
+ //!this function, all pointers constructed in this buffer
+ //!must be offset pointers. Otherwise, the result is undefined.
+ //!Returns true if the growth has been successful, so you will
+ //!have some extra bytes to allocate new objects. If returns
+ //!false, the heap allocation has failed.
+ bool grow(std::size_t extra_bytes)
+ {
+ //If memory is reallocated, data will
+ //be automatically copied
+ BOOST_TRY{
+ m_heapmem.resize(m_heapmem.size()+extra_bytes);
+ }
+ BOOST_CATCH(...){
+ return false;
+ }
+ BOOST_CATCH_END
+
+ //Grow always works
+ base_t::close_impl();
+ base_t::open_impl(&m_heapmem[0], m_heapmem.size());
+ base_t::grow(extra_bytes);
+ return true;
+ }
+
+ //!Swaps the ownership of the managed heap memories managed by *this and other.
+ //!Never throws.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_managed_heap_memory> &moved)
+ { this->swap(moved.get()); }
+ void swap(basic_managed_heap_memory &other)
+ #else
+ void swap(basic_managed_heap_memory &&other)
+ #endif
+ {
+ base_t::swap(other);
+ m_heapmem.swap(other.m_heapmem);
+ }
+
+ /// @cond
+ private:
+ //!Frees resources. Never throws.
+ void priv_close()
+ {
+ base_t::destroy_impl();
+ std::vector<char>().swap(m_heapmem);
+ }
+
+ std::vector<char> m_heapmem;
+ /// @endcond
+};
+
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_HEAP_MEMORY_HPP
+
Added: sandbox/boost/interprocess/managed_mapped_file.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/managed_mapped_file.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,222 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MANAGED_MAPPED_FILE_HPP
+#define BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/detail/file_wrapper.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/file_mapping.hpp>
+
+namespace boost {
+namespace interprocess {
+
+//!A basic mapped file named object creation class. Initializes the
+//!mapped file. Inherits all basic functionality from
+//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
+template
+ <
+ class CharType,
+ class AllocationAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_mapped_file
+ : public detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType
+ ,detail::managed_open_or_create_impl<detail::file_wrapper>::ManagedOpenOrCreateUserOffset>
+{
+ /// @cond
+ public:
+ typedef detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType,
+ detail::managed_open_or_create_impl<detail::file_wrapper>::ManagedOpenOrCreateUserOffset> base_t;
+ typedef detail::file_wrapper device_type;
+ basic_managed_mapped_file(basic_managed_mapped_file&);
+ basic_managed_mapped_file & operator=(basic_managed_mapped_file&);
+
+ private:
+
+ typedef detail::create_open_func<base_t> create_open_func_t;
+ typedef detail::managed_open_or_create_impl<detail::file_wrapper> managed_open_or_create_type;
+
+ basic_managed_mapped_file *get_this_pointer()
+ { return this; }
+
+ private:
+ typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
+ /// @endcond
+
+ public: //functions
+ BOOST_ENABLE_MOVE_EMULATION(basic_managed_mapped_file)
+
+ //!Creates mapped file and creates and places the segment manager.
+ //!This can throw.
+ basic_managed_mapped_file()
+ {}
+
+ //!Creates mapped file and creates and places the segment manager.
+ //!This can throw.
+ basic_managed_mapped_file(create_only_t create_only, const char *name,
+ std::size_t size, const void *addr = 0)
+ : m_mfile(create_only, name, size, read_write, addr,
+ create_open_func_t(get_this_pointer(), detail::DoCreate))
+ {}
+
+ //!Creates mapped file and creates and places the segment manager if
+ //!segment was not created. If segment was created it connects to the
+ //!segment.
+ //!This can throw.
+ basic_managed_mapped_file (open_or_create_t open_or_create,
+ const char *name, std::size_t size,
+ const void *addr = 0)
+ : m_mfile(open_or_create, name, size, read_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpenOrCreate))
+ {}
+
+ //!Connects to a created mapped file and its segment manager.
+ //!This can throw.
+ basic_managed_mapped_file (open_only_t open_only, const char* name,
+ const void *addr = 0)
+ : m_mfile(open_only, name, read_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Connects to a created mapped file and its segment manager
+ //!in copy_on_write mode.
+ //!This can throw.
+ basic_managed_mapped_file (open_copy_on_write_t, const char* name,
+ const void *addr = 0)
+ : m_mfile(open_only, name, copy_on_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Connects to a created mapped file and its segment manager
+ //!in read-only mode.
+ //!This can throw.
+ basic_managed_mapped_file (open_read_only_t, const char* name,
+ const void *addr = 0)
+ : m_mfile(open_only, name, read_only, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Moves the ownership of "moved"'s managed memory to *this.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_mapped_file(boost::rv<basic_managed_mapped_file> &moved)
+ #else
+ basic_managed_mapped_file(basic_managed_mapped_file &&moved)
+ #endif
+ {
+ this->swap(moved);
+ }
+
+ //!Moves the ownership of "moved"'s managed memory to *this.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_mapped_file &operator=(boost::rv<basic_managed_mapped_file> &moved)
+ #else
+ basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved)
+ #endif
+ {
+ basic_managed_mapped_file tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~basic_managed_mapped_file()
+ {}
+
+ //!Swaps the ownership of the managed mapped memories managed by *this and other.
+ //!Never throws.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_managed_mapped_file> &moved)
+ { this->swap(moved.get()); }
+
+ void swap(basic_managed_mapped_file &other)
+ #else
+ void swap(basic_managed_mapped_file &&other)
+ #endif
+ {
+ base_t::swap(other);
+ m_mfile.swap(other.m_mfile);
+ }
+
+ //!Flushes cached data to file.
+ //!Never throws
+ bool flush()
+ { return m_mfile.flush(); }
+
+ //!Tries to resize mapped file so that we have room for
+ //!more objects.
+ //!
+ //!This function is not synchronized so no other thread or process should
+ //!be reading or writing the file
+ static bool grow(const char *filename, std::size_t extra_bytes)
+ {
+ return base_t::template grow
+ <basic_managed_mapped_file>(filename, extra_bytes);
+ }
+
+ //!Tries to resize mapped file to minimized the size of the file.
+ //!
+ //!This function is not synchronized so no other thread or process should
+ //!be reading or writing the file
+ static bool shrink_to_fit(const char *filename)
+ {
+ return base_t::template shrink_to_fit
+ <basic_managed_mapped_file>(filename);
+ }
+
+ /// @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 (char_ptr_holder_t name)
+ {
+ if(m_mfile.get_mapped_region().get_mode() == read_only){
+ return base_t::template find_no_lock<T>(name);
+ }
+ else{
+ return base_t::template find<T>(name);
+ }
+ }
+
+ private:
+ managed_open_or_create_type m_mfile;
+ /// @endcond
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
Added: sandbox/boost/interprocess/managed_shared_memory.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/managed_shared_memory.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,224 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MANAGED_SHARED_MEMORY_HPP
+#define BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+//!A basic shared memory named object creation class. Initializes the
+//!shared memory segment. Inherits all basic functionality from
+//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
+template
+ <
+ class CharType,
+ class AllocationAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_shared_memory
+ : public detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType
+ ,detail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset>
+ , private detail::managed_open_or_create_impl<shared_memory_object>
+{
+ /// @cond
+ public:
+ typedef shared_memory_object device_type;
+
+ private:
+ typedef detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType,
+ detail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset> base_t;
+ typedef detail::managed_open_or_create_impl
+ <shared_memory_object> base2_t;
+
+ typedef detail::create_open_func<base_t> create_open_func_t;
+
+ basic_managed_shared_memory *get_this_pointer()
+ { return this; }
+
+ private:
+ typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
+ basic_managed_shared_memory(basic_managed_shared_memory&);
+ basic_managed_shared_memory & operator=(basic_managed_shared_memory&);
+ /// @endcond
+
+ public: //functions
+ BOOST_ENABLE_MOVE_EMULATION(basic_managed_shared_memory)
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~basic_managed_shared_memory()
+ {}
+
+ //!Default constructor. Does nothing.
+ //!Useful in combination with move semantics
+ basic_managed_shared_memory()
+ {}
+
+ //!Creates shared memory and creates and places the segment manager.
+ //!This can throw.
+ basic_managed_shared_memory(create_only_t create_only, const char *name,
+ std::size_t size, const void *addr = 0)
+ : base_t()
+ , base2_t(create_only, name, size, read_write, addr,
+ create_open_func_t(get_this_pointer(), detail::DoCreate))
+ {}
+
+ //!Creates shared memory and creates and places the segment manager if
+ //!segment was not created. If segment was created it connects to the
+ //!segment.
+ //!This can throw.
+ basic_managed_shared_memory (open_or_create_t open_or_create,
+ const char *name, std::size_t size,
+ const void *addr = 0)
+ : base_t()
+ , base2_t(open_or_create, name, size, read_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpenOrCreate))
+ {}
+
+ //!Connects to a created shared memory and its segment manager.
+ //!in copy_on_write mode.
+ //!This can throw.
+ basic_managed_shared_memory (open_copy_on_write_t, const char* name,
+ const void *addr = 0)
+ : base_t()
+ , base2_t(open_only, name, copy_on_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Connects to a created shared memory and its segment manager.
+ //!in read-only mode.
+ //!This can throw.
+ basic_managed_shared_memory (open_read_only_t, const char* name,
+ const void *addr = 0)
+ : base_t()
+ , base2_t(open_only, name, read_only, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Connects to a created shared memory and its segment manager.
+ //!This can throw.
+ basic_managed_shared_memory (open_only_t open_only, const char* name,
+ const void *addr = 0)
+ : base_t()
+ , base2_t(open_only, name, read_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Moves the ownership of "moved"'s managed memory to *this.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_shared_memory(boost::rv<basic_managed_shared_memory> &moved)
+ #else
+ basic_managed_shared_memory(basic_managed_shared_memory &&moved)
+ #endif
+ {
+ basic_managed_shared_memory tmp;
+ this->swap(moved);
+ tmp.swap(moved);
+ }
+
+ //!Moves the ownership of "moved"'s managed memory to *this.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_shared_memory &operator=(boost::rv<basic_managed_shared_memory> &moved)
+ #else
+ basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved)
+ #endif
+ {
+ basic_managed_shared_memory tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Swaps the ownership of the managed shared memories managed by *this and other.
+ //!Never throws.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_managed_shared_memory> &moved)
+ { this->swap(moved.get()); }
+ void swap(basic_managed_shared_memory &other)
+ #else
+ void swap(basic_managed_shared_memory &&other)
+ #endif
+ {
+ base_t::swap(other);
+ base2_t::swap(other);
+ }
+
+ //!Tries to resize the managed shared memory object so that we have
+ //!room for more objects.
+ //!
+ //!This function is not synchronized so no other thread or process should
+ //!be reading or writing the file
+ static bool grow(const char *filename, std::size_t extra_bytes)
+ {
+ return base_t::template grow
+ <basic_managed_shared_memory>(filename, extra_bytes);
+ }
+
+ //!Tries to resize the managed shared memory to minimized the size of the file.
+ //!
+ //!This function is not synchronized so no other thread or process should
+ //!be reading or writing the file
+ static bool shrink_to_fit(const char *filename)
+ {
+ return base_t::template shrink_to_fit
+ <basic_managed_shared_memory>(filename);
+ }
+
+ /// @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 (char_ptr_holder_t name)
+ {
+ if(base2_t::get_mapped_region().get_mode() == read_only){
+ return base_t::template find_no_lock<T>(name);
+ }
+ else{
+ return base_t::template find<T>(name);
+ }
+ }
+
+ /// @endcond
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
+
Added: sandbox/boost/interprocess/managed_windows_shared_memory.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/managed_windows_shared_memory.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,198 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MANAGED_WINDOWS_SHARED_MEMORY_HPP
+#define BOOST_INTERPROCESS_MANAGED_WINDOWS_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_open_or_create_impl.hpp>
+#include <boost/interprocess/detail/managed_memory_impl.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/windows_shared_memory.hpp>
+#include <boost/move_semantics/move.hpp>
+
+namespace boost {
+namespace interprocess {
+
+//!A basic managed windows shared memory creation class. Initializes the
+//!shared memory segment. Inherits all basic functionality from
+//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
+//!Unlike basic_managed_shared_memory, it has
+//!no kernel persistence and the shared memory is destroyed
+//!when all processes destroy all their windows_shared_memory
+//!objects and mapped regions for the same shared memory
+//!or the processes end/crash.
+//!
+//!Warning: basic_managed_windows_shared_memory and
+//!basic_managed_shared_memory can't communicate between them.
+template
+ <
+ class CharType,
+ class AllocationAlgorithm,
+ template<class IndexConfig> class IndexType
+ >
+class basic_managed_windows_shared_memory
+ : public detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType
+ ,detail::managed_open_or_create_impl<windows_shared_memory>::ManagedOpenOrCreateUserOffset>
+{
+ /// @cond
+ private:
+ typedef detail::basic_managed_memory_impl
+ <CharType, AllocationAlgorithm, IndexType,
+ detail::managed_open_or_create_impl<windows_shared_memory>::ManagedOpenOrCreateUserOffset> base_t;
+ typedef detail::create_open_func<base_t> create_open_func_t;
+
+ basic_managed_windows_shared_memory *get_this_pointer()
+ { return this; }
+
+ private:
+ typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
+ basic_managed_windows_shared_memory(basic_managed_windows_shared_memory&);
+ basic_managed_windows_shared_memory & operator=(basic_managed_windows_shared_memory&);
+
+ /// @endcond
+
+ public: //functions
+ BOOST_ENABLE_MOVE_EMULATION(basic_managed_windows_shared_memory)
+
+ //!Default constructor. Does nothing.
+ //!Useful in combination with move semantics
+ basic_managed_windows_shared_memory()
+ {}
+
+ //!Creates shared memory and creates and places the segment manager.
+ //!This can throw.
+ basic_managed_windows_shared_memory
+ (create_only_t create_only, const char *name,
+ std::size_t size, const void *addr = 0)
+ : m_wshm(create_only, name, size, read_write, addr,
+ create_open_func_t(get_this_pointer(), detail::DoCreate))
+ {}
+
+ //!Creates shared memory and creates and places the segment manager if
+ //!segment was not created. If segment was created it connects to the
+ //!segment.
+ //!This can throw.
+ basic_managed_windows_shared_memory
+ (open_or_create_t open_or_create,
+ const char *name, std::size_t size,
+ const void *addr = 0)
+ : m_wshm(open_or_create, name, size, read_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpenOrCreate))
+ {}
+
+ //!Connects to a created shared memory and its segment manager.
+ //!This can throw.
+ basic_managed_windows_shared_memory
+ (open_only_t open_only, const char* name, const void *addr = 0)
+ : m_wshm(open_only, name, read_write, addr,
+ create_open_func_t(get_this_pointer(),
+ detail::DoOpen))
+ {}
+
+ //!Connects to a created shared memory and its segment manager
+ //!in copy_on_write mode.
+ //!This can throw.
+ basic_managed_windows_shared_memory
+ (open_copy_on_write_t, const char* name, const void *addr = 0)
+ : m_wshm(open_only, name, copy_on_write, addr,
+ create_open_func_t(get_this_pointer(), detail::DoOpen))
+ {}
+
+ //!Connects to a created shared memory and its segment manager
+ //!in read-only mode.
+ //!This can throw.
+ basic_managed_windows_shared_memory
+ (open_read_only_t, const char* name, const void *addr = 0)
+ : base_t()
+ , m_wshm(open_only, name, read_only, addr,
+ create_open_func_t(get_this_pointer(), detail::DoOpen))
+ {}
+
+ //!Moves the ownership of "moved"'s managed memory to *this.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_windows_shared_memory
+ (boost::rv<basic_managed_windows_shared_memory> &moved)
+ { this->swap(moved.get()); }
+ #else
+ basic_managed_windows_shared_memory(basic_managed_windows_shared_memory &&moved)
+ { this->swap(moved); }
+ #endif
+
+ //!Moves the ownership of "moved"'s managed memory to *this.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ basic_managed_windows_shared_memory &operator=(boost::rv<basic_managed_windows_shared_memory> &moved)
+ #else
+ basic_managed_windows_shared_memory &operator=(basic_managed_windows_shared_memory &&moved)
+ #endif
+ {
+ basic_managed_windows_shared_memory tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. All mapped regions are still valid after
+ //!destruction. When all mapped regions and basic_managed_windows_shared_memory
+ //!objects referring the shared memory are destroyed, the
+ //!operating system will destroy the shared memory.
+ ~basic_managed_windows_shared_memory()
+ {}
+
+ //!Swaps the ownership of the managed mapped memories managed by *this and other.
+ //!Never throws.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<basic_managed_windows_shared_memory> &moved)
+ { this->swap(moved.get()); }
+ void swap(basic_managed_windows_shared_memory &other)
+ #else
+ void swap(basic_managed_windows_shared_memory &&other)
+ #endif
+ {
+ base_t::swap(other);
+ m_wshm.swap(other.m_wshm);
+ }
+
+ /// @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 (char_ptr_holder_t name)
+ {
+ if(m_wshm.get_mapped_region().get_mode() == read_only){
+ return base_t::template find_no_lock<T>(name);
+ }
+ else{
+ return base_t::template find<T>(name);
+ }
+ }
+
+ private:
+ detail::managed_open_or_create_impl<windows_shared_memory, false> m_wshm;
+ /// @endcond
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MANAGED_WINDOWS_SHARED_MEMORY_HPP
Added: sandbox/boost/interprocess/mapped_region.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mapped_region.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,595 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MAPPED_REGION_HPP
+#define BOOST_INTERPROCESS_MAPPED_REGION_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/move_semantics/move.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/os_file_functions.hpp>
+#include <string>
+#include <limits>
+
+#if (defined BOOST_INTERPROCESS_WINDOWS)
+# include <boost/interprocess/detail/win32_api.hpp>
+#else
+# ifdef BOOST_HAS_UNISTD_H
+# include <fcntl.h>
+# include <sys/mman.h> //mmap
+# include <unistd.h>
+# include <sys/stat.h>
+# include <sys/types.h>
+# else
+# error Unknown platform
+# endif
+
+#endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
+
+//!\file
+//!Describes memory_mappable and mapped region classes
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail{ class interprocess_tester; }
+namespace detail{ class raw_mapped_region_creator; }
+
+/// @endcond
+
+//!The mapped_region class represents a portion or region created from a
+//!memory_mappable object.
+class mapped_region
+{
+ /// @cond
+ //Non-copyable
+ mapped_region(mapped_region &);
+ mapped_region &operator=(mapped_region &);
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(mapped_region)
+
+ //!Creates a mapping region of the mapped memory "mapping", starting in
+ //!offset "offset", and the mapping's size will be "size". The mapping
+ //!can be opened for read-only "read_only" or read-write
+ //!"read_write.
+ template<class MemoryMappable>
+ mapped_region(const MemoryMappable& mapping
+ ,mode_t mode
+ ,offset_t offset = 0
+ ,std::size_t size = 0
+ ,const void *address = 0);
+
+ //!Default constructor. Address and size and offset will be 0.
+ //!Does not throw
+ mapped_region();
+
+ //!Move constructor. *this will be constructed taking ownership of "other"'s
+ //!region and "other" will be left in default constructor state.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ mapped_region(boost::rv<mapped_region> &other);
+ #else
+ mapped_region(mapped_region &&other);
+ #endif
+
+ //!Destroys the mapped region.
+ //!Does not throw
+ ~mapped_region();
+
+ //!Move assignment. If *this owns a memory mapped region, it will be
+ //!destroyed and it will take ownership of "other"'s memory mapped region.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ mapped_region &operator=(boost::rv<mapped_region> &other);
+ #else
+ mapped_region &operator=(mapped_region &&other);
+ #endif
+
+ //!Returns the size of the mapping. Note for windows users: If
+ //!windows_shared_memory is mapped using 0 as the size, it returns 0
+ //!because the size is unknown. Never throws.
+ std::size_t get_size() const;
+
+ //!Returns the base address of the mapping.
+ //!Never throws.
+ void* get_address() const;
+
+ //!Returns the offset of the mapping from the beginning of the
+ //!mapped memory. Never throws.
+ offset_t get_offset() const;
+
+ //!Returns the mode of the mapping used to construct the mapped file.
+ //!Never throws.
+ mode_t get_mode() const;
+
+ //!Flushes to the disk a byte range within the mapped memory.
+ //!Never throws
+ bool flush(std::size_t mapping_offset = 0, std::size_t numbytes = 0);
+
+ //!Swaps the mapped_region with another
+ //!mapped region
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<mapped_region> &moved)
+ { this->swap(moved.get()); }
+ void swap(mapped_region &other);
+ #else
+ void swap(mapped_region &&other);
+ #endif
+
+ //!Returns the size of the page. This size is the minimum memory that
+ //!will be used by the system when mapping a memory mappable source.
+ static std::size_t get_page_size();
+
+ /// @cond
+ private:
+ //!Closes a previously opened memory mapping. Never throws
+ void priv_close();
+
+ template<int dummy>
+ struct page_size_holder
+ {
+ static const std::size_t PageSize;
+ static std::size_t get_page_size();
+ };
+
+ void* m_base;
+ std::size_t m_size;
+ offset_t m_offset;
+ offset_t m_extra_offset;
+ mode_t m_mode;
+ #if (defined BOOST_INTERPROCESS_WINDOWS)
+ file_handle_t m_file_mapping_hnd;
+ #endif
+
+ friend class detail::interprocess_tester;
+ friend class detail::raw_mapped_region_creator;
+ void dont_close_on_destruction();
+ /// @endcond
+};
+
+///@cond
+
+inline void swap(mapped_region &x, mapped_region &y)
+{ x.swap(y); }
+
+#ifndef BOOST_HAS_RVALUE_REFS
+inline mapped_region &mapped_region::operator=(boost::rv<mapped_region> &moved)
+{
+#else
+inline mapped_region &mapped_region::operator=(mapped_region &&moved)
+{
+#endif
+ mapped_region tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+}
+
+inline mapped_region::~mapped_region()
+{ this->priv_close(); }
+
+inline std::size_t mapped_region::get_size() const
+{ return m_size; }
+
+inline offset_t mapped_region::get_offset() const
+{ return m_offset; }
+
+inline mode_t mapped_region::get_mode() const
+{ return m_mode; }
+
+inline void* mapped_region::get_address() const
+{ return m_base; }
+
+#if (defined BOOST_INTERPROCESS_WINDOWS)
+
+inline mapped_region::mapped_region()
+ : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only)
+ , m_file_mapping_hnd(detail::invalid_file())
+{}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+inline mapped_region::mapped_region(boost::rv<mapped_region> &other)
+ : m_base(0), m_size(0), m_offset(0)
+ , m_extra_offset(0)
+ , m_mode(read_only)
+ , m_file_mapping_hnd(detail::invalid_file())
+{ this->swap(other); }
+#else
+inline mapped_region::mapped_region(mapped_region &&other)
+ : m_base(0), m_size(0), m_offset(0)
+ , m_extra_offset(0)
+ , m_mode(read_only)
+ , m_file_mapping_hnd(detail::invalid_file())
+{ this->swap(other); }
+#endif
+
+template<int dummy>
+inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size()
+{
+ winapi::system_info info;
+ get_system_info(&info);
+ return std::size_t(info.dwAllocationGranularity);
+}
+
+template<class MemoryMappable>
+inline mapped_region::mapped_region
+ (const MemoryMappable &mapping
+ ,mode_t mode
+ ,offset_t offset
+ ,std::size_t size
+ ,const void *address)
+ : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode)
+ , m_file_mapping_hnd(detail::invalid_file())
+{
+ mapping_handle_t mhandle = mapping.get_mapping_handle();
+ file_handle_t native_mapping_handle = 0;
+
+ //Set accesses
+ unsigned long file_map_access = 0;
+ unsigned long map_access = 0;
+
+ switch(mode)
+ {
+ case read_only:
+ file_map_access |= winapi::page_readonly;
+ map_access |= winapi::file_map_read;
+ break;
+ case read_write:
+ file_map_access |= winapi::page_readwrite;
+ map_access |= winapi::file_map_write;
+ break;
+ case copy_on_write:
+ file_map_access |= winapi::page_writecopy;
+ map_access |= winapi::file_map_copy;
+ break;
+ default:
+ {
+ error_info err(mode_error);
+ throw interprocess_exception(err);
+ }
+ break;
+ }
+
+ if(!mhandle.is_shm){
+ //Update mapping size if the user does not specify it
+ if(size == 0){
+ __int64 total_size;
+ if(!winapi::get_file_size(detail::file_handle_from_mapping_handle(mapping.get_mapping_handle()), total_size)){
+ error_info err(winapi::get_last_error());
+ throw interprocess_exception(err);
+ }
+ #ifdef max
+ #undef max
+ #endif
+
+ if(static_cast<unsigned __int64>(total_size) >
+ std::numeric_limits<std::size_t>::max()){
+ error_info err(size_error);
+ throw interprocess_exception(err);
+ }
+ size = static_cast<std::size_t>(total_size - offset);
+ }
+
+ //Create file mapping
+ native_mapping_handle =
+ winapi::create_file_mapping
+ (detail::file_handle_from_mapping_handle(mapping.get_mapping_handle()), file_map_access, 0, 0, 0);
+
+ //Check if all is correct
+ if(!native_mapping_handle){
+ error_info err = winapi::get_last_error();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+ }
+
+ //We can't map any offset so we have to obtain system's
+ //memory granularity
+ unsigned long granularity = 0;
+ unsigned long foffset_low;
+ unsigned long foffset_high;
+
+ winapi::system_info info;
+ get_system_info(&info);
+ granularity = info.dwAllocationGranularity;
+
+ //Now we calculate valid offsets
+ foffset_low = (unsigned long)(offset / granularity) * granularity;
+ foffset_high = (unsigned long)(((offset / granularity) * granularity) >> 32);
+
+ //We calculate the difference between demanded and valid offset
+ m_extra_offset = (offset - (offset / granularity) * granularity);
+
+ //Store user values in memory
+ m_offset = offset;
+ m_size = size;
+
+ //Update the mapping address
+ if(address){
+ address = static_cast<const char*>(address) - m_extra_offset;
+ }
+
+ if(mhandle.is_shm){
+ //Windows shared memory needs the duplication of the handle if we want to
+ //make mapped_region independent from the mappable device
+ if(!winapi::duplicate_current_process_handle(mhandle.handle, &m_file_mapping_hnd)){
+ error_info err = winapi::get_last_error();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+ native_mapping_handle = m_file_mapping_hnd;
+ }
+
+ //Map with new offsets and size
+ m_base = winapi::map_view_of_file_ex
+ (native_mapping_handle,
+ map_access,
+ foffset_high,
+ foffset_low,
+ m_size ? static_cast<std::size_t>(m_extra_offset + m_size) : 0,
+ const_cast<void*>(address));
+
+ if(!mhandle.is_shm){
+ //For files we don't need the file mapping anymore
+ winapi::close_handle(native_mapping_handle);
+ }
+
+ //Check error
+ if(!m_base){
+ error_info err = winapi::get_last_error();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+
+ //Calculate new base for the user
+ m_base = static_cast<char*>(m_base) + m_extra_offset;
+}
+
+inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
+{
+ //Check some errors
+ if(m_base == 0)
+ return false;
+
+ if(mapping_offset >= m_size || (mapping_offset + numbytes) > m_size){
+ return false;
+ }
+
+ //Update flush size if the user does not provide it
+ if(m_size == 0){
+ numbytes = 0;
+ }
+ else if(numbytes == 0){
+ numbytes = m_size - mapping_offset;
+ }
+
+ //Flush it all
+ return 0 == winapi::flush_view_of_file
+ (static_cast<char*>(m_base)+mapping_offset,
+ static_cast<std::size_t>(numbytes));
+}
+
+inline void mapped_region::priv_close()
+{
+ if(m_base){
+ this->flush();
+ winapi::unmap_view_of_file(static_cast<char*>(m_base) - m_extra_offset);
+ m_base = 0;
+ }
+ #if (defined BOOST_INTERPROCESS_WINDOWS)
+ if(m_file_mapping_hnd != detail::invalid_file()){
+ winapi::close_handle(m_file_mapping_hnd);
+ m_file_mapping_hnd = detail::invalid_file();
+ }
+ #endif
+}
+
+inline void mapped_region::dont_close_on_destruction()
+{}
+
+#else //#if (defined BOOST_INTERPROCESS_WINDOWS)
+
+inline mapped_region::mapped_region()
+ : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only)
+{}
+
+#ifndef BOOST_HAS_RVALUE_REFS
+inline mapped_region::mapped_region(boost::rv<mapped_region> &other)
+ : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only)
+{ this->swap(other); }
+#else
+inline mapped_region::mapped_region(mapped_region &&other)
+ : m_base(MAP_FAILED), m_size(0), m_offset(0), m_mode(read_only)
+ , m_extra_offset(0)
+{ this->swap(other); }
+#endif
+
+template<int dummy>
+inline std::size_t mapped_region::page_size_holder<dummy>::get_page_size()
+{ return std::size_t(sysconf(_SC_PAGESIZE)); }
+
+template<class MemoryMappable>
+inline mapped_region::mapped_region
+ (const MemoryMappable &mapping,
+ mode_t mode,
+ offset_t offset,
+ std::size_t size,
+ const void *address)
+ : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode)
+{
+ if(size == 0){
+// offset_t filesize = lseek64
+ offset_t filesize = lseek
+ (mapping.get_mapping_handle(), offset, SEEK_END);
+
+ if(filesize == -1 ){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+ if(offset >= filesize){
+ error_info err(size_error);
+ throw interprocess_exception(err);
+ }
+ filesize -= offset;
+
+ size = (size_t)filesize;
+ if((offset_t)size != filesize){
+ error_info err(size_error);
+ throw interprocess_exception(err);
+ }
+ }
+
+ //Create new mapping
+ int prot = 0;
+ int flags = 0;
+
+ switch(mode)
+ {
+ case read_only:
+ prot |= PROT_READ;
+ flags |= MAP_SHARED;
+ break;
+
+ case read_write:
+ prot |= (PROT_WRITE | PROT_READ);
+ flags |= MAP_SHARED;
+ break;
+
+ case copy_on_write:
+ prot |= (PROT_WRITE | PROT_READ);
+ flags |= MAP_PRIVATE;
+ break;
+
+ default:
+ {
+ error_info err(mode_error);
+ throw interprocess_exception(err);
+ }
+ break;
+ }
+
+ //We calculate the difference between demanded and valid offset
+ std::size_t page_size = this->get_page_size();
+ m_extra_offset = (offset - (offset / page_size) * page_size);
+
+ //Store user values in memory
+ m_offset = offset;
+ m_size = size;
+
+ //Update the mapping address
+ if(address){
+ address = static_cast<const char*>(address) - m_extra_offset;
+ }
+
+ //Map it to the address space
+ m_base = mmap ( const_cast<void*>(address)
+ , static_cast<std::size_t>(m_extra_offset + m_size)
+ , prot
+ , flags
+ , mapping.get_mapping_handle()
+ , offset - m_extra_offset);
+
+ //Check if mapping was successful
+ if(m_base == MAP_FAILED){
+ error_info err = system_error_code();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+
+ //Calculate new base for the user
+ const void *old_base = m_base;
+ m_base = static_cast<char*>(m_base) + m_extra_offset;
+ m_offset = offset;
+ m_size = size;
+
+ //Check for fixed mapping error
+ if(address && (old_base != address)){
+ error_info err = system_error_code();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+}
+
+inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbytes)
+{
+ if(mapping_offset >= m_size || (mapping_offset+numbytes)> m_size){
+ return false;
+ }
+
+ if(numbytes == 0){
+ numbytes = m_size - mapping_offset;
+ }
+ //Flush it all
+ return msync(static_cast<char*>(m_base)+mapping_offset,
+ numbytes, MS_SYNC) == 0;
+}
+
+inline void mapped_region::priv_close()
+{
+ if(m_base != MAP_FAILED){
+ this->flush();
+ munmap(static_cast<char*>(m_base) - m_extra_offset, m_size + m_extra_offset);
+ m_base = MAP_FAILED;
+ }
+}
+
+inline void mapped_region::dont_close_on_destruction()
+{ m_base = MAP_FAILED; }
+
+#endif //##if (defined BOOST_INTERPROCESS_WINDOWS)
+
+template<int dummy>
+const std::size_t mapped_region::page_size_holder<dummy>::PageSize
+ = mapped_region::page_size_holder<dummy>::get_page_size();
+
+inline std::size_t mapped_region::get_page_size()
+{
+ if(!page_size_holder<0>::PageSize)
+ return page_size_holder<0>::get_page_size();
+ else
+ return page_size_holder<0>::PageSize;
+}
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+inline void mapped_region::swap(mapped_region &other)
+#else
+inline void mapped_region::swap(mapped_region &&other)
+#endif
+{
+ detail::do_swap(this->m_base, other.m_base);
+ detail::do_swap(this->m_size, other.m_size);
+ detail::do_swap(this->m_offset, other.m_offset);
+ detail::do_swap(this->m_extra_offset, other.m_extra_offset);
+ detail::do_swap(this->m_mode, other.m_mode);
+ #if (defined BOOST_INTERPROCESS_WINDOWS)
+ detail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd);
+ #endif
+}
+
+//!No-op functor
+struct null_mapped_region_function
+{
+ bool operator()(void *, std::size_t , bool) const
+ { return true; }
+};
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MAPPED_REGION_HPP
+
Added: sandbox/boost/interprocess/mem_algo/detail/mem_algo_common.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mem_algo/detail/mem_algo_common.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1002 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MEM_ALGO_COMMON_HPP
+#define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/iterators.hpp>
+#include <boost/interprocess/detail/math_functions.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <algorithm>
+#include <utility>
+
+//!\file
+//!Implements common operations for memory algorithms.
+
+namespace boost {
+namespace interprocess {
+namespace 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*>(detail::get_pointer(p)); }
+
+ basic_multiallocation_slist(basic_multiallocation_slist &);
+ basic_multiallocation_slist &operator=(basic_multiallocation_slist &);
+
+ public:
+ BOOST_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*>(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*>(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())
+ {}
+
+ #ifdef BOOST_HAS_RVALUE_REFS
+ basic_multiallocation_slist(basic_multiallocation_slist &&other)
+ : it_(iterator())
+ { this->swap(other); }
+
+ basic_multiallocation_slist& operator=(basic_multiallocation_slist &&other)
+ {
+ basic_multiallocation_slist tmp(boost::move(other));
+ this->swap(tmp);
+ return *this;
+ }
+ #else
+ basic_multiallocation_slist(boost::rv<basic_multiallocation_slist> &other)
+ : it_(iterator())
+ { this->swap(other.get()); }
+
+ basic_multiallocation_slist& operator=(boost::rv<basic_multiallocation_slist> &other)
+ {
+ basic_multiallocation_slist tmp(boost::move(other));
+ this->swap(tmp);
+ return *this;
+ }
+ #endif
+
+ 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 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_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())
+ {}
+
+ #ifdef BOOST_HAS_RVALUE_REFS
+ basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &&other)
+ : slist_(), last_(slist_.before_begin())
+ { this->swap(other); }
+
+ basic_multiallocation_cached_slist& operator=(basic_multiallocation_cached_slist &&other)
+ {
+ basic_multiallocation_cached_slist tmp(boost::move(other));
+ this->swap(tmp);
+ return *this;
+ }
+ #else
+ basic_multiallocation_cached_slist(boost::rv<basic_multiallocation_cached_slist> &other)
+ : slist_(), last_(slist_.before_begin())
+ { this->swap(other.get()); }
+
+ basic_multiallocation_cached_slist& operator=(boost::rv<basic_multiallocation_cached_slist> &other)
+ {
+ basic_multiallocation_cached_slist tmp(boost::move(other));
+ this->swap(tmp);
+ return *this;
+ }
+ #endif
+
+ 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_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)
+ {}
+
+ #ifdef BOOST_HAS_RVALUE_REFS
+ basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &&other)
+ : cached_slist_(), size_(0)
+ { this->swap(other); }
+
+ basic_multiallocation_cached_counted_slist& operator=(basic_multiallocation_cached_counted_slist &&other)
+ {
+ basic_multiallocation_cached_counted_slist tmp(boost::move(other));
+ this->swap(tmp);
+ return *this;
+ }
+
+ #else
+ basic_multiallocation_cached_counted_slist(boost::rv<basic_multiallocation_cached_counted_slist> &other)
+ : cached_slist_(), size_(0)
+ { this->swap(other.get()); }
+
+ basic_multiallocation_cached_counted_slist& operator=(boost::rv<basic_multiallocation_cached_counted_slist> &other)
+ {
+ basic_multiallocation_cached_counted_slist tmp(boost::move(other));
+ this->swap(tmp);
+ return *this;
+ }
+
+ #endif
+
+ basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n)
+ : cached_slist_(boost::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();
+ }
+};
+
+//!This class implements several allocation functions shared by different algorithms
+//!(aligned allocation, multiple allocation...).
+template<class MemoryAlgorithm>
+class memory_algorithm_common
+{
+ public:
+ typedef typename MemoryAlgorithm::void_pointer void_pointer;
+ typedef typename MemoryAlgorithm::block_ctrl block_ctrl;
+ typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
+ typedef memory_algorithm_common<MemoryAlgorithm> this_type;
+
+ static const std::size_t Alignment = MemoryAlgorithm::Alignment;
+ static const std::size_t MinBlockUnits = MemoryAlgorithm::MinBlockUnits;
+ static const std::size_t AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes;
+ static const std::size_t AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits;
+ static const std::size_t BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes;
+ static const std::size_t BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits;
+ static const std::size_t UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk;
+
+ static void assert_alignment(const void *ptr)
+ { assert_alignment((std::size_t)ptr); }
+
+ static void assert_alignment(std::size_t uint_ptr)
+ {
+ (void)uint_ptr;
+ BOOST_ASSERT(uint_ptr % Alignment == 0);
+ }
+
+ static bool check_alignment(const void *ptr)
+ { return (((std::size_t)ptr) % Alignment == 0); }
+
+ static std::size_t ceil_units(std::size_t size)
+ { return detail::get_rounded_size(size, Alignment)/Alignment; }
+
+ static std::size_t floor_units(std::size_t size)
+ { return size/Alignment; }
+
+ static std::size_t multiple_of_units(std::size_t size)
+ { return detail::get_rounded_size(size, Alignment); }
+
+ static multiallocation_chain allocate_many
+ (MemoryAlgorithm *memory_algo, std::size_t elem_bytes, std::size_t n_elements)
+ {
+ return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0);
+ }
+
+ static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
+ {
+ return this_type::priv_deallocate_many(memory_algo, boost::move(chain));
+ }
+
+ static bool calculate_lcm_and_needs_backwards_lcmed
+ (std::size_t backwards_multiple, std::size_t received_size, std::size_t size_to_achieve,
+ std::size_t &lcm_out, std::size_t &needs_backwards_lcmed_out)
+ {
+ // Now calculate lcm
+ std::size_t max = backwards_multiple;
+ std::size_t min = Alignment;
+ std::size_t needs_backwards;
+ std::size_t needs_backwards_lcmed;
+ std::size_t lcm;
+ std::size_t current_forward;
+ //Swap if necessary
+ if(max < min){
+ std::size_t tmp = min;
+ min = max;
+ max = tmp;
+ }
+ //Check if it's power of two
+ if((backwards_multiple & (backwards_multiple-1)) == 0){
+ if(0 != (size_to_achieve & ((backwards_multiple-1)))){
+ return false;
+ }
+
+ lcm = max;
+ //If we want to use minbytes data to get a buffer between maxbytes
+ //and minbytes if maxbytes can't be achieved, calculate the
+ //biggest of all possibilities
+ current_forward = detail::get_truncated_size_po2(received_size, backwards_multiple);
+ needs_backwards = size_to_achieve - current_forward;
+ assert((needs_backwards % backwards_multiple) == 0);
+ needs_backwards_lcmed = detail::get_rounded_size_po2(needs_backwards, lcm);
+ lcm_out = lcm;
+ needs_backwards_lcmed_out = needs_backwards_lcmed;
+ return true;
+ }
+ //Check if it's multiple of alignment
+ else if((backwards_multiple & (Alignment - 1u)) == 0){
+ lcm = backwards_multiple;
+ current_forward = detail::get_truncated_size(received_size, backwards_multiple);
+ //No need to round needs_backwards because backwards_multiple == lcm
+ needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
+ assert((needs_backwards_lcmed & (Alignment - 1u)) == 0);
+ lcm_out = lcm;
+ needs_backwards_lcmed_out = needs_backwards_lcmed;
+ return true;
+ }
+ //Check if it's multiple of the half of the alignmment
+ else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){
+ lcm = backwards_multiple*2u;
+ current_forward = detail::get_truncated_size(received_size, backwards_multiple);
+ needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
+ if(0 != (needs_backwards_lcmed & (Alignment-1)))
+ //while(0 != (needs_backwards_lcmed & (Alignment-1)))
+ needs_backwards_lcmed += backwards_multiple;
+ assert((needs_backwards_lcmed % lcm) == 0);
+ lcm_out = lcm;
+ needs_backwards_lcmed_out = needs_backwards_lcmed;
+ return true;
+ }
+ //Check if it's multiple of the half of the alignmment
+ else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){
+ std::size_t remainder;
+ lcm = backwards_multiple*4u;
+ current_forward = detail::get_truncated_size(received_size, backwards_multiple);
+ needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
+ //while(0 != (needs_backwards_lcmed & (Alignment-1)))
+ //needs_backwards_lcmed += backwards_multiple;
+ if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){
+ if(backwards_multiple & Alignment/2u){
+ needs_backwards_lcmed += (remainder)*backwards_multiple;
+ }
+ else{
+ needs_backwards_lcmed += (4-remainder)*backwards_multiple;
+ }
+ }
+ assert((needs_backwards_lcmed % lcm) == 0);
+ lcm_out = lcm;
+ needs_backwards_lcmed_out = needs_backwards_lcmed;
+ return true;
+ }
+ else{
+ lcm = detail::lcm(max, min);
+ }
+ //If we want to use minbytes data to get a buffer between maxbytes
+ //and minbytes if maxbytes can't be achieved, calculate the
+ //biggest of all possibilities
+ current_forward = detail::get_truncated_size(received_size, backwards_multiple);
+ needs_backwards = size_to_achieve - current_forward;
+ assert((needs_backwards % backwards_multiple) == 0);
+ needs_backwards_lcmed = detail::get_rounded_size(needs_backwards, lcm);
+ lcm_out = lcm;
+ needs_backwards_lcmed_out = needs_backwards_lcmed;
+ return true;
+ }
+
+ static multiallocation_chain allocate_many
+ ( MemoryAlgorithm *memory_algo
+ , const std::size_t *elem_sizes
+ , std::size_t n_elements
+ , std::size_t sizeof_element)
+ {
+ return this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element);
+ }
+
+ static void* allocate_aligned
+ (MemoryAlgorithm *memory_algo, std::size_t nbytes, std::size_t alignment)
+ {
+
+ //Ensure power of 2
+ if ((alignment & (alignment - std::size_t(1u))) != 0){
+ //Alignment is not power of two
+ BOOST_ASSERT((alignment & (alignment - std::size_t(1u))) == 0);
+ return 0;
+ }
+
+ std::size_t real_size;
+ if(alignment <= Alignment){
+ return memory_algo->priv_allocate(allocate_new, nbytes, nbytes, real_size).first;
+ }
+
+ if(nbytes > UsableByPreviousChunk)
+ nbytes -= UsableByPreviousChunk;
+
+ //We can find a aligned portion if we allocate a block that has alignment
+ //nbytes + alignment bytes or more.
+ std::size_t minimum_allocation = max_value
+ (nbytes + alignment, std::size_t(MinBlockUnits*Alignment));
+ //Since we will split that block, we must request a bit more memory
+ //if the alignment is near the beginning of the buffer, because otherwise,
+ //there is no space for a new block before the alignment.
+ //
+ // ____ Aligned here
+ // |
+ // -----------------------------------------------------
+ // | MBU |
+ // -----------------------------------------------------
+ std::size_t request =
+ minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes
+ //prevsize - UsableByPreviousChunk
+ );
+
+ //Now allocate the buffer
+ void *buffer = memory_algo->priv_allocate(allocate_new, request, request, real_size).first;
+ if(!buffer){
+ return 0;
+ }
+ else if ((((std::size_t)(buffer)) % alignment) == 0){
+ //If we are lucky and the buffer is aligned, just split it and
+ //return the high part
+ block_ctrl *first = memory_algo->priv_get_block(buffer);
+ std::size_t old_size = first->m_size;
+ const std::size_t first_min_units =
+ max_value(ceil_units(nbytes) + AllocatedCtrlUnits, std::size_t(MinBlockUnits));
+ //We can create a new block in the end of the segment
+ if(old_size >= (first_min_units + MinBlockUnits)){
+ block_ctrl *second = reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(first) + Alignment*first_min_units);
+ first->m_size = first_min_units;
+ second->m_size = old_size - first->m_size;
+ BOOST_ASSERT(second->m_size >= MinBlockUnits);
+ memory_algo->priv_mark_new_allocated_block(first);
+ //memory_algo->priv_tail_size(first, first->m_size);
+ memory_algo->priv_mark_new_allocated_block(second);
+ memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second));
+ }
+ return buffer;
+ }
+
+ //Buffer not aligned, find the aligned part.
+ //
+ // ____ Aligned here
+ // |
+ // -----------------------------------------------------
+ // | MBU +more | ACB |
+ // -----------------------------------------------------
+ char *pos = reinterpret_cast<char*>
+ (reinterpret_cast<std::size_t>(static_cast<char*>(buffer) +
+ //This is the minimum size of (2)
+ (MinBlockUnits*Alignment - AllocatedCtrlBytes) +
+ //This is the next MBU for the aligned memory
+ AllocatedCtrlBytes +
+ //This is the alignment trick
+ alignment - 1) & -alignment);
+
+ //Now obtain the address of the blocks
+ block_ctrl *first = memory_algo->priv_get_block(buffer);
+ block_ctrl *second = memory_algo->priv_get_block(pos);
+ assert(pos <= (reinterpret_cast<char*>(first) + first->m_size*Alignment));
+ assert(first->m_size >= 2*MinBlockUnits);
+ assert((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <=
+ (reinterpret_cast<char*>(first) + first->m_size*Alignment));
+ //Set the new size of the first block
+ std::size_t old_size = first->m_size;
+ first->m_size = (reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment;
+ memory_algo->priv_mark_new_allocated_block(first);
+
+ //Now check if we can create a new buffer in the end
+ //
+ // __"second" block
+ // | __Aligned here
+ // | | __"third" block
+ // -----------|-----|-----|------------------------------
+ // | MBU +more | ACB | (3) | BCU |
+ // -----------------------------------------------------
+ //This size will be the minimum size to be able to create a
+ //new block in the end.
+ const std::size_t second_min_units = max_value(std::size_t(MinBlockUnits),
+ ceil_units(nbytes) + AllocatedCtrlUnits );
+
+ //Check if we can create a new block (of size MinBlockUnits) in the end of the segment
+ if((old_size - first->m_size) >= (second_min_units + MinBlockUnits)){
+ //Now obtain the address of the end block
+ block_ctrl *third = new (reinterpret_cast<char*>(second) + Alignment*second_min_units)block_ctrl;
+ second->m_size = second_min_units;
+ third->m_size = old_size - first->m_size - second->m_size;
+ BOOST_ASSERT(third->m_size >= MinBlockUnits);
+ memory_algo->priv_mark_new_allocated_block(second);
+ memory_algo->priv_mark_new_allocated_block(third);
+ memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(third));
+ }
+ else{
+ second->m_size = old_size - first->m_size;
+ assert(second->m_size >= MinBlockUnits);
+ memory_algo->priv_mark_new_allocated_block(second);
+ }
+
+ memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(first));
+ return memory_algo->priv_get_user_buffer(second);
+ }
+
+ static bool try_shrink
+ (MemoryAlgorithm *memory_algo, void *ptr
+ ,const std::size_t max_size, const std::size_t preferred_size
+ ,std::size_t &received_size)
+ {
+ (void)memory_algo;
+ //Obtain the real block
+ block_ctrl *block = memory_algo->priv_get_block(ptr);
+ std::size_t old_block_units = block->m_size;
+
+ //The block must be marked as allocated
+ BOOST_ASSERT(memory_algo->priv_is_allocated_block(block));
+
+ //Check if alignment and block size are right
+ assert_alignment(ptr);
+
+ //Put this to a safe value
+ received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
+
+ //Now translate it to Alignment units
+ const std::size_t max_user_units = floor_units(max_size - UsableByPreviousChunk);
+ const std::size_t preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk);
+
+ //Check if rounded max and preferred are possible correct
+ if(max_user_units < preferred_user_units)
+ return false;
+
+ //Check if the block is smaller than the requested minimum
+ std::size_t old_user_units = old_block_units - AllocatedCtrlUnits;
+
+ if(old_user_units < preferred_user_units)
+ return false;
+
+ //If the block is smaller than the requested minimum
+ if(old_user_units == preferred_user_units)
+ return true;
+
+ std::size_t shrunk_user_units =
+ ((BlockCtrlUnits - AllocatedCtrlUnits) > preferred_user_units)
+ ? (BlockCtrlUnits - AllocatedCtrlUnits)
+ : preferred_user_units;
+
+ //Some parameter checks
+ if(max_user_units < shrunk_user_units)
+ return false;
+
+ //We must be able to create at least a new empty block
+ if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){
+ return false;
+ }
+
+ //Update new size
+ received_size = shrunk_user_units*Alignment + UsableByPreviousChunk;
+ return true;
+ }
+
+ static bool shrink
+ (MemoryAlgorithm *memory_algo, void *ptr
+ ,const std::size_t max_size, const std::size_t preferred_size
+ ,std::size_t &received_size)
+ {
+ //Obtain the real block
+ block_ctrl *block = memory_algo->priv_get_block(ptr);
+ std::size_t old_block_units = block->m_size;
+
+ if(!try_shrink
+ (memory_algo, ptr, max_size, preferred_size, received_size)){
+ return false;
+ }
+
+ //Check if the old size was just the shrunk size (no splitting)
+ if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk))
+ return true;
+
+ //Now we can just rewrite the size of the old buffer
+ block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits;
+ BOOST_ASSERT(block->m_size >= BlockCtrlUnits);
+
+ //We create the new block
+ block_ctrl *new_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(block) + block->m_size*Alignment);
+ //Write control data to simulate this new block was previously allocated
+ //and deallocate it
+ new_block->m_size = old_block_units - block->m_size;
+ BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
+ memory_algo->priv_mark_new_allocated_block(block);
+ memory_algo->priv_mark_new_allocated_block(new_block);
+ memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block));
+ return true;
+ }
+
+ private:
+ static multiallocation_chain priv_allocate_many
+ ( MemoryAlgorithm *memory_algo
+ , const std::size_t *elem_sizes
+ , std::size_t n_elements
+ , std::size_t sizeof_element)
+ {
+ //Note: sizeof_element == 0 indicates that we want to
+ //allocate n_elements of the same size "*elem_sizes"
+
+ //Calculate the total size of all requests
+ std::size_t total_request_units = 0;
+ std::size_t elem_units = 0;
+ const std::size_t ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer));
+ if(!sizeof_element){
+ elem_units = memory_algo->priv_get_total_units(*elem_sizes);
+ elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
+ total_request_units = n_elements*elem_units;
+ }
+ else{
+ for(std::size_t i = 0; i < n_elements; ++i){
+ elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element);
+ elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
+ total_request_units += elem_units;
+ }
+ }
+
+ multiallocation_chain chain;
+
+ std::size_t low_idx = 0;
+ while(low_idx < n_elements){
+ std::size_t total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
+ std::size_t min_allocation = (!sizeof_element)
+ ? elem_units
+ : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
+ min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
+
+ std::size_t received_size;
+ std::pair<void *, bool> ret = memory_algo->priv_allocate
+ (allocate_new, min_allocation, total_bytes, received_size, 0);
+ if(!ret.first){
+ break;
+ }
+
+ block_ctrl *block = memory_algo->priv_get_block(ret.first);
+ std::size_t received_units = block->m_size;
+ char *block_address = reinterpret_cast<char*>(block);
+
+ std::size_t total_used_units = 0;
+// block_ctrl *prev_block = 0;
+ while(total_used_units < received_units){
+ if(sizeof_element){
+ elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
+ elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
+ }
+ if(total_used_units + elem_units > received_units)
+ break;
+ total_request_units -= elem_units;
+ //This is the position where the new block must be created
+ block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address);
+ assert_alignment(new_block);
+
+ //The last block should take all the remaining space
+ if((low_idx + 1) == n_elements ||
+ (total_used_units + elem_units +
+ ((!sizeof_element)
+ ? elem_units
+ : memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element))
+ ) > received_units){
+ //By default, the new block will use the rest of the buffer
+ new_block->m_size = received_units - total_used_units;
+ memory_algo->priv_mark_new_allocated_block(new_block);
+
+ //If the remaining units are bigger than needed and we can
+ //split it obtaining a new free memory block do it.
+ if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
+ std::size_t shrunk_received;
+ std::size_t shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
+ bool shrink_ok = shrink
+ (memory_algo
+ ,memory_algo->priv_get_user_buffer(new_block)
+ ,shrunk_request
+ ,shrunk_request
+ ,shrunk_received);
+ (void)shrink_ok;
+ //Shrink must always succeed with passed parameters
+ BOOST_ASSERT(shrink_ok);
+ //Some sanity checks
+ BOOST_ASSERT(shrunk_request == shrunk_received);
+ BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
+ //"new_block->m_size" must have been reduced to elem_units by "shrink"
+ BOOST_ASSERT(new_block->m_size == elem_units);
+ //Now update the total received units with the reduction
+ received_units = elem_units + total_used_units;
+ }
+ }
+ else{
+ new_block->m_size = elem_units;
+ memory_algo->priv_mark_new_allocated_block(new_block);
+ }
+
+ block_address += new_block->m_size*Alignment;
+ total_used_units += new_block->m_size;
+ //Check we have enough room to overwrite the intrusive pointer
+ assert((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
+ void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0);
+ chain.push_back(p);
+ ++low_idx;
+ //prev_block = new_block;
+ }
+ //Sanity check
+ BOOST_ASSERT(total_used_units == received_units);
+ }
+
+ if(low_idx != n_elements){
+ priv_deallocate_many(memory_algo, boost::move(chain));
+ }
+ return boost::move(chain);
+ }
+
+ static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
+ {
+ while(!chain.empty()){
+ void *addr = detail::get_pointer(chain.front());
+ chain.pop_front();
+ memory_algo->priv_deallocate(addr);
+ }
+ }
+};
+
+} //namespace detail {
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
Added: sandbox/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,61 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MULTI_SIMPLE_SEQ_FIT_HPP
+#define BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp>
+#include <boost/interprocess/intersegment_ptr.hpp>
+
+/*!\file
+ Describes sequential fit algorithm used to allocate objects in shared memory.
+*/
+
+namespace boost {
+
+namespace interprocess {
+
+/*!This class implements the simple sequential fit algorithm with a simply
+ linked list of free buffers.*/
+template<class MutexFamily, class VoidPtr>
+class multi_simple_seq_fit
+ : public detail::simple_seq_fit_impl<MutexFamily, VoidPtr>
+{
+ typedef detail::simple_seq_fit_impl<MutexFamily, VoidPtr> base_t;
+ public:
+ /*!Constructor. "size" is the total size of the managed memory segment,
+ "extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(multi_simple_seq_fit)
+ offset that the allocator should not use at all.*/
+ multi_simple_seq_fit (std::size_t size, std::size_t extra_hdr_bytes)
+ : base_t(size, extra_hdr_bytes){}
+
+ /*!Allocates bytes from existing segments. If there is no memory, it uses
+ the growing functor associated with the group to allocate a new segment.
+ If this fails, returns 0.*/
+ void* allocate (std::size_t nbytes)
+ { return base_t::multi_allocate(nbytes); }
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP
+
Added: sandbox/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,971 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
+#define BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/multi_segment_services.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#include <boost/type_traits/type_with_alignment.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <algorithm>
+#include <utility>
+#include <cstring>
+
+#include <assert.h>
+#include <new>
+
+/*!\file
+ Describes sequential fit algorithm used to allocate objects in shared memory.
+ This class is intended as a base class for single segment and multi-segment
+ implementations.
+*/
+
+namespace boost {
+
+namespace interprocess {
+
+namespace detail {
+
+/*!This class implements the simple sequential fit algorithm with a simply
+ linked list of free buffers.
+ This class is intended as a base class for single segment and multi-segment
+ implementations.*/
+template<class MutexFamily, class VoidPointer>
+class simple_seq_fit_impl
+{
+ //Non-copyable
+ simple_seq_fit_impl();
+ simple_seq_fit_impl(const simple_seq_fit_impl &);
+ simple_seq_fit_impl &operator=(const simple_seq_fit_impl &);
+
+ public:
+ /*!Shared interprocess_mutex family used for the rest of the Interprocess framework*/
+ typedef MutexFamily mutex_family;
+ /*!Pointer type to be used with the rest of the Interprocess framework*/
+ typedef VoidPointer void_pointer;
+
+ private:
+ struct block_ctrl;
+ typedef typename detail::
+ pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr;
+
+ /*!Block control structure*/
+ struct block_ctrl
+ {
+ /*!Offset pointer to the next block.*/
+ block_ctrl_ptr m_next;
+ /*!This block's memory size (including block_ctrl
+ header) in BasicSize units*/
+ std::size_t m_size;
+
+ std::size_t get_user_bytes() const
+ { return this->m_size*Alignment - BlockCtrlBytes; }
+
+ std::size_t get_total_bytes() const
+ { return this->m_size*Alignment; }
+
+ static block_ctrl *get_block_from_addr(void *addr)
+ {
+ return reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(addr) - BlockCtrlBytes);
+ }
+
+ void *get_addr() const
+ {
+ return reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<const char*>(this) + BlockCtrlBytes);
+ }
+
+ };
+
+ /*!Shared interprocess_mutex to protect memory allocate/deallocate*/
+ typedef typename MutexFamily::mutex_type interprocess_mutex;
+
+ /*!This struct includes needed data and derives from
+ interprocess_mutex to allow EBO when using null interprocess_mutex*/
+ struct header_t : public interprocess_mutex
+ {
+ /*!Pointer to the first free block*/
+ block_ctrl m_root;
+ /*!Allocated bytes for internal checking*/
+ std::size_t m_allocated;
+ /*!The size of the memory segment*/
+ std::size_t m_size;
+ } m_header;
+
+ public:
+ /*!Constructor. "size" is the total size of the managed memory segment,
+ "extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit_impl)
+ offset that the allocator should not use at all.*/
+ simple_seq_fit_impl (std::size_t size, std::size_t extra_hdr_bytes);
+ /*!Destructor.*/
+ ~simple_seq_fit_impl();
+ /*!Obtains the minimum size needed by the algorithm*/
+ static std::size_t get_min_size (std::size_t extra_hdr_bytes);
+
+ //Functions for single segment management
+
+ /*!Allocates bytes, returns 0 if there is not more memory*/
+ void* allocate (std::size_t nbytes);
+
+ /*!Deallocates previously allocated bytes*/
+ void deallocate (void *addr);
+
+ /*!Returns the size of the memory segment*/
+ std::size_t get_size() const;
+
+ /*!Increases managed memory in extra_size bytes more*/
+ void grow(std::size_t extra_size);
+
+ /*!Returns true if all allocated memory has been deallocated*/
+ bool all_memory_deallocated();
+
+ /*!Makes an internal sanity check and returns true if success*/
+ bool check_sanity();
+
+ //!Initializes to zero all the memory that's not in use.
+ //!This function is normally used for security reasons.
+ void clear_free_memory();
+
+ std::pair<void *, bool>
+ allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ void *reuse_ptr = 0, std::size_t backwards_multiple = 1);
+
+ /*!Returns the size of the buffer previously allocated pointed by ptr*/
+ std::size_t size(void *ptr) const;
+
+ /*!Allocates aligned bytes, returns 0 if there is not more memory.
+ Alignment must be power of 2*/
+ void* allocate_aligned (std::size_t nbytes, std::size_t alignment);
+
+ /*!Allocates bytes, if there is no more memory, it executes functor
+ f(std::size_t) to allocate a new segment to manage. The functor returns
+ std::pair<void*, std::size_t> indicating the base address and size of
+ the new segment. If the new segment can't be allocated, allocate
+ it will return 0.*/
+ void* multi_allocate(std::size_t nbytes);
+
+ private:
+ /*!Real allocation algorithm with min allocation option*/
+ std::pair<void *, bool> priv_allocate(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr = 0);
+ /*!Returns next block if it's free.
+ Returns 0 if next block is not free.*/
+ block_ctrl *priv_next_block_if_free(block_ctrl *ptr);
+
+ /*!Returns previous block's if it's free.
+ Returns 0 if previous block is not free.*/
+ std::pair<block_ctrl*, block_ctrl*>priv_prev_block_if_free(block_ctrl *ptr);
+
+ /*!Real expand function implementation*/
+ bool priv_expand(void *ptr
+ ,std::size_t min_size, std::size_t preferred_size
+ ,std::size_t &received_size);
+
+ /*!Real expand to both sides implementation*/
+ void* priv_expand_both_sides(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,bool only_preferred_backwards);
+
+ /*!Real shrink function implementation*/
+ bool priv_shrink(void *ptr
+ ,std::size_t max_size, std::size_t preferred_size
+ ,std::size_t &received_size);
+
+ //!Real private aligned allocation function
+ void* priv_allocate_aligned (std::size_t nbytes, std::size_t alignment);
+
+ /*!Checks if block has enough memory and splits/unlinks the block
+ returning the address to the users*/
+ void* priv_check_and_allocate(std::size_t units
+ ,block_ctrl* prev
+ ,block_ctrl* block
+ ,std::size_t &received_size);
+ /*!Real deallocation algorithm*/
+ void priv_deallocate(void *addr);
+
+ /*!Makes a new memory portion available for allocation*/
+ void priv_add_segment(void *addr, std::size_t size);
+
+ enum { Alignment = boost::alignment_of<boost::detail::max_align>::value };
+ enum { BlockCtrlBytes = detail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value };
+ enum { BlockCtrlSize = BlockCtrlBytes/Alignment };
+ enum { MinBlockSize = BlockCtrlSize + Alignment };
+
+ public:
+ enum { PayloadPerAllocation = BlockCtrlBytes };
+};
+
+template<class MutexFamily, class VoidPointer>
+inline simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ simple_seq_fit_impl(std::size_t size, std::size_t extra_hdr_bytes)
+{
+ //Initialize sizes and counters
+ m_header.m_allocated = 0;
+ m_header.m_size = size;
+
+ //Initialize pointers
+ std::size_t block1_off = detail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment);
+ m_header.m_root.m_next = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(this) + block1_off);
+ m_header.m_root.m_next->m_size = (size - block1_off)/Alignment;
+ m_header.m_root.m_next->m_next = &m_header.m_root;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline simple_seq_fit_impl<MutexFamily, VoidPointer>::~simple_seq_fit_impl()
+{
+ //There is a memory leak!
+// assert(m_header.m_allocated == 0);
+// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root));
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::grow(std::size_t extra_size)
+{
+ //Old highest address block's end offset
+ std::size_t old_end = m_header.m_size/Alignment*Alignment;
+
+ //Update managed buffer's size
+ m_header.m_size += extra_size;
+
+ //We need at least MinBlockSize blocks to create a new block
+ if((m_header.m_size - old_end) < MinBlockSize){
+ return;
+ }
+
+ //We'll create a new free block with extra_size bytes
+ block_ctrl *new_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(this) + old_end);
+
+ new_block->m_next = 0;
+ new_block->m_size = (m_header.m_size - old_end)/Alignment;
+ m_header.m_allocated += new_block->m_size*Alignment;
+ this->priv_deallocate(reinterpret_cast<char*>(new_block) + BlockCtrlBytes);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, std::size_t size)
+{
+ //Check size
+ assert(!(size < MinBlockSize));
+ if(size < MinBlockSize)
+ return;
+ //Construct big block using the new segment
+ block_ctrl *new_block = static_cast<block_ctrl *>(addr);
+ new_block->m_size = size/Alignment;
+ new_block->m_next = 0;
+ //Simulate this block was previously allocated
+ m_header.m_allocated += new_block->m_size*Alignment;
+ //Return block and insert it in the free block list
+ this->priv_deallocate(reinterpret_cast<char*>(new_block) + BlockCtrlBytes);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::get_size() const
+ { return m_header.m_size; }
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ get_min_size (std::size_t extra_hdr_bytes)
+{
+ return detail::get_rounded_size(sizeof(simple_seq_fit_impl)+extra_hdr_bytes
+ ,Alignment)
+ + MinBlockSize;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ all_memory_deallocated()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return m_header.m_allocated == 0 &&
+ detail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::clear_free_memory()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ block_ctrl *block = detail::get_pointer(m_header.m_root.m_next);
+
+ //Iterate through all free portions
+ do{
+ //Just clear user the memory part reserved for the user
+ std::memset( reinterpret_cast<char*>(block) + BlockCtrlBytes
+ , 0
+ , block->m_size*Alignment - BlockCtrlBytes);
+ block = detail::get_pointer(block->m_next);
+ }
+ while(block != &m_header.m_root);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ check_sanity()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ block_ctrl *block = detail::get_pointer(m_header.m_root.m_next);
+
+ std::size_t free_memory = 0;
+
+ //Iterate through all blocks obtaining their size
+ do{
+ //Free blocks's next must be always valid
+ block_ctrl *next = detail::get_pointer(block->m_next);
+ if(!next){
+ return false;
+ }
+ free_memory += block->m_size*Alignment;
+ block = next;
+ }
+ while(block != &m_header.m_root);
+
+ //Check allocated bytes are less than size
+ if(m_header.m_allocated > m_header.m_size){
+ return false;
+ }
+
+ //Check free bytes are less than size
+ if(free_memory > m_header.m_size){
+ return false;
+ }
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ allocate(std::size_t nbytes)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ std::size_t ignore;
+ return priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ allocate_aligned(std::size_t nbytes, std::size_t alignment)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return priv_allocate_aligned(nbytes, alignment);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ allocation_command (allocation_type command, std::size_t min_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ void *reuse_ptr, std::size_t backwards_multiple)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ (void)backwards_multiple;
+ command &= ~expand_bwd;
+ if(!command)
+ return std::pair<void *, bool>(0, false);
+ return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ size(void *ptr) const
+{
+ //We need no synchronization since this block is not going
+ //to be modified
+ //Obtain the real size of the block
+ block_ctrl *block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(ptr) - BlockCtrlBytes);
+ return block->m_size*Alignment - BlockCtrlBytes;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ multi_allocate(std::size_t nbytes)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ //Multisegment pointer. Let's try first the normal allocation
+ //since it's faster.
+ std::size_t ignore;
+ void *addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
+ if(!addr){
+ //If this fails we will try the allocation through the segment
+ //creator.
+ std::size_t group, id;
+ //Obtain the segment group of this segment
+ void_pointer::get_group_and_id(this, group, id);
+ if(group == 0){
+ //Ooops, group 0 is not valid.
+ return 0;
+ }
+ //Now obtain the polymorphic functor that creates
+ //new segments and try to allocate again.
+ boost::interprocess::multi_segment_services *p_services =
+ static_cast<boost::interprocess::multi_segment_services*>
+ (void_pointer::find_group_data(group));
+ assert(p_services);
+ std::pair<void *, std::size_t> ret =
+ p_services->create_new_segment(MinBlockSize > nbytes ? MinBlockSize : nbytes);
+ if(ret.first){
+ priv_add_segment(ret.first, ret.second);
+ addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
+ }
+ }
+ return addr;
+}
+
+template<class MutexFamily, class VoidPointer>
+void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_expand_both_sides(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,bool only_preferred_backwards)
+{
+ typedef std::pair<block_ctrl *, block_ctrl *> prev_block_t;
+ block_ctrl *reuse = block_ctrl::get_block_from_addr(reuse_ptr);
+ received_size = 0;
+
+ if(this->size(reuse_ptr) > min_size){
+ received_size = this->size(reuse_ptr);
+ return reuse_ptr;
+ }
+
+ if(command & expand_fwd){
+ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size))
+ return reuse_ptr;
+ }
+ else{
+ received_size = this->size(reuse_ptr);
+ }
+ if(command & expand_bwd){
+ std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes;
+ prev_block_t prev_pair = priv_prev_block_if_free(reuse);
+ block_ctrl *prev = prev_pair.second;
+ if(!prev){
+ return 0;
+ }
+
+ std::size_t needs_backwards =
+ detail::get_rounded_size(preferred_size - extra_forward, Alignment);
+
+ if(!only_preferred_backwards){
+ needs_backwards =
+ max_value(detail::get_rounded_size(min_size - extra_forward, Alignment)
+ ,min_value(prev->get_user_bytes(), needs_backwards));
+ }
+
+ //Check if previous block has enough size
+ if((prev->get_user_bytes()) >= needs_backwards){
+ //Now take all next space. This will succeed
+ if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){
+ assert(0);
+ }
+
+ //We need a minimum size to split the previous one
+ if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){
+ block_ctrl *new_block = reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(reuse) - needs_backwards - BlockCtrlBytes);
+ new_block->m_next = 0;
+ new_block->m_size =
+ BlockCtrlSize + (needs_backwards + extra_forward)/Alignment;
+ prev->m_size =
+ (prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlSize;
+ received_size = needs_backwards + extra_forward;
+ m_header.m_allocated += needs_backwards + BlockCtrlBytes;
+ return new_block->get_addr();
+ }
+ else{
+ //Just merge the whole previous block
+ block_ctrl *prev_2_block = prev_pair.first;
+ //Update received size and allocation
+ received_size = extra_forward + prev->get_user_bytes();
+ m_header.m_allocated += prev->get_total_bytes();
+ //Now unlink it from previous block
+ prev_2_block->m_next = prev->m_next;
+ prev->m_size = reuse->m_size + prev->m_size;
+ prev->m_next = 0;
+ return prev->get_addr();
+ }
+ }
+ }
+ return 0;
+}
+
+template<class MutexFamily, class VoidPointer>
+std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_allocate(allocation_type command
+ ,std::size_t limit_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr)
+{
+ if(command & shrink_in_place){
+ bool success =
+ this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size);
+ return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
+ }
+ typedef std::pair<void *, bool> return_type;
+ received_size = 0;
+
+ if(limit_size > preferred_size)
+ return return_type(0, false);
+
+ //Number of units to request (including block_ctrl header)
+ std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlSize;
+
+ //Get the root and the first memory block
+ block_ctrl *prev = &m_header.m_root;
+ block_ctrl *block = detail::get_pointer(prev->m_next);
+ block_ctrl *root = &m_header.m_root;
+ block_ctrl *biggest_block = 0;
+ block_ctrl *prev_biggest_block = 0;
+ std::size_t biggest_size = limit_size;
+
+ //Expand in place
+ //reuse_ptr, limit_size, preferred_size, received_size
+ //
+ if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
+ void *ret = priv_expand_both_sides
+ (command, limit_size, preferred_size, received_size, reuse_ptr, true);
+ if(ret)
+ return return_type(ret, true);
+ }
+
+ if(command & allocate_new){
+ received_size = 0;
+ while(block != root){
+ //Update biggest block pointers
+ if(block->m_size > biggest_size){
+ prev_biggest_block = prev;
+ biggest_size = block->m_size;
+ biggest_block = block;
+ }
+ void *addr = this->priv_check_and_allocate(nunits, prev, block, received_size);
+ if(addr) return return_type(addr, false);
+ //Bad luck, let's check next block
+ prev = block;
+ block = detail::get_pointer(block->m_next);
+ }
+
+ //Bad luck finding preferred_size, now if we have any biggest_block
+ //try with this block
+ if(biggest_block){
+ received_size = biggest_block->m_size*Alignment - BlockCtrlSize;
+ nunits = detail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlSize;
+ void *ret = this->priv_check_and_allocate
+ (nunits, prev_biggest_block, biggest_block, received_size);
+ if(ret)
+ return return_type(ret, false);
+ }
+ }
+ //Now try to expand both sides with min size
+ if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
+ return return_type(priv_expand_both_sides
+ (command, limit_size, preferred_size, received_size, reuse_ptr, false), true);
+ }
+ return return_type(0, false);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
+ simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_next_block_if_free
+ (typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
+{
+ //Take the address where the next block should go
+ block_ctrl *next_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(ptr) + ptr->m_size*Alignment);
+
+ //Check if the adjacent block is in the managed segment
+ std::size_t distance = (reinterpret_cast<char*>(next_block) - reinterpret_cast<char*>(this))/Alignment;
+ if(distance >= (m_header.m_size/Alignment)){
+ //"next_block" does not exist so we can't expand "block"
+ return 0;
+ }
+
+ if(!next_block->m_next)
+ return 0;
+
+ return next_block;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline
+ std::pair<typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
+ ,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *>
+ simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_prev_block_if_free
+ (typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
+{
+ typedef std::pair<block_ctrl *, block_ctrl *> prev_pair_t;
+ //Take the address where the previous block should go
+ block_ctrl *root = &m_header.m_root;
+ block_ctrl *prev_2_block = root;
+ block_ctrl *prev_block = detail::get_pointer(root->m_next);
+ while((reinterpret_cast<char*>(prev_block) + prev_block->m_size*Alignment)
+ != (reinterpret_cast<char*>(ptr))
+ && prev_block != root){
+ prev_2_block = prev_block;
+ prev_block = detail::get_pointer(prev_block->m_next);
+ }
+
+ if(prev_block == root || !prev_block->m_next)
+ return prev_pair_t(0, 0);
+
+ //Check if the previous block is in the managed segment
+ std::size_t distance = (reinterpret_cast<char*>(prev_block) - reinterpret_cast<char*>(this))/Alignment;
+ if(distance >= (m_header.m_size/Alignment)){
+ //"previous_block" does not exist so we can't expand "block"
+ return prev_pair_t(0, 0);
+ }
+ return prev_pair_t(prev_2_block, prev_block);
+}
+
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_expand (void *ptr
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size)
+{
+ //Obtain the real size of the block
+ block_ctrl *block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(ptr) - BlockCtrlBytes);
+ std::size_t old_block_size = block->m_size;
+
+ //All used blocks' next is marked with 0 so check it
+ assert(block->m_next == 0);
+
+ //Put this to a safe value
+ received_size = old_block_size*Alignment - BlockCtrlBytes;
+
+ //Now translate it to Alignment units
+ min_size = detail::get_rounded_size(min_size, Alignment)/Alignment;
+ preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment;
+
+ //Some parameter checks
+ if(min_size > preferred_size)
+ return false;
+
+ std::size_t data_size = old_block_size - BlockCtrlSize;
+
+ if(data_size >= min_size)
+ return true;
+
+ block_ctrl *next_block = priv_next_block_if_free(block);
+ if(!next_block){
+ return false;
+ }
+
+ //Is "block" + "next_block" big enough?
+ std::size_t merged_size = old_block_size + next_block->m_size;
+
+ //Now we can expand this block further than before
+ received_size = merged_size*Alignment - BlockCtrlBytes;
+
+ if(merged_size < (min_size + BlockCtrlSize)){
+ return false;
+ }
+
+ //We can fill expand. Merge both blocks,
+ block->m_next = next_block->m_next;
+ block->m_size = merged_size;
+
+ //Find the previous free block of next_block
+ block_ctrl *prev = &m_header.m_root;
+ while(detail::get_pointer(prev->m_next) != next_block){
+ prev = detail::get_pointer(prev->m_next);
+ }
+
+ //Now insert merged block in the free list
+ //This allows reusing allocation logic in this function
+ m_header.m_allocated -= old_block_size*Alignment;
+ prev->m_next = block;
+
+ //Now use check and allocate to do the allocation logic
+ preferred_size += BlockCtrlSize;
+ std::size_t nunits = preferred_size < merged_size ? preferred_size : merged_size;
+
+ //This must success since nunits is less than merged_size!
+ if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){
+ //Something very ugly is happening here. This is a bug
+ //or there is memory corruption
+ assert(0);
+ return false;
+ }
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_shrink (void *ptr
+ ,std::size_t max_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size)
+{
+ //Obtain the real size of the block
+ block_ctrl *block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(ptr) - BlockCtrlBytes);
+ std::size_t block_size = block->m_size;
+
+ //All used blocks' next is marked with 0 so check it
+ assert(block->m_next == 0);
+
+ //Put this to a safe value
+ received_size = block_size*Alignment - BlockCtrlBytes;
+
+ //Now translate it to Alignment units
+ max_size = max_size/Alignment;
+ preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment;
+
+ //Some parameter checks
+ if(max_size < preferred_size)
+ return false;
+
+ std::size_t data_size = block_size - BlockCtrlSize;
+
+ if(data_size < preferred_size)
+ return false;
+
+ if(data_size == preferred_size)
+ return true;
+
+ //We must be able to create at least a new empty block
+ if((data_size - preferred_size) < BlockCtrlSize){
+ return false;
+ }
+
+ //Now we can just rewrite the size of the old buffer
+ block->m_size = preferred_size + BlockCtrlSize;
+
+ //Update new size
+ received_size = preferred_size*Alignment;
+
+ //We create the new block
+ block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(block) + block->m_size*Alignment);
+
+ //Write control data to simulate this new block was previously allocated
+ block->m_next = 0;
+ block->m_size = data_size - preferred_size;
+
+ //Now deallocate the new block to insert it in the free list
+ this->priv_deallocate(reinterpret_cast<char*>(block)+BlockCtrlBytes);
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_allocate_aligned(std::size_t nbytes, std::size_t alignment)
+{
+ //Ensure power of 2
+ if ((alignment & (alignment - std::size_t(1u))) != 0){
+ //Alignment is not power of two
+ assert((alignment & (alignment - std::size_t(1u))) != 0);
+ return 0;
+ }
+
+ std::size_t ignore;
+ if(alignment <= Alignment){
+ return priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
+ }
+
+ std::size_t request =
+ nbytes + alignment + MinBlockSize*Alignment - BlockCtrlBytes;
+ void *buffer = priv_allocate(allocate_new, request, request, ignore).first;
+ if(!buffer)
+ return 0;
+ else if ((((std::size_t)(buffer)) % alignment) == 0)
+ return buffer;
+
+ char *aligned_portion = reinterpret_cast<char*>
+ (reinterpret_cast<std::size_t>(static_cast<char*>(buffer) + alignment - 1) & -alignment);
+
+ char *pos = ((aligned_portion - reinterpret_cast<char*>(buffer)) >= (MinBlockSize*Alignment)) ?
+ aligned_portion : (aligned_portion + alignment);
+
+ block_ctrl *first = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(buffer) - BlockCtrlBytes);
+
+ block_ctrl *second = reinterpret_cast<block_ctrl*>(pos - BlockCtrlBytes);
+
+ std::size_t old_size = first->m_size;
+
+ first->m_size = (reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment;
+ second->m_size = old_size - first->m_size;
+
+ //Write control data to simulate this new block was previously allocated
+ second->m_next = 0;
+
+ //Now deallocate the new block to insert it in the free list
+ this->priv_deallocate(reinterpret_cast<char*>(first) + BlockCtrlBytes);
+ return reinterpret_cast<char*>(second) + BlockCtrlBytes;
+}
+
+template<class MutexFamily, class VoidPointer> inline
+void* simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_check_and_allocate
+ (std::size_t nunits
+ ,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* prev
+ ,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* block
+ ,std::size_t &received_size)
+{
+ std::size_t upper_nunits = nunits + BlockCtrlSize;
+ bool found = false;
+
+ if (block->m_size > upper_nunits){
+ //This block is bigger than needed, split it in
+ //two blocks, the first's size will be (block->m_size-units)
+ //the second's size (units)
+ std::size_t total_size = block->m_size;
+ block->m_size = nunits;
+ block_ctrl *new_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(block) + Alignment*nunits);
+ new_block->m_size = total_size - nunits;
+ new_block->m_next = block->m_next;
+ prev->m_next = new_block;
+ found = true;
+ }
+ else if (block->m_size >= nunits){
+ //This block has exactly the right size with an extra
+ //unusable extra bytes.
+ prev->m_next = block->m_next;
+ found = true;
+ }
+
+ if(found){
+ //We need block_ctrl for deallocation stuff, so
+ //return memory user can overwrite
+ m_header.m_allocated += block->m_size*Alignment;
+ received_size = block->m_size*Alignment - BlockCtrlBytes;
+ //Mark the block as allocated
+ block->m_next = 0;
+ //Check alignment
+ assert(((reinterpret_cast<char*>(block) - reinterpret_cast<char*>(this))
+ % Alignment) == 0 );
+ return reinterpret_cast<char*>(block) + BlockCtrlBytes;
+ }
+ return 0;
+}
+
+template<class MutexFamily, class VoidPointer>
+void simple_seq_fit_impl<MutexFamily, VoidPointer>::deallocate(void* addr)
+{
+ if(!addr) return;
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return this->priv_deallocate(addr);
+}
+
+template<class MutexFamily, class VoidPointer>
+void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
+{
+ if(!addr) return;
+
+ //Let's get free block list. List is always sorted
+ //by memory address to allow block merging.
+ //Pointer next always points to the first
+ //(lower address) block
+ block_ctrl_ptr prev = &m_header.m_root;
+ block_ctrl_ptr pos = m_header.m_root.m_next;
+ block_ctrl_ptr block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(addr) - BlockCtrlBytes);
+
+ //All used blocks' next is marked with 0 so check it
+ assert(block->m_next == 0);
+
+ //Check if alignment and block size are right
+ assert((reinterpret_cast<char*>(addr) - reinterpret_cast<char*>(this))
+ % Alignment == 0 );
+
+ std::size_t total_size = Alignment*block->m_size;
+ assert(m_header.m_allocated >= total_size);
+
+ //Update used memory count
+ m_header.m_allocated -= total_size;
+
+ //Let's find the previous and the next block of the block to deallocate
+ //This ordering comparison must be done with original pointers
+ //types since their mapping to raw pointers can be different
+ //in each process
+ while((detail::get_pointer(pos) != &m_header.m_root) && (block > pos)){
+ prev = pos;
+ pos = pos->m_next;
+ }
+
+ //Try to combine with upper block
+ if ((reinterpret_cast<char*>(detail::get_pointer(block))
+ + Alignment*block->m_size) ==
+ reinterpret_cast<char*>(detail::get_pointer(pos))){
+
+ block->m_size += pos->m_size;
+ block->m_next = pos->m_next;
+ }
+ else{
+ block->m_next = pos;
+ }
+
+ //Try to combine with lower block
+ if ((reinterpret_cast<char*>(detail::get_pointer(prev))
+ + Alignment*prev->m_size) ==
+ reinterpret_cast<char*>(detail::get_pointer(block))){
+ prev->m_size += block->m_size;
+ prev->m_next = block->m_next;
+ }
+ else{
+ prev->m_next = block;
+ }
+}
+
+} //namespace detail {
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
+
Added: sandbox/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1101 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
+#define BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/min_max.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
+#include <algorithm>
+#include <utility>
+#include <cstring>
+#include <cassert>
+#include <new>
+
+//!\file
+//!Describes sequential fit algorithm used to allocate objects in shared memory.
+//!This class is intended as a base class for single segment and multi-segment
+//!implementations.
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+//!This class implements the simple sequential fit algorithm with a simply
+//!linked list of free buffers.
+//!This class is intended as a base class for single segment and multi-segment
+//!implementations.
+template<class MutexFamily, class VoidPointer>
+class simple_seq_fit_impl
+{
+ //Non-copyable
+ simple_seq_fit_impl();
+ simple_seq_fit_impl(const simple_seq_fit_impl &);
+ simple_seq_fit_impl &operator=(const simple_seq_fit_impl &);
+
+ public:
+
+ //!Shared interprocess_mutex family used for the rest of the Interprocess framework
+ typedef MutexFamily mutex_family;
+ //!Pointer type to be used with the rest of the Interprocess framework
+ typedef VoidPointer void_pointer;
+ typedef detail::basic_multiallocation_cached_slist<void_pointer> multialloc_cached;
+ typedef detail::basic_multiallocation_cached_counted_slist
+ <multialloc_cached> multiallocation_chain;
+
+ private:
+ class block_ctrl;
+ typedef typename detail::
+ pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr;
+
+ class block_ctrl;
+ friend class block_ctrl;
+
+ //!Block control structure
+ class block_ctrl
+ {
+ public:
+ //!Offset pointer to the next block.
+ block_ctrl_ptr m_next;
+ //!This block's memory size (including block_ctrl
+ //!header) in BasicSize units
+ std::size_t m_size;
+
+ std::size_t get_user_bytes() const
+ { return this->m_size*Alignment - BlockCtrlBytes; }
+
+ std::size_t get_total_bytes() const
+ { return this->m_size*Alignment; }
+ };
+
+ //!Shared interprocess_mutex to protect memory allocate/deallocate
+ typedef typename MutexFamily::mutex_type interprocess_mutex;
+
+ //!This struct includes needed data and derives from
+ //!interprocess_mutex to allow EBO when using null interprocess_mutex
+ struct header_t : public interprocess_mutex
+ {
+ //!Pointer to the first free block
+ block_ctrl m_root;
+ //!Allocated bytes for internal checking
+ std::size_t m_allocated;
+ //!The size of the memory segment
+ std::size_t m_size;
+ //!The extra size required by the segment
+ std::size_t m_extra_hdr_bytes;
+ } m_header;
+
+ friend class detail::memory_algorithm_common<simple_seq_fit_impl>;
+
+ typedef detail::memory_algorithm_common<simple_seq_fit_impl> algo_impl_t;
+
+ public:
+ //!Constructor. "size" is the total size of the managed memory segment,
+ //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit_impl)
+ //!offset that the allocator should not use at all.
+ simple_seq_fit_impl (std::size_t size, std::size_t extra_hdr_bytes);
+
+ //!Destructor
+ ~simple_seq_fit_impl();
+
+ //!Obtains the minimum size needed by the algorithm
+ static std::size_t get_min_size (std::size_t extra_hdr_bytes);
+
+ //Functions for single segment management
+
+ //!Allocates bytes, returns 0 if there is not more memory
+ void* allocate (std::size_t nbytes);
+
+ /// @cond
+
+ //!Multiple element allocation, same size
+ multiallocation_chain
+ allocate_many(std::size_t elem_bytes, std::size_t num_elements)
+ {
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return algo_impl_t::allocate_many(this, elem_bytes, num_elements);
+ }
+
+ //!Multiple element allocation, different size
+ multiallocation_chain
+ allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element)
+ {
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element);
+ }
+
+ //!Multiple element deallocation
+ void deallocate_many(multiallocation_chain chain);
+
+ /// @endcond
+
+ //!Deallocates previously allocated bytes
+ void deallocate (void *addr);
+
+ //!Returns the size of the memory segment
+ std::size_t get_size() const;
+
+ //!Returns the number of free bytes of the memory segment
+ std::size_t get_free_memory() const;
+
+ //!Increases managed memory in extra_size bytes more
+ void grow(std::size_t extra_size);
+
+ //!Decreases managed memory as much as possible
+ void shrink_to_fit();
+
+ //!Returns true if all allocated memory has been deallocated
+ bool all_memory_deallocated();
+
+ //!Makes an internal sanity check and returns true if success
+ bool check_sanity();
+
+ //!Initializes to zero all the memory that's not in use.
+ //!This function is normally used for security reasons.
+ void zero_free_memory();
+
+ template<class T>
+ std::pair<T *, bool>
+ allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ T *reuse_ptr = 0);
+
+ std::pair<void *, bool>
+ raw_allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ void *reuse_ptr = 0, std::size_t sizeof_object = 1);
+
+ //!Returns the size of the buffer previously allocated pointed by ptr
+ std::size_t size(const void *ptr) const;
+
+ //!Allocates aligned bytes, returns 0 if there is not more memory.
+ //!Alignment must be power of 2
+ void* allocate_aligned (std::size_t nbytes, std::size_t alignment);
+
+ private:
+
+ //!Obtains the pointer returned to the user from the block control
+ static void *priv_get_user_buffer(const block_ctrl *block);
+
+ //!Obtains the block control structure of the user buffer
+ static block_ctrl *priv_get_block(const void *ptr);
+
+ //!Real allocation algorithm with min allocation option
+ std::pair<void *, bool> priv_allocate(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr = 0);
+
+ std::pair<void *, bool> priv_allocation_command(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,std::size_t sizeof_object);
+
+ //!Returns the number of total units that a user buffer
+ //!of "userbytes" bytes really occupies (including header)
+ static std::size_t priv_get_total_units(std::size_t userbytes);
+
+ static std::size_t priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes);
+ std::size_t priv_block_end_offset() const;
+
+ //!Returns next block if it's free.
+ //!Returns 0 if next block is not free.
+ block_ctrl *priv_next_block_if_free(block_ctrl *ptr);
+
+ //!Check if this block is free (not allocated)
+ bool priv_is_allocated_block(block_ctrl *ptr);
+
+ //!Returns previous block's if it's free.
+ //!Returns 0 if previous block is not free.
+ std::pair<block_ctrl*, block_ctrl*>priv_prev_block_if_free(block_ctrl *ptr);
+
+ //!Real expand function implementation
+ bool priv_expand(void *ptr
+ ,std::size_t min_size, std::size_t preferred_size
+ ,std::size_t &received_size);
+
+ //!Real expand to both sides implementation
+ void* priv_expand_both_sides(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,bool only_preferred_backwards);
+
+ //!Real private aligned allocation function
+ //void* priv_allocate_aligned (std::size_t nbytes, std::size_t alignment);
+
+ //!Checks if block has enough memory and splits/unlinks the block
+ //!returning the address to the users
+ void* priv_check_and_allocate(std::size_t units
+ ,block_ctrl* prev
+ ,block_ctrl* block
+ ,std::size_t &received_size);
+ //!Real deallocation algorithm
+ void priv_deallocate(void *addr);
+
+ //!Makes a new memory portion available for allocation
+ void priv_add_segment(void *addr, std::size_t size);
+
+ void priv_mark_new_allocated_block(block_ctrl *block);
+
+ public:
+ static const std::size_t Alignment = detail::alignment_of<detail::max_align>::value;
+ private:
+ static const std::size_t BlockCtrlBytes = detail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value;
+ static const std::size_t BlockCtrlUnits = BlockCtrlBytes/Alignment;
+ static const std::size_t MinBlockUnits = BlockCtrlUnits;
+ static const std::size_t MinBlockSize = MinBlockUnits*Alignment;
+ static const std::size_t AllocatedCtrlBytes = BlockCtrlBytes;
+ static const std::size_t AllocatedCtrlUnits = BlockCtrlUnits;
+ static const std::size_t UsableByPreviousChunk = 0;
+
+ public:
+ static const std::size_t PayloadPerAllocation = BlockCtrlBytes;
+};
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>
+ ::priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes)
+{
+ //First align "this" pointer
+ std::size_t uint_this = (std::size_t)this_ptr;
+ std::size_t uint_aligned_this = uint_this/Alignment*Alignment;
+ std::size_t this_disalignment = (uint_this - uint_aligned_this);
+ std::size_t block1_off =
+ detail::get_rounded_size(sizeof(simple_seq_fit_impl) + extra_hdr_bytes + this_disalignment, Alignment)
+ - this_disalignment;
+ algo_impl_t::assert_alignment(this_disalignment + block1_off);
+ return block1_off;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>
+ ::priv_block_end_offset() const
+{
+ //First align "this" pointer
+ std::size_t uint_this = (std::size_t)this;
+ std::size_t uint_aligned_this = uint_this/Alignment*Alignment;
+ std::size_t this_disalignment = (uint_this - uint_aligned_this);
+ std::size_t old_end =
+ detail::get_truncated_size(m_header.m_size + this_disalignment, Alignment)
+ - this_disalignment;
+ algo_impl_t::assert_alignment(old_end + this_disalignment);
+ return old_end;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ simple_seq_fit_impl(std::size_t size, std::size_t extra_hdr_bytes)
+{
+ //Initialize sizes and counters
+ m_header.m_allocated = 0;
+ m_header.m_size = size;
+ m_header.m_extra_hdr_bytes = extra_hdr_bytes;
+
+ //Initialize pointers
+ std::size_t block1_off = priv_first_block_offset(this, extra_hdr_bytes);
+
+ m_header.m_root.m_next = reinterpret_cast<block_ctrl*>
+ ((reinterpret_cast<char*>(this) + block1_off));
+ algo_impl_t::assert_alignment(detail::get_pointer(m_header.m_root.m_next));
+ m_header.m_root.m_next->m_size = (size - block1_off)/Alignment;
+ m_header.m_root.m_next->m_next = &m_header.m_root;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline simple_seq_fit_impl<MutexFamily, VoidPointer>::~simple_seq_fit_impl()
+{
+ //There is a memory leak!
+// assert(m_header.m_allocated == 0);
+// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root));
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::grow(std::size_t extra_size)
+{
+ //Old highest address block's end offset
+ std::size_t old_end = this->priv_block_end_offset();
+
+ //Update managed buffer's size
+ m_header.m_size += extra_size;
+
+ //We need at least MinBlockSize blocks to create a new block
+ if((m_header.m_size - old_end) < MinBlockSize){
+ return;
+ }
+
+ //We'll create a new free block with extra_size bytes
+
+ block_ctrl *new_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(this) + old_end);
+
+ algo_impl_t::assert_alignment(new_block);
+ new_block->m_next = 0;
+ new_block->m_size = (m_header.m_size - old_end)/Alignment;
+ m_header.m_allocated += new_block->m_size*Alignment;
+ this->priv_deallocate(priv_get_user_buffer(new_block));
+}
+
+template<class MutexFamily, class VoidPointer>
+void simple_seq_fit_impl<MutexFamily, VoidPointer>::shrink_to_fit()
+{
+ //Get the root and the first memory block
+ block_ctrl *prev = &m_header.m_root;
+ block_ctrl *last = &m_header.m_root;
+ block_ctrl *block = detail::get_pointer(last->m_next);
+ block_ctrl *root = &m_header.m_root;
+
+ //No free block?
+ if(block == root) return;
+
+ //Iterate through the free block list
+ while(block != root){
+ prev = last;
+ last = block;
+ block = detail::get_pointer(block->m_next);
+ }
+
+ char *last_free_end_address = reinterpret_cast<char*>(last) + last->m_size*Alignment;
+ if(last_free_end_address != (reinterpret_cast<char*>(this) + priv_block_end_offset())){
+ //there is an allocated block in the end of this block
+ //so no shrinking is possible
+ return;
+ }
+
+ //Check if have only 1 big free block
+ void *unique_block = 0;
+ if(!m_header.m_allocated){
+ assert(prev == root);
+ std::size_t ignore;
+ unique_block = priv_allocate(allocate_new, 0, 0, ignore).first;
+ if(!unique_block)
+ return;
+ last = detail::get_pointer(m_header.m_root.m_next);
+ assert(last_free_end_address == (reinterpret_cast<char*>(last) + last->m_size*Alignment));
+ }
+ std::size_t last_units = last->m_size;
+
+ std::size_t received_size;
+ void *addr = priv_check_and_allocate(last_units, prev, last, received_size);
+ (void)addr;
+ assert(addr);
+ assert(received_size == last_units*Alignment - AllocatedCtrlBytes);
+
+ //Shrink it
+ m_header.m_size /= Alignment;
+ m_header.m_size -= last->m_size;
+ m_header.m_size *= Alignment;
+ m_header.m_allocated -= last->m_size*Alignment;
+
+ if(unique_block)
+ priv_deallocate(unique_block);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_mark_new_allocated_block(block_ctrl *new_block)
+{
+ new_block->m_next = 0;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline
+typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
+ simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_get_block(const void *ptr)
+{
+ return const_cast<block_ctrl*>(reinterpret_cast<const block_ctrl*>
+ (reinterpret_cast<const char*>(ptr) - AllocatedCtrlBytes));
+}
+
+template<class MutexFamily, class VoidPointer>
+inline
+void *simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_get_user_buffer(const typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *block)
+{
+ return const_cast<char*>(reinterpret_cast<const char*>(block) + AllocatedCtrlBytes);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_add_segment(void *addr, std::size_t size)
+{
+ algo_impl_t::assert_alignment(addr);
+ //Check size
+ assert(!(size < MinBlockSize));
+ if(size < MinBlockSize)
+ return;
+ //Construct big block using the new segment
+ block_ctrl *new_block = static_cast<block_ctrl *>(addr);
+ new_block->m_size = size/Alignment;
+ new_block->m_next = 0;
+ //Simulate this block was previously allocated
+ m_header.m_allocated += new_block->m_size*Alignment;
+ //Return block and insert it in the free block list
+ this->priv_deallocate(priv_get_user_buffer(new_block));
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::get_size() const
+ { return m_header.m_size; }
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::get_free_memory() const
+{
+ return m_header.m_size - m_header.m_allocated -
+ algo_impl_t::multiple_of_units(sizeof(*this) + m_header.m_extra_hdr_bytes);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ get_min_size (std::size_t extra_hdr_bytes)
+{
+ return detail::get_rounded_size(sizeof(simple_seq_fit_impl),Alignment) +
+ detail::get_rounded_size(extra_hdr_bytes,Alignment)
+ + MinBlockSize;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ all_memory_deallocated()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return m_header.m_allocated == 0 &&
+ detail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::zero_free_memory()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ block_ctrl *block = detail::get_pointer(m_header.m_root.m_next);
+
+ //Iterate through all free portions
+ do{
+ //Just clear user the memory part reserved for the user
+ std::memset( priv_get_user_buffer(block)
+ , 0
+ , block->get_user_bytes());
+ block = detail::get_pointer(block->m_next);
+ }
+ while(block != &m_header.m_root);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ check_sanity()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ block_ctrl *block = detail::get_pointer(m_header.m_root.m_next);
+
+ std::size_t free_memory = 0;
+
+ //Iterate through all blocks obtaining their size
+ while(block != &m_header.m_root){
+ algo_impl_t::assert_alignment(block);
+ if(!algo_impl_t::check_alignment(block))
+ return false;
+ //Free blocks's next must be always valid
+ block_ctrl *next = detail::get_pointer(block->m_next);
+ if(!next){
+ return false;
+ }
+ free_memory += block->m_size*Alignment;
+ block = next;
+ }
+
+ //Check allocated bytes are less than size
+ if(m_header.m_allocated > m_header.m_size){
+ return false;
+ }
+
+ //Check free bytes are less than size
+ if(free_memory > m_header.m_size){
+ return false;
+ }
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ allocate(std::size_t nbytes)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ std::size_t ignore;
+ return priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ allocate_aligned(std::size_t nbytes, std::size_t alignment)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return algo_impl_t::
+ allocate_aligned(this, nbytes, alignment);
+}
+
+template<class MutexFamily, class VoidPointer>
+template<class T>
+inline std::pair<T*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ T *reuse_ptr)
+{
+ std::pair<void*, bool> ret = priv_allocation_command
+ (command, limit_size, preferred_size, received_size, static_cast<void*>(reuse_ptr), sizeof(T));
+
+ BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of<T>::value));
+ return std::pair<T *, bool>(static_cast<T*>(ret.first), ret.second);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ raw_allocation_command (allocation_type command, std::size_t limit_objects,
+ std::size_t preferred_objects,std::size_t &received_objects,
+ void *reuse_ptr, std::size_t sizeof_object)
+{
+ if(!sizeof_object)
+ return std::pair<void *, bool>(static_cast<void*>(0), 0);
+ if(command & try_shrink_in_place){
+ bool success = algo_impl_t::try_shrink
+ ( this, reuse_ptr, limit_objects*sizeof_object
+ , preferred_objects*sizeof_object, received_objects);
+ received_objects /= sizeof_object;
+ return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
+ }
+ return priv_allocation_command
+ (command, limit_objects, preferred_objects, received_objects, reuse_ptr, sizeof_object);
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::pair<void*, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size, std::size_t &received_size,
+ void *reuse_ptr, std::size_t sizeof_object)
+{
+ command &= ~expand_bwd;
+ if(!command) return std::pair<void *, bool>(static_cast<void*>(0), false);
+
+ std::pair<void*, bool> ret;
+ std::size_t max_count = m_header.m_size/sizeof_object;
+ if(limit_size > max_count || preferred_size > max_count){
+ ret.first = 0; return ret;
+ }
+ std::size_t l_size = limit_size*sizeof_object;
+ std::size_t p_size = preferred_size*sizeof_object;
+ std::size_t r_size;
+ {
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ ret = priv_allocate(command, l_size, p_size, r_size, reuse_ptr);
+ }
+ received_size = r_size/sizeof_object;
+ return ret;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ size(const void *ptr) const
+{
+ //We need no synchronization since this block is not going
+ //to be modified
+ //Obtain the real size of the block
+ const block_ctrl *block = static_cast<const block_ctrl*>(priv_get_block(ptr));
+ return block->get_user_bytes();
+}
+
+template<class MutexFamily, class VoidPointer>
+void* simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_expand_both_sides(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,bool only_preferred_backwards)
+{
+ typedef std::pair<block_ctrl *, block_ctrl *> prev_block_t;
+ block_ctrl *reuse = priv_get_block(reuse_ptr);
+ received_size = 0;
+
+ if(this->size(reuse_ptr) > min_size){
+ received_size = this->size(reuse_ptr);
+ return reuse_ptr;
+ }
+
+ if(command & expand_fwd){
+ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size))
+ return reuse_ptr;
+ }
+ else{
+ received_size = this->size(reuse_ptr);
+ }
+ if(command & expand_bwd){
+ std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes;
+ prev_block_t prev_pair = priv_prev_block_if_free(reuse);
+ block_ctrl *prev = prev_pair.second;
+ if(!prev){
+ return 0;
+ }
+
+ std::size_t needs_backwards =
+ detail::get_rounded_size(preferred_size - extra_forward, Alignment);
+
+ if(!only_preferred_backwards){
+ max_value(detail::get_rounded_size(min_size - extra_forward, Alignment)
+ ,min_value(prev->get_user_bytes(), needs_backwards));
+ }
+
+ //Check if previous block has enough size
+ if((prev->get_user_bytes()) >= needs_backwards){
+ //Now take all next space. This will succeed
+ if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){
+ assert(0);
+ }
+
+ //We need a minimum size to split the previous one
+ if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){
+ block_ctrl *new_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(reuse) - needs_backwards - BlockCtrlBytes);
+
+ new_block->m_next = 0;
+ new_block->m_size =
+ BlockCtrlUnits + (needs_backwards + extra_forward)/Alignment;
+ prev->m_size =
+ (prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlUnits;
+ received_size = needs_backwards + extra_forward;
+ m_header.m_allocated += needs_backwards + BlockCtrlBytes;
+ return priv_get_user_buffer(new_block);
+ }
+ else{
+ //Just merge the whole previous block
+ block_ctrl *prev_2_block = prev_pair.first;
+ //Update received size and allocation
+ received_size = extra_forward + prev->get_user_bytes();
+ m_header.m_allocated += prev->get_total_bytes();
+ //Now unlink it from previous block
+ prev_2_block->m_next = prev->m_next;
+ prev->m_size = reuse->m_size + prev->m_size;
+ prev->m_next = 0;
+ priv_get_user_buffer(prev);
+ }
+ }
+ }
+ return 0;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline void simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ deallocate_many(typename simple_seq_fit_impl<MutexFamily, VoidPointer>::multiallocation_chain chain)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ while(!chain.empty()){
+ void *addr = chain.front();
+ chain.pop_front();
+ this->priv_deallocate(addr);
+ }
+}
+
+template<class MutexFamily, class VoidPointer>
+inline std::size_t simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_get_total_units(std::size_t userbytes)
+{
+ std::size_t s = detail::get_rounded_size(userbytes, Alignment)/Alignment;
+ if(!s) ++s;
+ return BlockCtrlUnits + s;
+}
+
+template<class MutexFamily, class VoidPointer>
+std::pair<void *, bool> simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_allocate(allocation_type command
+ ,std::size_t limit_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr)
+{
+ if(command & shrink_in_place){
+ bool success =
+ algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size);
+ return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
+ }
+ typedef std::pair<void *, bool> return_type;
+ received_size = 0;
+
+ if(limit_size > preferred_size)
+ return return_type(static_cast<void*>(0), false);
+
+ //Number of units to request (including block_ctrl header)
+ std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlUnits;
+
+ //Get the root and the first memory block
+ block_ctrl *prev = &m_header.m_root;
+ block_ctrl *block = detail::get_pointer(prev->m_next);
+ block_ctrl *root = &m_header.m_root;
+ block_ctrl *biggest_block = 0;
+ block_ctrl *prev_biggest_block = 0;
+ std::size_t biggest_size = 0;
+
+ //Expand in place
+ //reuse_ptr, limit_size, preferred_size, received_size
+ //
+ if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
+ void *ret = priv_expand_both_sides
+ (command, limit_size, preferred_size, received_size, reuse_ptr, true);
+ if(ret){
+ algo_impl_t::assert_alignment(ret);
+ return return_type(ret, true);
+ }
+ }
+
+ if(command & allocate_new){
+ received_size = 0;
+ while(block != root){
+ //Update biggest block pointers
+ if(block->m_size > biggest_size){
+ prev_biggest_block = prev;
+ biggest_size = block->m_size;
+ biggest_block = block;
+ }
+ algo_impl_t::assert_alignment(block);
+ void *addr = this->priv_check_and_allocate(nunits, prev, block, received_size);
+ if(addr){
+ algo_impl_t::assert_alignment(addr);
+ return return_type(addr, false);
+ }
+ //Bad luck, let's check next block
+ prev = block;
+ block = detail::get_pointer(block->m_next);
+ }
+
+ //Bad luck finding preferred_size, now if we have any biggest_block
+ //try with this block
+ if(biggest_block){
+ std::size_t limit_units = detail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlUnits;
+ if(biggest_block->m_size < limit_units)
+ return return_type(static_cast<void*>(0), false);
+
+ received_size = biggest_block->m_size*Alignment - BlockCtrlUnits;
+ void *ret = this->priv_check_and_allocate
+ (biggest_block->m_size, prev_biggest_block, biggest_block, received_size);
+ assert(ret != 0);
+ algo_impl_t::assert_alignment(ret);
+ return return_type(ret, false);
+ }
+ }
+ //Now try to expand both sides with min size
+ if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
+ return_type ret (priv_expand_both_sides
+ (command, limit_size, preferred_size, received_size, reuse_ptr, false), true);
+ algo_impl_t::assert_alignment(ret.first);
+ return ret;
+ }
+ return return_type(static_cast<void*>(0), false);
+}
+
+template<class MutexFamily, class VoidPointer> inline
+bool simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_is_allocated_block
+ (typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *block)
+{ return block->m_next == 0; }
+
+template<class MutexFamily, class VoidPointer>
+inline typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
+ simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_next_block_if_free
+ (typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
+{
+ //Take the address where the next block should go
+ block_ctrl *next_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(ptr) + ptr->m_size*Alignment);
+
+ //Check if the adjacent block is in the managed segment
+ char *this_char_ptr = reinterpret_cast<char*>(this);
+ char *next_char_ptr = reinterpret_cast<char*>(next_block);
+ std::size_t distance = (next_char_ptr - this_char_ptr)/Alignment;
+
+ if(distance >= (m_header.m_size/Alignment)){
+ //"next_block" does not exist so we can't expand "block"
+ return 0;
+ }
+
+ if(!next_block->m_next)
+ return 0;
+
+ return next_block;
+}
+
+template<class MutexFamily, class VoidPointer>
+inline
+ std::pair<typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *
+ ,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *>
+ simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_prev_block_if_free
+ (typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl *ptr)
+{
+ typedef std::pair<block_ctrl *, block_ctrl *> prev_pair_t;
+ //Take the address where the previous block should go
+ block_ctrl *root = &m_header.m_root;
+ block_ctrl *prev_2_block = root;
+ block_ctrl *prev_block = detail::get_pointer(root->m_next);
+
+ while((reinterpret_cast<char*>(prev_block) + prev_block->m_size*Alignment)
+ != reinterpret_cast<char*>(ptr)
+ && prev_block != root){
+ prev_2_block = prev_block;
+ prev_block = detail::get_pointer(prev_block->m_next);
+ }
+
+ if(prev_block == root || !prev_block->m_next)
+ return prev_pair_t(static_cast<block_ctrl*>(0), static_cast<block_ctrl*>(0));
+
+ //Check if the previous block is in the managed segment
+ char *this_char_ptr = reinterpret_cast<char*>(this);
+ char *prev_char_ptr = reinterpret_cast<char*>(prev_block);
+ std::size_t distance = (prev_char_ptr - this_char_ptr)/Alignment;
+
+ if(distance >= (m_header.m_size/Alignment)){
+ //"previous_block" does not exist so we can't expand "block"
+ return prev_pair_t(static_cast<block_ctrl*>(0), static_cast<block_ctrl*>(0));
+ }
+ return prev_pair_t(prev_2_block, prev_block);
+}
+
+
+template<class MutexFamily, class VoidPointer>
+inline bool simple_seq_fit_impl<MutexFamily, VoidPointer>::
+ priv_expand (void *ptr
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size)
+{
+ //Obtain the real size of the block
+ block_ctrl *block = reinterpret_cast<block_ctrl*>(priv_get_block(ptr));
+ std::size_t old_block_size = block->m_size;
+
+ //All used blocks' next is marked with 0 so check it
+ assert(block->m_next == 0);
+
+ //Put this to a safe value
+ received_size = old_block_size*Alignment - BlockCtrlBytes;
+
+ //Now translate it to Alignment units
+ min_size = detail::get_rounded_size(min_size, Alignment)/Alignment;
+ preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment;
+
+ //Some parameter checks
+ if(min_size > preferred_size)
+ return false;
+
+ std::size_t data_size = old_block_size - BlockCtrlUnits;
+
+ if(data_size >= min_size)
+ return true;
+
+ block_ctrl *next_block = priv_next_block_if_free(block);
+ if(!next_block){
+ return false;
+ }
+
+ //Is "block" + "next_block" big enough?
+ std::size_t merged_size = old_block_size + next_block->m_size;
+
+ //Now we can expand this block further than before
+ received_size = merged_size*Alignment - BlockCtrlBytes;
+
+ if(merged_size < (min_size + BlockCtrlUnits)){
+ return false;
+ }
+
+ //We can fill expand. Merge both blocks,
+ block->m_next = next_block->m_next;
+ block->m_size = merged_size;
+
+ //Find the previous free block of next_block
+ block_ctrl *prev = &m_header.m_root;
+ while(detail::get_pointer(prev->m_next) != next_block){
+ prev = detail::get_pointer(prev->m_next);
+ }
+
+ //Now insert merged block in the free list
+ //This allows reusing allocation logic in this function
+ m_header.m_allocated -= old_block_size*Alignment;
+ prev->m_next = block;
+
+ //Now use check and allocate to do the allocation logic
+ preferred_size += BlockCtrlUnits;
+ std::size_t nunits = preferred_size < merged_size ? preferred_size : merged_size;
+
+ //This must success since nunits is less than merged_size!
+ if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){
+ //Something very ugly is happening here. This is a bug
+ //or there is memory corruption
+ assert(0);
+ return false;
+ }
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer> inline
+void* simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_check_and_allocate
+ (std::size_t nunits
+ ,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* prev
+ ,typename simple_seq_fit_impl<MutexFamily, VoidPointer>::block_ctrl* block
+ ,std::size_t &received_size)
+{
+ std::size_t upper_nunits = nunits + BlockCtrlUnits;
+ bool found = false;
+
+ if (block->m_size > upper_nunits){
+ //This block is bigger than needed, split it in
+ //two blocks, the first's size will be "units"
+ //the second's size will be "block->m_size-units"
+ std::size_t total_size = block->m_size;
+ block->m_size = nunits;
+
+ block_ctrl *new_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(block) + Alignment*nunits);
+ new_block->m_size = total_size - nunits;
+ new_block->m_next = block->m_next;
+ prev->m_next = new_block;
+ found = true;
+ }
+ else if (block->m_size >= nunits){
+ //This block has exactly the right size with an extra
+ //unusable extra bytes.
+ prev->m_next = block->m_next;
+ found = true;
+ }
+
+ if(found){
+ //We need block_ctrl for deallocation stuff, so
+ //return memory user can overwrite
+ m_header.m_allocated += block->m_size*Alignment;
+ received_size = block->get_user_bytes();
+ //Mark the block as allocated
+ block->m_next = 0;
+ //Check alignment
+ algo_impl_t::assert_alignment(block);
+ return priv_get_user_buffer(block);
+ }
+ return 0;
+}
+
+template<class MutexFamily, class VoidPointer>
+void simple_seq_fit_impl<MutexFamily, VoidPointer>::deallocate(void* addr)
+{
+ if(!addr) return;
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return this->priv_deallocate(addr);
+}
+
+template<class MutexFamily, class VoidPointer>
+void simple_seq_fit_impl<MutexFamily, VoidPointer>::priv_deallocate(void* addr)
+{
+ if(!addr) return;
+
+ //Let's get free block list. List is always sorted
+ //by memory address to allow block merging.
+ //Pointer next always points to the first
+ //(lower address) block
+ block_ctrl * prev = &m_header.m_root;
+ block_ctrl * pos = detail::get_pointer(m_header.m_root.m_next);
+ block_ctrl * block = reinterpret_cast<block_ctrl*>(priv_get_block(addr));
+
+ //All used blocks' next is marked with 0 so check it
+ assert(block->m_next == 0);
+
+ //Check if alignment and block size are right
+ algo_impl_t::assert_alignment(addr);
+
+ std::size_t total_size = Alignment*block->m_size;
+ assert(m_header.m_allocated >= total_size);
+
+ //Update used memory count
+ m_header.m_allocated -= total_size;
+
+ //Let's find the previous and the next block of the block to deallocate
+ //This ordering comparison must be done with original pointers
+ //types since their mapping to raw pointers can be different
+ //in each process
+ while((detail::get_pointer(pos) != &m_header.m_root) && (block > pos)){
+ prev = pos;
+ pos = detail::get_pointer(pos->m_next);
+ }
+
+ //Try to combine with upper block
+ char *block_char_ptr = reinterpret_cast<char*>(detail::get_pointer(block));
+
+ if ((block_char_ptr + Alignment*block->m_size) ==
+ reinterpret_cast<char*>(detail::get_pointer(pos))){
+ block->m_size += pos->m_size;
+ block->m_next = pos->m_next;
+ }
+ else{
+ block->m_next = pos;
+ }
+
+ //Try to combine with lower block
+ if ((reinterpret_cast<char*>(detail::get_pointer(prev))
+ + Alignment*prev->m_size) ==
+ block_char_ptr){
+
+
+ prev->m_size += block->m_size;
+ prev->m_next = block->m_next;
+ }
+ else{
+ prev->m_next = block;
+ }
+}
+
+} //namespace detail {
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP
+
Added: sandbox/boost/interprocess/mem_algo/rbtree_best_fit.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mem_algo/rbtree_best_fit.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1311 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MEM_ALGO_RBTREE_BEST_FIT_HPP
+#define BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
+#include <boost/interprocess/allocators/allocation_type.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/min_max.hpp>
+#include <boost/interprocess/detail/math_functions.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <algorithm>
+#include <utility>
+#include <climits>
+#include <cstring>
+#include <iterator>
+
+#include <cassert>
+#include <new>
+
+#include <boost/intrusive/set.hpp>
+
+//!\file
+//!Describes a best-fit algorithm based in an intrusive red-black tree used to allocate
+//!objects in shared memory. This class is intended as a base class for single segment
+//!and multi-segment implementations.
+
+namespace boost {
+namespace interprocess {
+
+//!This class implements an algorithm that stores the free nodes in a red-black tree
+//!to have logarithmic search/insert times.
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+class rbtree_best_fit
+{
+ /// @cond
+ //Non-copyable
+ rbtree_best_fit();
+ rbtree_best_fit(const rbtree_best_fit &);
+ rbtree_best_fit &operator=(const rbtree_best_fit &);
+ /// @endcond
+
+ public:
+ //!Shared interprocess_mutex family used for the rest of the Interprocess framework
+ typedef MutexFamily mutex_family;
+ //!Pointer type to be used with the rest of the Interprocess framework
+ typedef VoidPointer void_pointer;
+ //typedef detail::basic_multiallocation_cached_counted_slist<void_pointer> multiallocation_chain;
+
+ typedef detail::basic_multiallocation_cached_slist<void_pointer> multialloc_cached;
+ typedef detail::basic_multiallocation_cached_counted_slist
+ <multialloc_cached> multiallocation_chain;
+
+ /// @cond
+
+ private:
+ struct block_ctrl;
+ typedef typename detail::
+ pointer_to_other<void_pointer, block_ctrl>::type block_ctrl_ptr;
+ typedef typename detail::
+ pointer_to_other<void_pointer, char>::type char_ptr;
+
+ typedef typename bi::make_set_base_hook
+ < bi::void_pointer<VoidPointer>
+ , bi::optimize_size<true>
+ , bi::link_mode<bi::normal_link> >::type TreeHook;
+
+ struct SizeHolder
+ {
+ //!This block's memory size (including block_ctrl
+ //!header) in Alignment units
+ std::size_t m_prev_size : sizeof(std::size_t)*CHAR_BIT;
+ std::size_t m_size : sizeof(std::size_t)*CHAR_BIT - 2;
+ std::size_t m_prev_allocated : 1;
+ std::size_t m_allocated : 1;
+ };
+
+ //!Block control structure
+ struct block_ctrl
+ : public SizeHolder, public TreeHook
+ {
+ block_ctrl()
+ { this->m_size = 0; this->m_allocated = 0, this->m_prev_allocated = 0; }
+
+ friend bool operator<(const block_ctrl &a, const block_ctrl &b)
+ { return a.m_size < b.m_size; }
+ friend bool operator==(const block_ctrl &a, const block_ctrl &b)
+ { return a.m_size == b.m_size; }
+ };
+
+ struct size_block_ctrl_compare
+ {
+ bool operator()(std::size_t size, const block_ctrl &block) const
+ { return size < block.m_size; }
+
+ bool operator()(const block_ctrl &block, std::size_t size) const
+ { return block.m_size < size; }
+ };
+
+ //!Shared interprocess_mutex to protect memory allocate/deallocate
+ typedef typename MutexFamily::mutex_type interprocess_mutex;
+ typedef typename bi::make_multiset
+ <block_ctrl, bi::base_hook<TreeHook> >::type Imultiset;
+
+ typedef typename Imultiset::iterator imultiset_iterator;
+
+ //!This struct includes needed data and derives from
+ //!interprocess_mutex to allow EBO when using null interprocess_mutex
+ struct header_t : public interprocess_mutex
+ {
+ Imultiset m_imultiset;
+
+ //!The extra size required by the segment
+ std::size_t m_extra_hdr_bytes;
+ //!Allocated bytes for internal checking
+ std::size_t m_allocated;
+ //!The size of the memory segment
+ std::size_t m_size;
+ } m_header;
+
+ friend class detail::memory_algorithm_common<rbtree_best_fit>;
+
+ typedef detail::memory_algorithm_common<rbtree_best_fit> algo_impl_t;
+
+ public:
+ /// @endcond
+
+ //!Constructor. "size" is the total size of the managed memory segment,
+ //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(rbtree_best_fit)
+ //!offset that the allocator should not use at all.
+ rbtree_best_fit (std::size_t size, std::size_t extra_hdr_bytes);
+
+ //!Destructor.
+ ~rbtree_best_fit();
+
+ //!Obtains the minimum size needed by the algorithm
+ static std::size_t get_min_size (std::size_t extra_hdr_bytes);
+
+ //Functions for single segment management
+
+ //!Allocates bytes, returns 0 if there is not more memory
+ void* allocate (std::size_t nbytes);
+
+ /// @cond
+
+ //Experimental. Dont' use
+
+ //!Multiple element allocation, same size
+ multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements)
+ {
+
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return algo_impl_t::allocate_many(this, elem_bytes, num_elements);
+ }
+
+ //!Multiple element allocation, different size
+ multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element)
+ {
+
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element);
+ }
+
+ //!Multiple element allocation, different size
+ void deallocate_many(multiallocation_chain chain);
+
+ /// @endcond
+
+ //!Deallocates previously allocated bytes
+ void deallocate (void *addr);
+
+ //!Returns the size of the memory segment
+ std::size_t get_size() const;
+
+ //!Returns the number of free bytes of the segment
+ std::size_t get_free_memory() const;
+
+ //!Initializes to zero all the memory that's not in use.
+ //!This function is normally used for security reasons.
+ void zero_free_memory();
+
+ //!Increases managed memory in
+ //!extra_size bytes more
+ void grow(std::size_t extra_size);
+
+ //!Decreases managed memory as much as possible
+ void shrink_to_fit();
+
+ //!Returns true if all allocated memory has been deallocated
+ bool all_memory_deallocated();
+
+ //!Makes an internal sanity check
+ //!and returns true if success
+ bool check_sanity();
+
+ template<class T>
+ std::pair<T *, bool>
+ allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ T *reuse_ptr = 0);
+
+ std::pair<void *, bool>
+ raw_allocation_command (allocation_type command, std::size_t limit_object,
+ std::size_t preferred_object,std::size_t &received_object,
+ void *reuse_ptr = 0, std::size_t sizeof_object = 1);
+
+ //!Returns the size of the buffer previously allocated pointed by ptr
+ std::size_t size(const void *ptr) const;
+
+ //!Allocates aligned bytes, returns 0 if there is not more memory.
+ //!Alignment must be power of 2
+ void* allocate_aligned (std::size_t nbytes, std::size_t alignment);
+
+ /// @cond
+ private:
+ static std::size_t priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes);
+
+ std::pair<void*, bool>
+ priv_allocation_command(allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ void *reuse_ptr, std::size_t sizeof_object);
+
+
+ //!Real allocation algorithm with min allocation option
+ std::pair<void *, bool> priv_allocate(allocation_type command
+ ,std::size_t limit_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr = 0
+ ,std::size_t backwards_multiple = 1);
+
+ //!Obtains the block control structure of the user buffer
+ static block_ctrl *priv_get_block(const void *ptr);
+
+ //!Obtains the pointer returned to the user from the block control
+ static void *priv_get_user_buffer(const block_ctrl *block);
+
+ //!Returns the number of total units that a user buffer
+ //!of "userbytes" bytes really occupies (including header)
+ static std::size_t priv_get_total_units(std::size_t userbytes);
+
+ //!Real expand function implementation
+ bool priv_expand(void *ptr
+ ,const std::size_t min_size, const std::size_t preferred_size
+ ,std::size_t &received_size);
+
+ //!Real expand to both sides implementation
+ void* priv_expand_both_sides(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,bool only_preferred_backwards
+ ,std::size_t backwards_multiple);
+
+ //!Get poitner of the previous block (previous block must be free)
+ block_ctrl * priv_prev_block(block_ctrl *ptr);
+
+ //!Returns true if the previous block is allocated
+ bool priv_is_prev_allocated(block_ctrl *ptr);
+
+ //!Get a pointer of the "end" block from the first block of the segment
+ block_ctrl * priv_end_block(block_ctrl *first_segment_block);
+
+ //!Get the size in the tail of the previous block
+ block_ctrl * priv_next_block(block_ctrl *ptr);
+
+ //!Check if this block is free (not allocated)
+ bool priv_is_allocated_block(block_ctrl *ptr);
+
+ //!Marks the block as allocated
+ void priv_mark_as_allocated_block(block_ctrl *ptr);
+
+ //!Marks the block as allocated
+ void priv_mark_as_free_block(block_ctrl *ptr);
+
+ //!Checks if block has enough memory and splits/unlinks the block
+ //!returning the address to the users
+ void* priv_check_and_allocate(std::size_t units
+ ,block_ctrl* block
+ ,std::size_t &received_size);
+ //!Real deallocation algorithm
+ void priv_deallocate(void *addr);
+
+ //!Makes a new memory portion available for allocation
+ void priv_add_segment(void *addr, std::size_t size);
+
+ void priv_mark_new_allocated_block(block_ctrl *block);
+
+ public:
+
+ static const std::size_t Alignment = !MemAlignment
+ ? detail::alignment_of<detail::max_align>::value
+ : MemAlignment
+ ;
+
+ private:
+ //Due to embedded bits in size, Alignment must be at least 4
+ BOOST_STATIC_ASSERT((Alignment >= 4));
+ //Due to rbtree size optimizations, Alignment must have at least pointer alignment
+ BOOST_STATIC_ASSERT((Alignment >= detail::alignment_of<void_pointer>::value));
+ static const std::size_t AlignmentMask = (Alignment - 1);
+ static const std::size_t BlockCtrlBytes = detail::ct_rounded_size<sizeof(block_ctrl), Alignment>::value;
+ static const std::size_t BlockCtrlUnits = BlockCtrlBytes/Alignment;
+ static const std::size_t AllocatedCtrlBytes = detail::ct_rounded_size<sizeof(SizeHolder), Alignment>::value;
+ static const std::size_t AllocatedCtrlUnits = AllocatedCtrlBytes/Alignment;
+ static const std::size_t EndCtrlBlockBytes = detail::ct_rounded_size<sizeof(SizeHolder), Alignment>::value;
+ static const std::size_t EndCtrlBlockUnits = EndCtrlBlockBytes/Alignment;
+ static const std::size_t MinBlockUnits = BlockCtrlUnits;
+ static const std::size_t UsableByPreviousChunk = sizeof(std::size_t);
+
+ //Make sure the maximum alignment is power of two
+ BOOST_STATIC_ASSERT((0 == (Alignment & (Alignment - std::size_t(1u)))));
+ /// @endcond
+ public:
+ static const std::size_t PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk;
+};
+
+/// @cond
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::size_t rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>
+ ::priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes)
+{
+ std::size_t uint_this = (std::size_t)this_ptr;
+ std::size_t main_hdr_end = uint_this + sizeof(rbtree_best_fit) + extra_hdr_bytes;
+ std::size_t aligned_main_hdr_end = detail::get_rounded_size(main_hdr_end, Alignment);
+ std::size_t block1_off = aligned_main_hdr_end - uint_this;
+ algo_impl_t::assert_alignment(aligned_main_hdr_end);
+ algo_impl_t::assert_alignment(uint_this + block1_off);
+ return block1_off;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ rbtree_best_fit(std::size_t size, std::size_t extra_hdr_bytes)
+{
+ //Initialize the header
+ m_header.m_allocated = 0;
+ m_header.m_size = size;
+ m_header.m_extra_hdr_bytes = extra_hdr_bytes;
+
+ //Now write calculate the offset of the first big block that will
+ //cover the whole segment
+ assert(get_min_size(extra_hdr_bytes) <= size);
+ std::size_t block1_off = priv_first_block_offset(this, extra_hdr_bytes);
+ priv_add_segment(reinterpret_cast<char*>(this) + block1_off, size - block1_off);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::~rbtree_best_fit()
+{
+ //There is a memory leak!
+// assert(m_header.m_allocated == 0);
+// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root));
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::grow(std::size_t extra_size)
+{
+ //Get the address of the first block
+ std::size_t block1_off =
+ priv_first_block_offset(this, m_header.m_extra_hdr_bytes);
+
+ block_ctrl *first_block = reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(this) + block1_off);
+ block_ctrl *old_end_block = priv_end_block(first_block);
+ assert(priv_is_allocated_block(old_end_block));
+ std::size_t old_border_offset = (reinterpret_cast<char*>(old_end_block) -
+ reinterpret_cast<char*>(this)) + EndCtrlBlockBytes;
+
+ //Update managed buffer's size
+ m_header.m_size += extra_size;
+
+ //We need at least MinBlockUnits blocks to create a new block
+// assert((m_header.m_size - old_end) >= MinBlockUnits);
+ if((m_header.m_size - old_border_offset) < MinBlockUnits){
+ return;
+ }
+
+ //Now create a new block between the old end and the new end
+ std::size_t align_offset = (m_header.m_size - old_border_offset)/Alignment;
+ block_ctrl *new_end_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(old_end_block) + align_offset*Alignment);
+ new_end_block->m_size = (reinterpret_cast<char*>(first_block) -
+ reinterpret_cast<char*>(new_end_block))/Alignment;
+ first_block->m_prev_size = new_end_block->m_size;
+ assert(first_block == priv_next_block(new_end_block));
+ priv_mark_new_allocated_block(new_end_block);
+
+ assert(new_end_block == priv_end_block(first_block));
+
+ //The old end block is the new block
+ block_ctrl *new_block = old_end_block;
+ new_block->m_size = (reinterpret_cast<char*>(new_end_block) -
+ reinterpret_cast<char*>(new_block))/Alignment;
+ assert(new_block->m_size >= BlockCtrlUnits);
+ priv_mark_new_allocated_block(new_block);
+ assert(priv_next_block(new_block) == new_end_block);
+
+ m_header.m_allocated += new_block->m_size*Alignment;
+
+ //Now deallocate the newly created block
+ this->priv_deallocate(priv_get_user_buffer(new_block));
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::shrink_to_fit()
+{
+ //Get the address of the first block
+ std::size_t block1_off =
+ priv_first_block_offset(this, m_header.m_extra_hdr_bytes);
+
+ block_ctrl *first_block = reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(this) + block1_off);
+ algo_impl_t::assert_alignment(first_block);
+
+ block_ctrl *old_end_block = priv_end_block(first_block);
+ algo_impl_t::assert_alignment(old_end_block);
+ assert(priv_is_allocated_block(old_end_block));
+
+ algo_impl_t::assert_alignment(old_end_block);
+
+ std::size_t old_end_block_size = old_end_block->m_size;
+
+ void *unique_buffer = 0;
+ block_ctrl *last_block;
+ if(priv_next_block(first_block) == old_end_block){
+ std::size_t ignore;
+ unique_buffer = priv_allocate(allocate_new, 0, 0, ignore).first;
+ if(!unique_buffer)
+ return;
+ algo_impl_t::assert_alignment(unique_buffer);
+ block_ctrl *unique_block = priv_get_block(unique_buffer);
+ assert(priv_is_allocated_block(unique_block));
+ algo_impl_t::assert_alignment(unique_block);
+ last_block = priv_next_block(unique_block);
+ assert(!priv_is_allocated_block(last_block));
+ algo_impl_t::assert_alignment(last_block);
+ }
+ else{
+ if(priv_is_prev_allocated(old_end_block))
+ return;
+ last_block = priv_prev_block(old_end_block);
+ }
+
+ std::size_t last_block_size = last_block->m_size;
+
+ //Erase block from the free tree, since we will erase it
+ m_header.m_imultiset.erase(Imultiset::s_iterator_to(*last_block));
+
+ std::size_t shrunk_border_offset = (reinterpret_cast<char*>(last_block) -
+ reinterpret_cast<char*>(this)) + EndCtrlBlockBytes;
+
+ block_ctrl *new_end_block = last_block;
+ algo_impl_t::assert_alignment(new_end_block);
+ new_end_block->m_size = old_end_block_size + last_block_size;
+ priv_mark_as_allocated_block(new_end_block);
+
+ //Although the first block might be allocated, we'll
+ //store the offset to the end block since in the previous
+ //offset can't be overwritten by a previous block
+ first_block->m_prev_size = new_end_block->m_size;
+ assert(priv_end_block(first_block) == new_end_block);
+
+ //Update managed buffer's size
+ m_header.m_size = shrunk_border_offset;
+ if(unique_buffer)
+ priv_deallocate(unique_buffer);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_add_segment(void *addr, std::size_t size)
+{
+ //Check alignment
+ algo_impl_t::check_alignment(addr);
+ //Check size
+ assert(size >= (BlockCtrlBytes + EndCtrlBlockBytes));
+
+ //Initialize the first big block and the "end" node
+ block_ctrl *first_big_block = new(addr)block_ctrl;
+ first_big_block->m_size = size/Alignment - EndCtrlBlockUnits;
+ assert(first_big_block->m_size >= BlockCtrlUnits);
+
+ //The "end" node is just a node of size 0 with the "end" bit set
+ block_ctrl *end_block = static_cast<block_ctrl*>
+ (new (reinterpret_cast<char*>(addr) + first_big_block->m_size*Alignment)SizeHolder);
+
+ //This will overwrite the prev part of the "end" node
+ priv_mark_as_free_block (first_big_block);
+ first_big_block->m_prev_size = end_block->m_size =
+ (reinterpret_cast<char*>(first_big_block) - reinterpret_cast<char*>(end_block))/Alignment;
+ priv_mark_as_allocated_block(end_block);
+
+ assert(priv_next_block(first_big_block) == end_block);
+ assert(priv_next_block(end_block) == first_big_block);
+ assert(priv_end_block(first_big_block) == end_block);
+ assert(priv_prev_block(end_block) == first_big_block);
+
+ //Some check to validate the algorithm, since it makes some assumptions
+ //to optimize the space wasted in bookkeeping:
+
+ //Check that the sizes of the header are placed before the rbtree
+ assert(static_cast<void*>(static_cast<SizeHolder*>(first_big_block))
+ < static_cast<void*>(static_cast<TreeHook*>(first_big_block)));
+
+ //Check that the alignment is power of two (we use some optimizations based on this)
+ //assert((Alignment % 2) == 0);
+ //Insert it in the intrusive containers
+ m_header.m_imultiset.insert(*first_big_block);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_mark_new_allocated_block(block_ctrl *new_block)
+{ priv_mark_as_allocated_block(new_block); }
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::size_t rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::get_size() const
+{ return m_header.m_size; }
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::size_t rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::get_free_memory() const
+{
+ return m_header.m_size - m_header.m_allocated -
+ priv_first_block_offset(this, m_header.m_extra_hdr_bytes);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::size_t rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ get_min_size (std::size_t extra_hdr_bytes)
+{
+ return (algo_impl_t::ceil_units(sizeof(rbtree_best_fit)) +
+ algo_impl_t::ceil_units(extra_hdr_bytes) +
+ MinBlockUnits + EndCtrlBlockUnits)*Alignment;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ all_memory_deallocated()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ std::size_t block1_off =
+ priv_first_block_offset(this, m_header.m_extra_hdr_bytes);
+
+ return m_header.m_allocated == 0 &&
+ m_header.m_imultiset.begin() != m_header.m_imultiset.end() &&
+ (++m_header.m_imultiset.begin()) == m_header.m_imultiset.end()
+ && m_header.m_imultiset.begin()->m_size ==
+ (m_header.m_size - block1_off - EndCtrlBlockBytes)/Alignment;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ check_sanity()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ imultiset_iterator ib(m_header.m_imultiset.begin()), ie(m_header.m_imultiset.end());
+
+ std::size_t free_memory = 0;
+
+ //Iterate through all blocks obtaining their size
+ for(; ib != ie; ++ib){
+ free_memory += ib->m_size*Alignment;
+ algo_impl_t::assert_alignment(&*ib);
+ if(!algo_impl_t::check_alignment(&*ib))
+ return false;
+ }
+
+ //Check allocated bytes are less than size
+ if(m_header.m_allocated > m_header.m_size){
+ return false;
+ }
+
+ std::size_t block1_off =
+ priv_first_block_offset(this, m_header.m_extra_hdr_bytes);
+
+ //Check free bytes are less than size
+ if(free_memory > (m_header.m_size - block1_off)){
+ return false;
+ }
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ allocate(std::size_t nbytes)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ std::size_t ignore;
+ void * ret = priv_allocate(allocate_new, nbytes, nbytes, ignore).first;
+ return ret;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ allocate_aligned(std::size_t nbytes, std::size_t alignment)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return algo_impl_t::allocate_aligned(this, nbytes, alignment);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+template<class T>
+inline std::pair<T*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ T *reuse_ptr)
+{
+ std::pair<void*, bool> ret = priv_allocation_command
+ (command, limit_size, preferred_size, received_size, static_cast<void*>(reuse_ptr), sizeof(T));
+
+ BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of<T>::value));
+ return std::pair<T *, bool>(static_cast<T*>(ret.first), ret.second);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::pair<void*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ raw_allocation_command (allocation_type command, std::size_t limit_objects,
+ std::size_t preferred_objects,std::size_t &received_objects,
+ void *reuse_ptr, std::size_t sizeof_object)
+{
+ if(!sizeof_object)
+ return std::pair<void *, bool>(static_cast<void*>(0), 0);
+ if(command & try_shrink_in_place){
+ bool success = algo_impl_t::try_shrink
+ ( this, reuse_ptr, limit_objects*sizeof_object
+ , preferred_objects*sizeof_object, received_objects);
+ received_objects /= sizeof_object;
+ return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
+ }
+ return priv_allocation_command
+ (command, limit_objects, preferred_objects, received_objects, reuse_ptr, sizeof_object);
+}
+
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::pair<void*, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ void *reuse_ptr, std::size_t sizeof_object)
+{
+ std::pair<void*, bool> ret;
+ std::size_t max_count = m_header.m_size/sizeof_object;
+ if(limit_size > max_count || preferred_size > max_count){
+ ret.first = 0; return ret;
+ }
+ std::size_t l_size = limit_size*sizeof_object;
+ std::size_t p_size = preferred_size*sizeof_object;
+ std::size_t r_size;
+ {
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ ret = priv_allocate(command, l_size, p_size, r_size, reuse_ptr, sizeof_object);
+ }
+ received_size = r_size/sizeof_object;
+ return ret;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline std::size_t rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ size(const void *ptr) const
+{
+ //We need no synchronization since this block's size is not going
+ //to be modified by anyone else
+ //Obtain the real size of the block
+ return (priv_get_block(ptr)->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::zero_free_memory()
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ imultiset_iterator ib(m_header.m_imultiset.begin()), ie(m_header.m_imultiset.end());
+
+ //Iterate through all blocks obtaining their size
+ for(; ib != ie; ++ib){
+ //Just clear user the memory part reserved for the user
+ std::memset( reinterpret_cast<char*>(&*ib) + BlockCtrlBytes
+ , 0
+ , ib->m_size*Alignment - BlockCtrlBytes);
+ }
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_expand_both_sides(allocation_type command
+ ,std::size_t min_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,bool only_preferred_backwards
+ ,std::size_t backwards_multiple)
+{
+ algo_impl_t::assert_alignment(reuse_ptr);
+ if(command & expand_fwd){
+ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size))
+ return reuse_ptr;
+ }
+ else{
+ received_size = this->size(reuse_ptr);
+ if(received_size >= preferred_size || received_size >= min_size)
+ return reuse_ptr;
+ }
+
+ if(backwards_multiple){
+ BOOST_ASSERT(0 == (min_size % backwards_multiple));
+ BOOST_ASSERT(0 == (preferred_size % backwards_multiple));
+ }
+
+ if(command & expand_bwd){
+ //Obtain the real size of the block
+ block_ctrl *reuse = priv_get_block(reuse_ptr);
+
+ //Sanity check
+ //assert(reuse->m_size == priv_tail_size(reuse));
+ algo_impl_t::assert_alignment(reuse);
+
+ block_ctrl *prev_block;
+
+ //If the previous block is not free, there is nothing to do
+ if(priv_is_prev_allocated(reuse)){
+ return 0;
+ }
+
+ prev_block = priv_prev_block(reuse);
+ assert(!priv_is_allocated_block(prev_block));
+
+ //Some sanity checks
+ assert(prev_block->m_size == reuse->m_prev_size);
+ algo_impl_t::assert_alignment(prev_block);
+
+ std::size_t needs_backwards_aligned;
+ std::size_t lcm;
+ if(!algo_impl_t::calculate_lcm_and_needs_backwards_lcmed
+ ( backwards_multiple
+ , received_size
+ , only_preferred_backwards ? preferred_size : min_size
+ , lcm, needs_backwards_aligned)){
+ return 0;
+ }
+
+ //Check if previous block has enough size
+ if(std::size_t(prev_block->m_size*Alignment) >= needs_backwards_aligned){
+ //Now take all next space. This will succeed
+ if(command & expand_fwd){
+ std::size_t received_size2;
+ if(!priv_expand(reuse_ptr, received_size, received_size, received_size2)){
+ assert(0);
+ }
+ assert(received_size = received_size2);
+ }
+ //We need a minimum size to split the previous one
+ if(prev_block->m_size >= (needs_backwards_aligned/Alignment + BlockCtrlUnits)){
+ block_ctrl *new_block = reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(reuse) - needs_backwards_aligned);
+
+ //Free old previous buffer
+ new_block->m_size =
+ AllocatedCtrlUnits + (needs_backwards_aligned + (received_size - UsableByPreviousChunk))/Alignment;
+ assert(new_block->m_size >= BlockCtrlUnits);
+ priv_mark_new_allocated_block(new_block);
+
+ prev_block->m_size = (reinterpret_cast<char*>(new_block) -
+ reinterpret_cast<char*>(prev_block))/Alignment;
+ assert(prev_block->m_size >= BlockCtrlUnits);
+ priv_mark_as_free_block(prev_block);
+
+ //Update the old previous block in the free blocks tree
+ //If the new size fulfills tree invariants do nothing,
+ //otherwise erase() + insert()
+ {
+ imultiset_iterator prev_block_it(Imultiset::s_iterator_to(*prev_block));
+ imultiset_iterator was_smaller_it(prev_block_it);
+ if(prev_block_it != m_header.m_imultiset.begin() &&
+ (--(was_smaller_it = prev_block_it))->m_size > prev_block->m_size){
+ m_header.m_imultiset.erase(prev_block_it);
+ m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *prev_block);
+ }
+ }
+
+ received_size = needs_backwards_aligned + received_size;
+ m_header.m_allocated += needs_backwards_aligned;
+
+ //Check alignment
+ algo_impl_t::assert_alignment(new_block);
+
+ //If the backwards expansion has remaining bytes in the
+ //first bytes, fill them with a pattern
+ void *p = priv_get_user_buffer(new_block);
+ void *user_ptr = reinterpret_cast<char*>(p);
+ assert((static_cast<char*>(reuse_ptr) - static_cast<char*>(user_ptr)) % backwards_multiple == 0);
+ algo_impl_t::assert_alignment(user_ptr);
+ return user_ptr;
+ }
+ //Check if there is no place to create a new block and
+ //the whole new block is multiple of the backwards expansion multiple
+ else if(prev_block->m_size >= needs_backwards_aligned/Alignment &&
+ 0 == ((prev_block->m_size*Alignment) % lcm)) {
+ //Erase old previous block, since we will change it
+ m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block));
+
+ //Just merge the whole previous block
+ //prev_block->m_size*Alignment is multiple of lcm (and backwards_multiple)
+ received_size = received_size + prev_block->m_size*Alignment;
+
+ m_header.m_allocated += prev_block->m_size*Alignment;
+ //Now update sizes
+ prev_block->m_size = prev_block->m_size + reuse->m_size;
+ assert(prev_block->m_size >= BlockCtrlUnits);
+ priv_mark_new_allocated_block(prev_block);
+
+ //If the backwards expansion has remaining bytes in the
+ //first bytes, fill them with a pattern
+ void *user_ptr = priv_get_user_buffer(prev_block);
+ assert((static_cast<char*>(reuse_ptr) - static_cast<char*>(user_ptr)) % backwards_multiple == 0);
+ algo_impl_t::assert_alignment(user_ptr);
+ return user_ptr;
+ }
+ else{
+ //Alignment issues
+ }
+ }
+ }
+ return 0;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ deallocate_many(typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::multiallocation_chain chain)
+{
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ algo_impl_t::deallocate_many(this, boost::move(chain));
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+std::pair<void *, bool> rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_allocate(allocation_type command
+ ,std::size_t limit_size
+ ,std::size_t preferred_size
+ ,std::size_t &received_size
+ ,void *reuse_ptr
+ ,std::size_t backwards_multiple)
+{
+ //Remove me. Forbid backwards allocation
+ //command &= (~expand_bwd);
+
+ if(command & shrink_in_place){
+ bool success =
+ algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size);
+ return std::pair<void *, bool> ((success ? reuse_ptr : 0), true);
+ }
+
+ typedef std::pair<void *, bool> return_type;
+ received_size = 0;
+
+ if(limit_size > preferred_size)
+ return return_type(static_cast<void*>(0), false);
+
+ //Number of units to request (including block_ctrl header)
+ std::size_t preferred_units = priv_get_total_units(preferred_size);
+
+ //Number of units to request (including block_ctrl header)
+ std::size_t limit_units = priv_get_total_units(limit_size);
+
+ //Expand in place
+ if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
+ void *ret = priv_expand_both_sides
+ (command, limit_size, preferred_size, received_size, reuse_ptr, true, backwards_multiple);
+ if(ret)
+ return return_type(ret, true);
+ }
+
+ if(command & allocate_new){
+ size_block_ctrl_compare comp;
+ imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp));
+
+ if(it != m_header.m_imultiset.end()){
+ return return_type(this->priv_check_and_allocate
+ (preferred_units, detail::get_pointer(&*it), received_size), false);
+ }
+
+ if(it != m_header.m_imultiset.begin()&&
+ (--it)->m_size >= limit_units){
+ return return_type(this->priv_check_and_allocate
+ (it->m_size, detail::get_pointer(&*it), received_size), false);
+ }
+ }
+
+
+ //Now try to expand both sides with min size
+ if(reuse_ptr && (command & (expand_fwd | expand_bwd))){
+ return return_type(priv_expand_both_sides
+ (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true);
+ }
+
+ return return_type(static_cast<void*>(0), false);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline
+typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *
+ rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_get_block(const void *ptr)
+{
+ return const_cast<block_ctrl*>
+ (reinterpret_cast<const block_ctrl*>
+ (reinterpret_cast<const char*>(ptr) - AllocatedCtrlBytes));
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline
+void *rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_get_user_buffer(const typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *block)
+{ return const_cast<char*>(reinterpret_cast<const char*>(block) + AllocatedCtrlBytes); }
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+inline
+std::size_t rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_get_total_units(std::size_t userbytes)
+{
+ if(userbytes < UsableByPreviousChunk)
+ userbytes = UsableByPreviousChunk;
+ std::size_t units = detail::get_rounded_size(userbytes - UsableByPreviousChunk, Alignment)/Alignment + AllocatedCtrlUnits;
+ if(units < BlockCtrlUnits) units = BlockCtrlUnits;
+ return units;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::
+ priv_expand (void *ptr
+ ,const std::size_t min_size
+ ,const std::size_t preferred_size
+ ,std::size_t &received_size)
+{
+ //Obtain the real size of the block
+ block_ctrl *block = priv_get_block(ptr);
+ std::size_t old_block_units = block->m_size;
+
+ //The block must be marked as allocated and the sizes must be equal
+ assert(priv_is_allocated_block(block));
+ //assert(old_block_units == priv_tail_size(block));
+
+ //Put this to a safe value
+ received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
+ if(received_size >= preferred_size || received_size >= min_size)
+ return true;
+
+ //Now translate it to Alignment units
+ const std::size_t min_user_units = algo_impl_t::ceil_units(min_size - UsableByPreviousChunk);
+ const std::size_t preferred_user_units = algo_impl_t::ceil_units(preferred_size - UsableByPreviousChunk);
+
+ //Some parameter checks
+ assert(min_user_units <= preferred_user_units);
+
+ block_ctrl *next_block;
+
+ if(priv_is_allocated_block(next_block = priv_next_block(block))){
+ return received_size >= min_size ? true : false;
+ }
+ algo_impl_t::assert_alignment(next_block);
+
+ //Is "block" + "next_block" big enough?
+ const std::size_t merged_units = old_block_units + next_block->m_size;
+
+ //Now get the expansion size
+ const std::size_t merged_user_units = merged_units - AllocatedCtrlUnits;
+
+ if(merged_user_units < min_user_units){
+ received_size = merged_units*Alignment - UsableByPreviousChunk;
+ return false;
+ }
+
+ //Now get the maximum size the user can allocate
+ std::size_t intended_user_units = (merged_user_units < preferred_user_units) ?
+ merged_user_units : preferred_user_units;
+
+ //These are total units of the merged block (supposing the next block can be split)
+ const std::size_t intended_units = AllocatedCtrlUnits + intended_user_units;
+
+ //Check if we can split the next one in two parts
+ if((merged_units - intended_units) >= BlockCtrlUnits){
+ //This block is bigger than needed, split it in
+ //two blocks, the first one will be merged and
+ //the second's size will be the remaining space
+ assert(next_block->m_size == priv_next_block(next_block)->m_prev_size);
+ const std::size_t rem_units = merged_units - intended_units;
+
+ //Check if we we need to update the old next block in the free blocks tree
+ //If the new size fulfills tree invariants, we just need to replace the node
+ //(the block start has been displaced), otherwise erase() + insert().
+ //
+ //This fixup must be done in two parts, because the new next block might
+ //overwrite the tree hook of the old next block. So we first erase the
+ //old if needed and we'll insert the new one after creating the new next
+ imultiset_iterator old_next_block_it(Imultiset::s_iterator_to(*next_block));
+ const bool size_invariants_broken =
+ (next_block->m_size - rem_units ) < BlockCtrlUnits ||
+ (old_next_block_it != m_header.m_imultiset.begin() &&
+ (--imultiset_iterator(old_next_block_it))->m_size > rem_units);
+ if(size_invariants_broken){
+ m_header.m_imultiset.erase(old_next_block_it);
+ }
+ //This is the remaining block
+ block_ctrl *rem_block = new(reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(block) + intended_units*Alignment))block_ctrl;
+ rem_block->m_size = rem_units;
+ algo_impl_t::assert_alignment(rem_block);
+ assert(rem_block->m_size >= BlockCtrlUnits);
+ priv_mark_as_free_block(rem_block);
+
+ //Now the second part of the fixup
+ if(size_invariants_broken)
+ m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block);
+ else
+ m_header.m_imultiset.replace_node(old_next_block_it, *rem_block);
+
+ //Write the new length
+ block->m_size = intended_user_units + AllocatedCtrlUnits;
+ assert(block->m_size >= BlockCtrlUnits);
+ m_header.m_allocated += (intended_units - old_block_units)*Alignment;
+ }
+ //There is no free space to create a new node: just merge both blocks
+ else{
+ //Now we have to update the data in the tree
+ m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block));
+
+ //Write the new length
+ block->m_size = merged_units;
+ assert(block->m_size >= BlockCtrlUnits);
+ m_header.m_allocated += (merged_units - old_block_units)*Alignment;
+ }
+ priv_mark_as_allocated_block(block);
+ received_size = (block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
+ return true;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *
+ rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_prev_block
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *ptr)
+{
+ assert(!ptr->m_prev_allocated);
+ return reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(ptr) - ptr->m_prev_size*Alignment);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_is_prev_allocated
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *ptr)
+{
+ if(ptr->m_prev_allocated){
+ return true;
+ }
+ else{
+ block_ctrl *prev = priv_prev_block(ptr);
+ (void)prev;
+ assert(!priv_is_allocated_block(prev));
+ return false;
+ }
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *
+ rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_end_block
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *first_segment_block)
+{
+ assert(first_segment_block->m_prev_allocated);
+ block_ctrl *end_block = reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(first_segment_block) - first_segment_block->m_prev_size*Alignment);
+ (void)end_block;
+ assert(priv_is_allocated_block(end_block));
+ assert(end_block > first_segment_block);
+ return end_block;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *
+ rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_next_block
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *ptr)
+{
+ return reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(ptr) + ptr->m_size*Alignment);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+bool rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_is_allocated_block
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *block)
+{
+ bool allocated = block->m_allocated != 0;
+ block_ctrl *next_block = reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(block) + block->m_size*Alignment);
+ bool next_block_prev_allocated = next_block->m_prev_allocated != 0;
+ (void)next_block_prev_allocated;
+ assert(allocated == next_block_prev_allocated);
+ return allocated;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_mark_as_allocated_block
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *block)
+{
+ //assert(!priv_is_allocated_block(block));
+ block->m_allocated = 1;
+ reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(block)+ block->m_size*Alignment)->m_prev_allocated = 1;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_mark_as_free_block
+ (typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl *block)
+{
+ block->m_allocated = 0;
+ reinterpret_cast<block_ctrl *>
+ (reinterpret_cast<char*>(block) + block->m_size*Alignment)->m_prev_allocated = 0;
+ //assert(!priv_is_allocated_block(ptr));
+ priv_next_block(block)->m_prev_size = block->m_size;
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment> inline
+void* rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_check_and_allocate
+ (std::size_t nunits
+ ,typename rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::block_ctrl* block
+ ,std::size_t &received_size)
+{
+ std::size_t upper_nunits = nunits + BlockCtrlUnits;
+ imultiset_iterator it_old = Imultiset::s_iterator_to(*block);
+ algo_impl_t::assert_alignment(block);
+
+ if (block->m_size >= upper_nunits){
+ //This block is bigger than needed, split it in
+ //two blocks, the first's size will be "units" and
+ //the second's size "block->m_size-units"
+ std::size_t block_old_size = block->m_size;
+ block->m_size = nunits;
+ assert(block->m_size >= BlockCtrlUnits);
+
+ //This is the remaining block
+ block_ctrl *rem_block = new(reinterpret_cast<block_ctrl*>
+ (reinterpret_cast<char*>(block) + Alignment*nunits))block_ctrl;
+ algo_impl_t::assert_alignment(rem_block);
+ rem_block->m_size = block_old_size - nunits;
+ assert(rem_block->m_size >= BlockCtrlUnits);
+ priv_mark_as_free_block(rem_block);
+
+ imultiset_iterator it_hint;
+ if(it_old == m_header.m_imultiset.begin()
+ || (--imultiset_iterator(it_old))->m_size < rem_block->m_size){
+ //option a: slow but secure
+ //m_header.m_imultiset.insert(m_header.m_imultiset.erase(it_old), *rem_block);
+ //option b: Construct an empty node and swap
+ //Imultiset::init_node(*rem_block);
+ //block->swap_nodes(*rem_block);
+ //option c: replace the node directly
+ m_header.m_imultiset.replace_node(Imultiset::s_iterator_to(*it_old), *rem_block);
+ }
+ else{
+ //Now we have to update the data in the tree
+ m_header.m_imultiset.erase(it_old);
+ m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block);
+ }
+
+ }
+ else if (block->m_size >= nunits){
+ m_header.m_imultiset.erase(it_old);
+ }
+ else{
+ assert(0);
+ return 0;
+ }
+ //We need block_ctrl for deallocation stuff, so
+ //return memory user can overwrite
+ m_header.m_allocated += block->m_size*Alignment;
+ received_size = (block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
+
+ //Mark the block as allocated
+ priv_mark_as_allocated_block(block);
+
+ //Clear the memory occupied by the tree hook, since this won't be
+ //cleared with zero_free_memory
+ TreeHook *t = static_cast<TreeHook*>(block);
+ std::memset(t, 0, sizeof(*t));
+ this->priv_next_block(block)->m_prev_size = 0;
+ return priv_get_user_buffer(block);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::deallocate(void* addr)
+{
+ if(!addr) return;
+ //-----------------------
+ boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
+ //-----------------------
+ return this->priv_deallocate(addr);
+}
+
+template<class MutexFamily, class VoidPointer, std::size_t MemAlignment>
+void rbtree_best_fit<MutexFamily, VoidPointer, MemAlignment>::priv_deallocate(void* addr)
+{
+ if(!addr) return;
+
+ block_ctrl *block = priv_get_block(addr);
+
+ //The blocks must be marked as allocated and the sizes must be equal
+ assert(priv_is_allocated_block(block));
+// assert(block->m_size == priv_tail_size(block));
+
+ //Check if alignment and block size are right
+ algo_impl_t::assert_alignment(addr);
+
+ std::size_t block_old_size = Alignment*block->m_size;
+ assert(m_header.m_allocated >= block_old_size);
+
+ //Update used memory count
+ m_header.m_allocated -= block_old_size;
+
+ //The block to insert in the tree
+ block_ctrl *block_to_insert = block;
+
+ //Get the next block
+ block_ctrl *next_block = priv_next_block(block);
+ bool merge_with_prev = !priv_is_prev_allocated(block);
+ bool merge_with_next = !priv_is_allocated_block(next_block);
+
+ //Merge logic. First just update block sizes, then fix free blocks tree
+ if(merge_with_prev || merge_with_next){
+ //Merge if the previous is free
+ if(merge_with_prev){
+ //Get the previous block
+ block_ctrl *prev_block = priv_prev_block(block);
+ prev_block->m_size += block->m_size;
+ assert(prev_block->m_size >= BlockCtrlUnits);
+ block_to_insert = prev_block;
+ }
+ //Merge if the next is free
+ if(merge_with_next){
+ block_to_insert->m_size += next_block->m_size;
+ assert(block_to_insert->m_size >= BlockCtrlUnits);
+ if(merge_with_prev)
+ m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block));
+ }
+
+ bool only_merge_next = !merge_with_prev && merge_with_next;
+ imultiset_iterator free_block_to_check_it
+ (Imultiset::s_iterator_to(only_merge_next ? *next_block : *block_to_insert));
+ imultiset_iterator was_bigger_it(free_block_to_check_it);
+
+ //Now try to shortcut erasure + insertion (O(log(N))) with
+ //a O(1) operation if merging does not alter tree positions
+ if(++was_bigger_it != m_header.m_imultiset.end() &&
+ block_to_insert->m_size > was_bigger_it->m_size ){
+ m_header.m_imultiset.erase(free_block_to_check_it);
+ m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert);
+ }
+ else if(only_merge_next){
+ m_header.m_imultiset.replace_node(free_block_to_check_it, *block_to_insert);
+ }
+ }
+ else{
+ m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert);
+ }
+ priv_mark_as_free_block(block_to_insert);
+}
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP
Added: sandbox/boost/interprocess/mem_algo/simple_seq_fit.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/mem_algo/simple_seq_fit.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,56 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_SIMPLE_SEQ_FIT_HPP
+#define BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
+
+//!\file
+//!Describes sequential fit algorithm used to allocate objects in shared memory.
+
+namespace boost {
+namespace interprocess {
+
+//!This class implements the simple sequential fit algorithm with a simply
+//!linked list of free buffers.
+template<class MutexFamily, class VoidPointer>
+class simple_seq_fit
+ : public detail::simple_seq_fit_impl<MutexFamily, VoidPointer>
+{
+ /// @cond
+ typedef detail::simple_seq_fit_impl<MutexFamily, VoidPointer> base_t;
+ /// @endcond
+
+ public:
+ //!Constructor. "size" is the total size of the managed memory segment,
+ //!"extra_hdr_bytes" indicates the extra bytes beginning in the sizeof(simple_seq_fit)
+ //!offset that the allocator should not use at all.*/
+ simple_seq_fit (std::size_t size, std::size_t extra_hdr_bytes)
+ : base_t(size, extra_hdr_bytes){}
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_SIMPLE_SEQ_FIT_HPP
+
Added: sandbox/boost/interprocess/offset_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/offset_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,458 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_OFFSET_PTR_HPP
+#define BOOST_OFFSET_PTR_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/cast_tags.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/assert.hpp>
+#include <ostream>
+#include <istream>
+#include <iterator>
+
+//!\file
+//!Describes a smart pointer that stores the offset between this pointer and
+//!target pointee, called offset_ptr.
+
+namespace boost {
+
+//Predeclarations
+template <class T>
+struct has_trivial_constructor;
+
+template <class T>
+struct has_trivial_destructor;
+
+namespace interprocess {
+
+//!A smart pointer that stores the offset between between the pointer and the
+//!the object it points. This allows offset allows special properties, since
+//!the pointer is independent from the address address of the pointee, if the
+//!pointer and the pointee are still separated by the same offset. This feature
+//!converts offset_ptr in a smart pointer that can be placed in shared memory and
+//!memory mapped files mapped in different addresses in every process.
+template <class PointedType>
+class offset_ptr
+{
+ /// @cond
+ typedef offset_ptr<PointedType> self_t;
+
+ void unspecified_bool_type_func() const {}
+ typedef void (self_t::*unspecified_bool_type)() const;
+
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0
+ #endif
+ void set_offset(const volatile void *ptr)
+ { set_offset(const_cast<const void*>(ptr)); }
+
+ void set_offset(const void *ptr)
+ {
+ const char *p = static_cast<const char*>(ptr);
+ //offset == 1 && ptr != 0 is not legal for this pointer
+ if(!ptr){
+ m_offset = 1;
+ }
+ else{
+ m_offset = p - reinterpret_cast<const char*>(this);
+ BOOST_ASSERT(m_offset != 1);
+ }
+ }
+
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0
+ #endif
+ void* get_pointer() const
+ { return (m_offset == 1) ? 0 : (const_cast<char*>(reinterpret_cast<const char*>(this)) + m_offset); }
+
+ void inc_offset(std::ptrdiff_t bytes)
+ { m_offset += bytes; }
+
+ void dec_offset(std::ptrdiff_t bytes)
+ { m_offset -= bytes; }
+
+ std::ptrdiff_t m_offset; //Distance between this object and pointed address
+ /// @endcond
+
+ public:
+ typedef PointedType * pointer;
+ typedef typename detail::
+ add_reference<PointedType>::type reference;
+ typedef PointedType value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ public: //Public Functions
+
+ //!Constructor from raw pointer (allows "0" pointer conversion).
+ //!Never throws.
+ offset_ptr(pointer ptr = 0) { this->set_offset(ptr); }
+
+ //!Constructor from other pointer.
+ //!Never throws.
+ template <class T>
+ offset_ptr(T *ptr)
+ { pointer p (ptr); (void)p; this->set_offset(p); }
+
+ //!Constructor from other offset_ptr
+ //!Never throws.
+ offset_ptr(const offset_ptr& ptr)
+ { this->set_offset(ptr.get()); }
+
+ //!Constructor from other offset_ptr. If pointers of pointee types are
+ //!convertible, offset_ptrs will be convertibles. Never throws.
+ template<class T2>
+ offset_ptr(const offset_ptr<T2> &ptr)
+ { pointer p(ptr.get()); (void)p; this->set_offset(p); }
+
+ //!Emulates static_cast operator.
+ //!Never throws.
+ template<class Y>
+ offset_ptr(const offset_ptr<Y> & r, detail::static_cast_tag)
+ { this->set_offset(static_cast<PointedType*>(r.get())); }
+
+ //!Emulates const_cast operator.
+ //!Never throws.
+ template<class Y>
+ offset_ptr(const offset_ptr<Y> & r, detail::const_cast_tag)
+ { this->set_offset(const_cast<PointedType*>(r.get())); }
+
+ //!Emulates dynamic_cast operator.
+ //!Never throws.
+ template<class Y>
+ offset_ptr(const offset_ptr<Y> & r, detail::dynamic_cast_tag)
+ { this->set_offset(dynamic_cast<PointedType*>(r.get())); }
+
+ //!Emulates reinterpret_cast operator.
+ //!Never throws.
+ template<class Y>
+ offset_ptr(const offset_ptr<Y> & r, detail::reinterpret_cast_tag)
+ { this->set_offset(reinterpret_cast<PointedType*>(r.get())); }
+
+ //!Obtains raw pointer from offset.
+ //!Never throws.
+ pointer get()const
+ { return static_cast<pointer>(this->get_pointer()); }
+
+ std::ptrdiff_t get_offset()
+ { return m_offset; }
+
+ //!Pointer-like -> operator. It can return 0 pointer.
+ //!Never throws.
+ pointer operator->() const
+ { return this->get(); }
+
+ //!Dereferencing operator, if it is a null offset_ptr behavior
+ //! is undefined. Never throws.
+ reference operator* () const
+ {
+ pointer p = this->get();
+ reference r = *p;
+ return r;
+ }
+
+ //!Indexing operator.
+ //!Never throws.
+ reference operator[](std::ptrdiff_t idx) const
+ { return this->get()[idx]; }
+
+ //!Assignment from pointer (saves extra conversion).
+ //!Never throws.
+ offset_ptr& operator= (pointer from)
+ { this->set_offset(from); return *this; }
+
+ //!Assignment from other offset_ptr.
+ //!Never throws.
+ offset_ptr& operator= (const offset_ptr & pt)
+ { pointer p(pt.get()); (void)p; this->set_offset(p); return *this; }
+
+ //!Assignment from related offset_ptr. If pointers of pointee types
+ //! are assignable, offset_ptrs will be assignable. Never throws.
+ template <class T2>
+ offset_ptr& operator= (const offset_ptr<T2> & pt)
+ { pointer p(pt.get()); this->set_offset(p); return *this; }
+
+ //!offset_ptr + std::ptrdiff_t.
+ //!Never throws.
+ offset_ptr operator+ (std::ptrdiff_t offset) const
+ { return offset_ptr(this->get()+offset); }
+
+ //!offset_ptr - std::ptrdiff_t.
+ //!Never throws.
+ offset_ptr operator- (std::ptrdiff_t offset) const
+ { return offset_ptr(this->get()-offset); }
+
+ //!offset_ptr += std::ptrdiff_t.
+ //!Never throws.
+ offset_ptr &operator+= (std::ptrdiff_t offset)
+ { this->inc_offset(offset * sizeof (PointedType)); return *this; }
+
+ //!offset_ptr -= std::ptrdiff_t.
+ //!Never throws.
+ offset_ptr &operator-= (std::ptrdiff_t offset)
+ { this->dec_offset(offset * sizeof (PointedType)); return *this; }
+
+ //!++offset_ptr.
+ //!Never throws.
+ offset_ptr& operator++ (void)
+ { this->inc_offset(sizeof (PointedType)); return *this; }
+
+ //!offset_ptr++.
+ //!Never throws.
+ offset_ptr operator++ (int)
+ { offset_ptr temp(*this); ++*this; return temp; }
+
+ //!--offset_ptr.
+ //!Never throws.
+ offset_ptr& operator-- (void)
+ { this->dec_offset(sizeof (PointedType)); return *this; }
+
+ //!offset_ptr--.
+ //!Never throws.
+ offset_ptr operator-- (int)
+ { offset_ptr temp(*this); --*this; return temp; }
+
+ //!safe bool conversion operator.
+ //!Never throws.
+ operator unspecified_bool_type() const
+ { return this->get()? &self_t::unspecified_bool_type_func : 0; }
+
+ //!Not operator. Not needed in theory, but improves portability.
+ //!Never throws
+ bool operator! () const
+ { return this->get() == 0; }
+/*
+ friend void swap (offset_ptr &pt, offset_ptr &pt2)
+ {
+ value_type *ptr = pt.get();
+ pt = pt2;
+ pt2 = ptr;
+ }
+*/
+};
+
+//!offset_ptr<T1> == offset_ptr<T2>.
+//!Never throws.
+template<class T1, class T2>
+inline bool operator== (const offset_ptr<T1> &pt1,
+ const offset_ptr<T2> &pt2)
+{ return pt1.get() == pt2.get(); }
+
+//!offset_ptr<T1> != offset_ptr<T2>.
+//!Never throws.
+template<class T1, class T2>
+inline bool operator!= (const offset_ptr<T1> &pt1,
+ const offset_ptr<T2> &pt2)
+{ return pt1.get() != pt2.get(); }
+
+//!offset_ptr<T1> < offset_ptr<T2>.
+//!Never throws.
+template<class T1, class T2>
+inline bool operator< (const offset_ptr<T1> &pt1,
+ const offset_ptr<T2> &pt2)
+{ return pt1.get() < pt2.get(); }
+
+//!offset_ptr<T1> <= offset_ptr<T2>.
+//!Never throws.
+template<class T1, class T2>
+inline bool operator<= (const offset_ptr<T1> &pt1,
+ const offset_ptr<T2> &pt2)
+{ return pt1.get() <= pt2.get(); }
+
+//!offset_ptr<T1> > offset_ptr<T2>.
+//!Never throws.
+template<class T1, class T2>
+inline bool operator> (const offset_ptr<T1> &pt1,
+ const offset_ptr<T2> &pt2)
+{ return pt1.get() > pt2.get(); }
+
+//!offset_ptr<T1> >= offset_ptr<T2>.
+//!Never throws.
+template<class T1, class T2>
+inline bool operator>= (const offset_ptr<T1> &pt1,
+ const offset_ptr<T2> &pt2)
+{ return pt1.get() >= pt2.get(); }
+
+//!operator<<
+//!for offset ptr
+template<class E, class T, class Y>
+inline std::basic_ostream<E, T> & operator<<
+ (std::basic_ostream<E, T> & os, offset_ptr<Y> const & p)
+{ return os << p.get_offset(); }
+
+//!operator>>
+//!for offset ptr
+template<class E, class T, class Y>
+inline std::basic_istream<E, T> & operator>>
+ (std::basic_istream<E, T> & is, offset_ptr<Y> & p)
+{ return is >> p.get_offset(); }
+
+//!std::ptrdiff_t + offset_ptr
+//!operation
+template<class T>
+inline offset_ptr<T> operator+(std::ptrdiff_t diff, const offset_ptr<T>& right)
+{ return right + diff; }
+
+//!offset_ptr - offset_ptr
+//!operation
+template<class T, class T2>
+inline std::ptrdiff_t operator- (const offset_ptr<T> &pt, const offset_ptr<T2> &pt2)
+{ return pt.get()- pt2.get(); }
+
+//!swap specialization
+//!for offset_ptr
+template<class T>
+inline void swap (boost::interprocess::offset_ptr<T> &pt,
+ boost::interprocess::offset_ptr<T> &pt2)
+{
+ typename offset_ptr<T>::value_type *ptr = pt.get();
+ pt = pt2;
+ pt2 = ptr;
+}
+
+//!Simulation of static_cast between pointers. Never throws.
+template<class T, class U>
+inline boost::interprocess::offset_ptr<T>
+ static_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
+{
+ return boost::interprocess::offset_ptr<T>
+ (r, boost::interprocess::detail::static_cast_tag());
+}
+
+//!Simulation of const_cast between pointers. Never throws.
+template<class T, class U>
+inline boost::interprocess::offset_ptr<T>
+ const_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
+{
+ return boost::interprocess::offset_ptr<T>
+ (r, boost::interprocess::detail::const_cast_tag());
+}
+
+//!Simulation of dynamic_cast between pointers. Never throws.
+template<class T, class U>
+inline boost::interprocess::offset_ptr<T>
+ dynamic_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
+{
+ return boost::interprocess::offset_ptr<T>
+ (r, boost::interprocess::detail::dynamic_cast_tag());
+}
+
+//!Simulation of reinterpret_cast between pointers. Never throws.
+template<class T, class U>
+inline boost::interprocess::offset_ptr<T>
+ reinterpret_pointer_cast(boost::interprocess::offset_ptr<U> const & r)
+{
+ return boost::interprocess::offset_ptr<T>
+ (r, boost::interprocess::detail::reinterpret_cast_tag());
+}
+
+} //namespace interprocess {
+
+/// @cond
+
+//!has_trivial_constructor<> == true_type specialization for optimizations
+template <class T>
+struct has_trivial_constructor< boost::interprocess::offset_ptr<T> >
+{
+ enum { value = true };
+};
+
+///has_trivial_destructor<> == true_type specialization for optimizations
+template <class T>
+struct has_trivial_destructor< boost::interprocess::offset_ptr<T> >
+{
+ enum { value = true };
+};
+
+//#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
+namespace interprocess {
+//#endif
+//!get_pointer() enables boost::mem_fn to recognize offset_ptr.
+//!Never throws.
+template<class T>
+inline T * get_pointer(boost::interprocess::offset_ptr<T> const & p)
+{ return p.get(); }
+//#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
+} //namespace interprocess
+//#endif
+
+/// @endcond
+} //namespace boost {
+
+/// @cond
+
+namespace boost{
+
+//This is to support embedding a bit in the pointer
+//for intrusive containers, saving space
+namespace intrusive {
+
+//Predeclaration to avoid including header
+template<class VoidPointer, std::size_t N>
+struct max_pointer_plus_bits;
+
+template<std::size_t Alignment>
+struct max_pointer_plus_bits<boost::interprocess::offset_ptr<void>, Alignment>
+{
+ //The offset ptr can embed one bit less than the alignment since it
+ //uses offset == 1 to store the null pointer.
+ static const std::size_t value = ::boost::interprocess::detail::ls_zeros<Alignment>::value - 1;
+};
+
+//Predeclaration
+template<class Pointer, std::size_t NumBits>
+struct pointer_plus_bits;
+
+template<class T, std::size_t NumBits>
+struct pointer_plus_bits<boost::interprocess::offset_ptr<T>, NumBits>
+{
+ typedef boost::interprocess::offset_ptr<T> pointer;
+ //Bits are stored in the lower bits of the pointer except the LSB,
+ //because this bit is used to represent the null pointer.
+ static const std::size_t Mask = ((std::size_t(1) << NumBits)-1)<<1u;
+
+ static pointer get_pointer(const pointer &n)
+ { return reinterpret_cast<T*>(std::size_t(n.get()) & ~std::size_t(Mask)); }
+
+ static void set_pointer(pointer &n, pointer p)
+ {
+ std::size_t pint = std::size_t(p.get());
+ assert(0 == (std::size_t(pint) & Mask));
+ n = reinterpret_cast<T*>(pint | (std::size_t(n.get()) & std::size_t(Mask)));
+ }
+
+ static std::size_t get_bits(const pointer &n)
+ { return(std::size_t(n.get()) & std::size_t(Mask)) >> 1u; }
+
+ static void set_bits(pointer &n, std::size_t b)
+ {
+ assert(b < (std::size_t(1) << NumBits));
+ n = reinterpret_cast<T*>(std::size_t(get_pointer(n).get()) | (b << 1u));
+ }
+};
+
+} //namespace intrusive
+} //namespace boost{
+/// @endcond
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_OFFSET_PTR_HPP
+
Added: sandbox/boost/interprocess/segment_manager.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/segment_manager.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,1347 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_HPP
+#define BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+
+#include <boost/interprocess/detail/iterators.hpp>
+
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/segment_manager_helper.hpp>
+#include <boost/interprocess/detail/named_proxy.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/offset_ptr.hpp>
+#include <boost/interprocess/indexes/iset_index.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/allocators/allocator.hpp>
+#include <boost/interprocess/smart_ptr/deleter.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <cstddef> //std::size_t
+#include <string> //char_traits
+#include <new> //std::nothrow
+#include <utility> //std::pair
+#ifndef BOOST_NO_EXCEPTIONS
+#include <exception>
+#endif
+
+//!\file
+//!Describes the object placed in a memory segment that provides
+//!named object allocation capabilities for single-segment and
+//!multi-segment allocations.
+
+namespace boost{
+namespace interprocess{
+
+//!This object is the public base class of segment manager.
+//!This class only depends on the memory allocation algorithm
+//!and implements all the allocation features not related
+//!to named or unique objects.
+//!
+//!Storing a reference to segment_manager forces
+//!the holder class to be dependent on index types and character types.
+//!When such dependence is not desirable and only anonymous and raw
+//!allocations are needed, segment_manager_base is the correct answer.
+template<class MemoryAlgorithm>
+class segment_manager_base
+ : private MemoryAlgorithm
+{
+ public:
+ typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
+ typedef typename MemoryAlgorithm::void_pointer void_pointer;
+ typedef typename MemoryAlgorithm::mutex_family mutex_family;
+ typedef MemoryAlgorithm memory_algorithm;
+
+ /// @cond
+
+ //Experimental. Don't use
+ typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
+
+ /// @endcond
+
+ //!This constant indicates the payload size
+ //!associated with each allocation of the memory algorithm
+ static const std::size_t PayloadPerAllocation = MemoryAlgorithm::PayloadPerAllocation;
+
+ //!Constructor of the segment_manager_base
+ //!
+ //!"size" is the size of the memory segment where
+ //!the basic segment manager is being constructed.
+ //!
+ //!"reserved_bytes" is the number of bytes
+ //!after the end of the memory algorithm object itself
+ //!that the memory algorithm will exclude from
+ //!dynamic allocation
+ //!
+ //!Can throw
+ segment_manager_base(std::size_t size, std::size_t reserved_bytes)
+ : MemoryAlgorithm(size, reserved_bytes)
+ {
+ assert((sizeof(segment_manager_base<MemoryAlgorithm>) == sizeof(MemoryAlgorithm)));
+ }
+
+ //!Returns the size of the memory
+ //!segment
+ std::size_t get_size() const
+ { return MemoryAlgorithm::get_size(); }
+
+ //!Returns the number of free bytes of the memory
+ //!segment
+ std::size_t get_free_memory() const
+ { return MemoryAlgorithm::get_free_memory(); }
+
+ //!Obtains the minimum size needed by
+ //!the segment manager
+ static std::size_t get_min_size (std::size_t size)
+ { return MemoryAlgorithm::get_min_size(size); }
+
+ //!Allocates nbytes bytes. This function is only used in
+ //!single-segment management. Never throws
+ void * allocate (std::size_t nbytes, std::nothrow_t)
+ { return MemoryAlgorithm::allocate(nbytes); }
+
+ /// @cond
+
+ //Experimental. Dont' use.
+ //!Allocates n_elements of
+ //!elem_size bytes. Throws bad_alloc on failure.
+ multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements)
+ {
+ multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements));
+ if(mem.empty()) throw bad_alloc();
+ return boost::move(mem);
+ }
+
+ //!Allocates n_elements, each one of
+ //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure.
+ multiallocation_chain allocate_many
+ (const std::size_t *element_lenghts, std::size_t n_elements, std::size_t sizeof_element = 1)
+ {
+ multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element));
+ if(mem.empty()) throw bad_alloc();
+ return boost::move(mem);
+ }
+
+ //!Allocates n_elements of
+ //!elem_size bytes. Returns a default constructed iterator on failure.
+ multiallocation_chain allocate_many
+ (std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t)
+ { return MemoryAlgorithm::allocate_many(elem_bytes, num_elements); }
+
+ //!Allocates n_elements, each one of
+ //!element_lenghts[i]*sizeof_element bytes.
+ //!Returns a default constructed iterator on failure.
+ multiallocation_chain allocate_many
+ (const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t)
+ { return MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element); }
+
+ //!Deallocates elements pointed by the
+ //!multiallocation iterator range.
+ void deallocate_many(multiallocation_chain chain)
+ { MemoryAlgorithm::deallocate_many(boost::move(chain)); }
+
+ /// @endcond
+
+ //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc
+ //!on failure
+ void * allocate(std::size_t nbytes)
+ {
+ void * ret = MemoryAlgorithm::allocate(nbytes);
+ if(!ret)
+ throw bad_alloc();
+ return ret;
+ }
+
+ //!Allocates nbytes bytes. This function is only used in
+ //!single-segment management. Never throws
+ void * allocate_aligned (std::size_t nbytes, std::size_t alignment, std::nothrow_t)
+ { return MemoryAlgorithm::allocate_aligned(nbytes, alignment); }
+
+ //!Allocates nbytes bytes. This function is only used in
+ //!single-segment management. Throws bad_alloc when fails
+ void * allocate_aligned(std::size_t nbytes, std::size_t alignment)
+ {
+ void * ret = MemoryAlgorithm::allocate_aligned(nbytes, alignment);
+ if(!ret)
+ throw bad_alloc();
+ return ret;
+ }
+
+ template<class T>
+ std::pair<T *, bool>
+ allocation_command (allocation_type command, std::size_t limit_size,
+ std::size_t preferred_size,std::size_t &received_size,
+ T *reuse_ptr = 0)
+ {
+ std::pair<T *, bool> ret = MemoryAlgorithm::allocation_command
+ ( command | nothrow_allocation, limit_size, preferred_size, received_size
+ , reuse_ptr);
+ if(!(command & nothrow_allocation) && !ret.first)
+ throw bad_alloc();
+ return ret;
+ }
+
+ std::pair<void *, bool>
+ raw_allocation_command (allocation_type command, std::size_t limit_objects,
+ std::size_t preferred_objects,std::size_t &received_objects,
+ void *reuse_ptr = 0, std::size_t sizeof_object = 1)
+ {
+ std::pair<void *, bool> ret = MemoryAlgorithm::raw_allocation_command
+ ( command | nothrow_allocation, limit_objects, preferred_objects, received_objects
+ , reuse_ptr, sizeof_object);
+ if(!(command & nothrow_allocation) && !ret.first)
+ throw bad_alloc();
+ return ret;
+ }
+
+ //!Deallocates the bytes allocated with allocate/allocate_many()
+ //!pointed by addr
+ void deallocate (void *addr)
+ { MemoryAlgorithm::deallocate(addr); }
+
+ //!Increases managed memory in extra_size bytes more. This only works
+ //!with single-segment management.
+ void grow(std::size_t extra_size)
+ { MemoryAlgorithm::grow(extra_size); }
+
+ //!Decreases managed memory to the minimum. This only works
+ //!with single-segment management.
+ void shrink_to_fit()
+ { MemoryAlgorithm::shrink_to_fit(); }
+
+ //!Returns the result of "all_memory_deallocated()" function
+ //!of the used memory algorithm
+ bool all_memory_deallocated()
+ { return MemoryAlgorithm::all_memory_deallocated(); }
+
+ //!Returns the result of "check_sanity()" function
+ //!of the used memory algorithm
+ bool check_sanity()
+ { return MemoryAlgorithm::check_sanity(); }
+
+ //!Writes to zero free memory (memory not yet allocated)
+ //!of the memory algorithm
+ void zero_free_memory()
+ { MemoryAlgorithm::zero_free_memory(); }
+
+ //!Returns the size of the buffer previously allocated pointed by ptr
+ std::size_t size(const void *ptr) const
+ { return MemoryAlgorithm::size(ptr); }
+
+ /// @cond
+ protected:
+ void * prot_anonymous_construct
+ (std::size_t num, bool dothrow, detail::in_place_interface &table)
+ {
+ typedef detail::block_header block_header_t;
+ block_header_t block_info ( table.size*num
+ , table.alignment
+ , anonymous_type
+ , 1
+ , 0);
+
+ //Allocate memory
+ void *ptr_struct = this->allocate(block_info.total_size(), std::nothrow_t());
+
+ //Check if there is enough memory
+ if(!ptr_struct){
+ if(dothrow){
+ throw bad_alloc();
+ }
+ else{
+ return 0;
+ }
+ }
+
+ //Build scoped ptr to avoid leaks with constructor exception
+ detail::mem_algo_deallocator<MemoryAlgorithm> mem(ptr_struct, *this);
+
+ //Now construct the header
+ block_header_t * hdr = new(ptr_struct) block_header_t(block_info);
+ void *ptr = 0; //avoid gcc warning
+ ptr = hdr->value();
+
+ //Now call constructors
+ detail::array_construct(ptr, num, table);
+
+ //All constructors successful, we don't want erase memory
+ mem.release();
+ return ptr;
+ }
+
+ //!Calls the destructor and makes an anonymous deallocate
+ void prot_anonymous_destroy(const void *object, detail::in_place_interface &table)
+ {
+
+ //Get control data from associated with this object
+ typedef detail::block_header block_header_t;
+ block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment);
+
+ //-------------------------------
+ //scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+
+ if(ctrl_data->allocation_type() != anonymous_type){
+ //This is not an anonymous object, the pointer is wrong!
+ assert(0);
+ }
+
+ //Call destructors and free memory
+ //Build scoped ptr to avoid leaks with destructor exception
+ std::size_t destroyed = 0;
+ table.destroy_n(const_cast<void*>(object), ctrl_data->m_value_bytes/table.size, destroyed);
+ this->deallocate(ctrl_data);
+ }
+ /// @endcond
+};
+
+//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;
+
+//!This object is placed in the beginning of memory segment and
+//!implements the allocation (named or anonymous) of portions
+//!of the segment. This object contains two indexes that
+//!maintain an association between a name and a portion of the segment.
+//!
+//!The first index contains the mappings for normal named objects using the
+//!char type specified in the template parameter.
+//!
+//!The second index contains the association for unique instances. The key will
+//!be the const char * returned from type_info.name() function for the unique
+//!type to be constructed.
+//!
+//!segment_manager<CharType, MemoryAlgorithm, IndexType> inherits publicly
+//!from segment_manager_base<MemoryAlgorithm> and inherits from it
+//!many public functions related to anonymous object and raw memory allocation.
+//!See segment_manager_base reference to know about those functions.
+template<class CharType
+ ,class MemoryAlgorithm
+ ,template<class IndexConfig> class IndexType>
+class segment_manager
+ : public segment_manager_base<MemoryAlgorithm>
+{
+ /// @cond
+ //Non-copyable
+ segment_manager();
+ segment_manager(const segment_manager &);
+ segment_manager &operator=(const segment_manager &);
+ typedef segment_manager_base<MemoryAlgorithm> Base;
+ typedef detail::block_header block_header_t;
+ /// @endcond
+
+ public:
+ typedef MemoryAlgorithm memory_algorithm;
+ typedef typename Base::void_pointer void_pointer;
+ typedef CharType char_type;
+
+ typedef segment_manager_base<MemoryAlgorithm> segment_manager_base_type;
+
+ static const std::size_t PayloadPerAllocation = Base::PayloadPerAllocation;
+
+ /// @cond
+ private:
+ typedef detail::index_config<CharType, MemoryAlgorithm> index_config_named;
+ typedef detail::index_config<char, MemoryAlgorithm> index_config_unique;
+ typedef IndexType<index_config_named> index_type;
+ typedef detail::bool_<is_intrusive_index<index_type>::value > is_intrusive_t;
+ typedef detail::bool_<is_node_index<index_type>::value> is_node_index_t;
+
+ public:
+ typedef IndexType<index_config_named> named_index_t;
+ typedef IndexType<index_config_unique> unique_index_t;
+ typedef detail::char_ptr_holder<CharType> char_ptr_holder_t;
+ typedef detail::segment_manager_iterator_transform
+ <typename named_index_t::const_iterator
+ ,is_intrusive_index<index_type>::value> named_transform;
+
+ typedef detail::segment_manager_iterator_transform
+ <typename unique_index_t::const_iterator
+ ,is_intrusive_index<index_type>::value> unique_transform;
+ /// @endcond
+
+ typedef typename Base::mutex_family mutex_family;
+
+ typedef transform_iterator
+ <typename named_index_t::const_iterator, named_transform> const_named_iterator;
+ typedef transform_iterator
+ <typename unique_index_t::const_iterator, unique_transform> const_unique_iterator;
+
+ /// @cond
+
+ //!Constructor proxy object definition helper class
+ template<class T>
+ struct construct_proxy
+ {
+ typedef detail::named_proxy<segment_manager, T, false> type;
+ };
+
+ //!Constructor proxy object definition helper class
+ template<class T>
+ struct construct_iter_proxy
+ {
+ typedef detail::named_proxy<segment_manager, T, true> type;
+ };
+
+ /// @endcond
+
+ //!Constructor of the segment manager
+ //!"size" is the size of the memory segment where
+ //!the segment manager is being constructed.
+ //!Can throw
+ segment_manager(std::size_t size)
+ : Base(size, priv_get_reserved_bytes())
+ , m_header(static_cast<Base*>(get_this_pointer()))
+ {
+ (void) anonymous_instance; (void) unique_instance;
+ assert(static_cast<const void*>(this) == static_cast<const void*>(static_cast<Base*>(this)));
+ }
+
+ //!Tries to find a previous named allocation. Returns the address
+ //!and the object count. On failure the first member of the
+ //!returned pair is 0.
+ template <class T>
+ std::pair<T*, std::size_t> find (const CharType* name)
+ { return this->priv_find_impl<T>(name, true); }
+
+ //!Tries to find a previous unique allocation. Returns the address
+ //!and the object count. On failure the first member of the
+ //!returned pair is 0.
+ template <class T>
+ std::pair<T*, std::size_t> find (const detail::unique_instance_t* name)
+ { return this->priv_find_impl<T>(name, true); }
+
+ //!Tries to find a previous named allocation. Returns the address
+ //!and the object count. On failure the first member of the
+ //!returned pair is 0. This search is not mutex-protected!
+ template <class T>
+ std::pair<T*, std::size_t> find_no_lock (const CharType* name)
+ { return this->priv_find_impl<T>(name, false); }
+
+ //!Tries to find a previous unique allocation. Returns the address
+ //!and the object count. On failure the first member of the
+ //!returned pair is 0. This search is not mutex-protected!
+ template <class T>
+ std::pair<T*, std::size_t> find_no_lock (const detail::unique_instance_t* name)
+ { return this->priv_find_impl<T>(name, false); }
+
+ //!Returns throwing "construct" proxy
+ //!object
+ template <class T>
+ typename construct_proxy<T>::type
+ construct(char_ptr_holder_t name)
+ { return typename construct_proxy<T>::type (this, name, false, true); }
+
+ //!Returns throwing "search or construct" proxy
+ //!object
+ template <class T>
+ typename construct_proxy<T>::type find_or_construct(char_ptr_holder_t name)
+ { return typename construct_proxy<T>::type (this, name, true, true); }
+
+ //!Returns no throwing "construct" proxy
+ //!object
+ template <class T>
+ typename construct_proxy<T>::type
+ construct(char_ptr_holder_t name, std::nothrow_t)
+ { return typename construct_proxy<T>::type (this, name, false, false); }
+
+ //!Returns no throwing "search or construct"
+ //!proxy object
+ template <class T>
+ typename construct_proxy<T>::type
+ find_or_construct(char_ptr_holder_t name, std::nothrow_t)
+ { return typename construct_proxy<T>::type (this, name, true, false); }
+
+ //!Returns throwing "construct from iterators" proxy object
+ template <class T>
+ typename construct_iter_proxy<T>::type
+ construct_it(char_ptr_holder_t name)
+ { return typename construct_iter_proxy<T>::type (this, name, false, true); }
+
+ //!Returns throwing "search or construct from iterators"
+ //!proxy object
+ template <class T>
+ typename construct_iter_proxy<T>::type
+ find_or_construct_it(char_ptr_holder_t name)
+ { return typename construct_iter_proxy<T>::type (this, name, true, true); }
+
+ //!Returns no throwing "construct from iterators"
+ //!proxy object
+ template <class T>
+ typename construct_iter_proxy<T>::type
+ construct_it(char_ptr_holder_t name, std::nothrow_t)
+ { return typename construct_iter_proxy<T>::type (this, name, false, false); }
+
+ //!Returns no throwing "search or construct from iterators"
+ //!proxy object
+ template <class T>
+ typename construct_iter_proxy<T>::type
+ find_or_construct_it(char_ptr_holder_t name, std::nothrow_t)
+ { return typename construct_iter_proxy<T>::type (this, name, true, false); }
+
+ //!Calls object function blocking recursive interprocess_mutex and guarantees that
+ //!no new named_alloc or destroy will be executed by any process while
+ //!executing the object function call*/
+ template <class Func>
+ void atomic_func(Func &f)
+ { scoped_lock<rmutex> guard(m_header); f(); }
+
+ //!Destroys a previously created unique instance.
+ //!Returns false if the object was not present.
+ template <class T>
+ bool destroy(const detail::unique_instance_t *)
+ {
+ detail::placement_destroy<T> dtor;
+ return this->priv_generic_named_destroy<char>
+ (typeid(T).name(), m_header.m_unique_index, dtor, is_intrusive_t());
+ }
+
+ //!Destroys the named object with
+ //!the given name. Returns false if that object can't be found.
+ template <class T>
+ bool destroy(const CharType *name)
+ {
+ detail::placement_destroy<T> dtor;
+ return this->priv_generic_named_destroy<CharType>
+ (name, m_header.m_named_index, dtor, is_intrusive_t());
+ }
+
+ //!Destroys an anonymous, unique or named object
+ //!using it's address
+ template <class T>
+ void destroy_ptr(const T *p)
+ {
+ //If T is void transform it to char
+ typedef typename detail::char_if_void<T>::type data_t;
+ detail::placement_destroy<data_t> dtor;
+ priv_destroy_ptr(p, dtor);
+ }
+
+ //!Returns the name of an object created with construct/find_or_construct
+ //!functions. Does not throw
+ template<class T>
+ static const CharType *get_instance_name(const T *ptr)
+ { return priv_get_instance_name(block_header_t::block_header_from_value(ptr)); }
+
+ //!Returns the length of an object created with construct/find_or_construct
+ //!functions. Does not throw.
+ template<class T>
+ static std::size_t get_instance_length(const T *ptr)
+ { return priv_get_instance_length(block_header_t::block_header_from_value(ptr), sizeof(T)); }
+
+ //!Returns is the the name of 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 priv_get_instance_type(block_header_t::block_header_from_value(ptr)); }
+
+ //!Preallocates needed index resources to optimize the
+ //!creation of "num" named objects in the managed memory segment.
+ //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
+ void reserve_named_objects(std::size_t num)
+ {
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ m_header.m_named_index.reserve(num);
+ }
+
+ //!Preallocates needed index resources to optimize the
+ //!creation of "num" unique objects in the managed memory segment.
+ //!Can throw boost::interprocess::bad_alloc if there is no enough memory.
+ void reserve_unique_objects(std::size_t num)
+ {
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ m_header.m_unique_index.reserve(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()
+ {
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ m_header.m_named_index.shrink_to_fit();
+ m_header.m_unique_index.shrink_to_fit();
+ }
+
+ //!Returns the number of named objects stored in
+ //!the segment.
+ std::size_t get_num_named_objects()
+ {
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ return m_header.m_named_index.size();
+ }
+
+ //!Returns the number of unique objects stored in
+ //!the segment.
+ std::size_t get_num_unique_objects()
+ {
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ return m_header.m_unique_index.size();
+ }
+
+ //!Obtains the minimum size needed by the
+ //!segment manager
+ static std::size_t get_min_size()
+ { return Base::get_min_size(priv_get_reserved_bytes()); }
+
+ //!Returns a constant iterator to the beginning of the information about
+ //!the named allocations performed in this segment manager
+ const_named_iterator named_begin() const
+ {
+ return make_transform_iterator
+ (m_header.m_named_index.begin(), named_transform());
+ }
+
+ //!Returns a constant iterator to the end of the information about
+ //!the named allocations performed in this segment manager
+ const_named_iterator named_end() const
+ {
+ return make_transform_iterator
+ (m_header.m_named_index.end(), named_transform());
+ }
+
+ //!Returns a constant iterator to the beginning of the information about
+ //!the unique allocations performed in this segment manager
+ const_unique_iterator unique_begin() const
+ {
+ return make_transform_iterator
+ (m_header.m_unique_index.begin(), unique_transform());
+ }
+
+ //!Returns a constant iterator to the end of the information about
+ //!the unique allocations performed in this segment manager
+ const_unique_iterator unique_end() const
+ {
+ return make_transform_iterator
+ (m_header.m_unique_index.end(), unique_transform());
+ }
+
+ //!This is the default allocator to allocate types T
+ //!from this managed segment
+ template<class T>
+ struct allocator
+ {
+ typedef boost::interprocess::allocator<T, segment_manager> 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 typename allocator<T>::type(this); }
+
+ //!This is the default deleter to delete types T
+ //!from this managed segment.
+ template<class T>
+ struct deleter
+ {
+ typedef boost::interprocess::deleter<T, segment_manager> 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 typename deleter<T>::type(this); }
+
+ /// @cond
+
+ //!Generic named/anonymous new function. Offers all the possibilities,
+ //!such as throwing, search before creating, and the constructor is
+ //!encapsulated in an object function.
+ template<class T>
+ T *generic_construct(const CharType *name,
+ std::size_t num,
+ bool try2find,
+ bool dothrow,
+ detail::in_place_interface &table)
+ {
+ return static_cast<T*>
+ (priv_generic_construct(name, num, try2find, dothrow, table));
+ }
+
+ private:
+ //!Tries to find a previous named allocation. Returns the address
+ //!and the object count. On failure the first member of the
+ //!returned pair is 0.
+ template <class T>
+ std::pair<T*, std::size_t> priv_find_impl (const CharType* name, bool lock)
+ {
+ //The name can't be null, no anonymous object can be found by name
+ assert(name != 0);
+ detail::placement_destroy<T> table;
+ std::size_t size;
+ void *ret;
+
+ if(name == reinterpret_cast<const CharType*>(-1)){
+ ret = priv_generic_find<char> (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), lock);
+ }
+ else{
+ ret = priv_generic_find<CharType> (name, m_header.m_named_index, table, size, is_intrusive_t(), lock);
+ }
+ return std::pair<T*, std::size_t>(static_cast<T*>(ret), size);
+ }
+
+ //!Tries to find a previous unique allocation. Returns the address
+ //!and the object count. On failure the first member of the
+ //!returned pair is 0.
+ template <class T>
+ std::pair<T*, std::size_t> priv_find__impl (const detail::unique_instance_t* name, bool lock)
+ {
+ detail::placement_destroy<T> table;
+ std::size_t size;
+ void *ret = priv_generic_find<char>(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock);
+ return std::pair<T*, std::size_t>(static_cast<T*>(ret), size);
+ }
+
+ void *priv_generic_construct(const CharType *name,
+ std::size_t num,
+ bool try2find,
+ bool dothrow,
+ detail::in_place_interface &table)
+ {
+ void *ret;
+ //Security overflow check
+ if(num > ((std::size_t)-1)/table.size){
+ if(dothrow)
+ throw bad_alloc();
+ else
+ return 0;
+ }
+ if(name == 0){
+ ret = this->prot_anonymous_construct(num, dothrow, table);
+ }
+ else if(name == reinterpret_cast<const CharType*>(-1)){
+ ret = this->priv_generic_named_construct<char>
+ (unique_type, table.type_name, num, try2find, dothrow, table, m_header.m_unique_index, is_intrusive_t());
+ }
+ else{
+ ret = this->priv_generic_named_construct<CharType>
+ (named_type, name, num, try2find, dothrow, table, m_header.m_named_index, is_intrusive_t());
+ }
+ return ret;
+ }
+
+ void priv_destroy_ptr(const void *ptr, detail::in_place_interface &dtor)
+ {
+ block_header_t *ctrl_data = block_header_t::block_header_from_value(ptr, dtor.size, dtor.alignment);
+ switch(ctrl_data->allocation_type()){
+ case anonymous_type:
+ this->prot_anonymous_destroy(ptr, dtor);
+ break;
+
+ case named_type:
+ this->priv_generic_named_destroy<CharType>
+ (ctrl_data, m_header.m_named_index, dtor, is_node_index_t());
+ break;
+
+ case unique_type:
+ this->priv_generic_named_destroy<char>
+ (ctrl_data, m_header.m_unique_index, dtor, is_node_index_t());
+ break;
+
+ default:
+ //This type is unknown, bad pointer passed to this function!
+ assert(0);
+ break;
+ }
+ }
+
+ //!Returns the name of an object created with construct/find_or_construct
+ //!functions. Does not throw
+ static const CharType *priv_get_instance_name(block_header_t *ctrl_data)
+ {
+ allocation_type type = ctrl_data->allocation_type();
+ if(type != named_type){
+ assert((type == anonymous_type && ctrl_data->m_num_char == 0) ||
+ (type == unique_type && ctrl_data->m_num_char != 0) );
+ return 0;
+ }
+ CharType *name = static_cast<CharType*>(ctrl_data->template name<CharType>());
+
+ //Sanity checks
+ assert(ctrl_data->sizeof_char() == sizeof(CharType));
+ assert(ctrl_data->m_num_char == std::char_traits<CharType>::length(name));
+ return name;
+ }
+
+ static std::size_t priv_get_instance_length(block_header_t *ctrl_data, std::size_t sizeofvalue)
+ {
+ //Get header
+ assert((ctrl_data->value_bytes() %sizeofvalue) == 0);
+ return ctrl_data->value_bytes()/sizeofvalue;
+ }
+
+ //!Returns is the the name of an object created with construct/find_or_construct
+ //!functions. Does not throw
+ static instance_type priv_get_instance_type(block_header_t *ctrl_data)
+ {
+ //Get header
+ assert((instance_type)ctrl_data->allocation_type() < max_allocation_type);
+ return (instance_type)ctrl_data->allocation_type();
+ }
+
+ static std::size_t priv_get_reserved_bytes()
+ {
+ //Get the number of bytes until the end of (*this)
+ //beginning in the end of the Base base.
+ return sizeof(segment_manager) - sizeof(Base);
+ }
+
+ template <class CharT>
+ void *priv_generic_find
+ (const CharT* name,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table,
+ std::size_t &length,
+ detail::true_ is_intrusive,
+ bool use_lock)
+ {
+ (void)is_intrusive;
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef detail::index_key<CharT, void_pointer> index_key_t;
+ typedef typename index_type::iterator index_it;
+
+ //-------------------------------
+ scoped_lock<rmutex> guard(priv_get_lock(use_lock));
+ //-------------------------------
+ //Find name in index
+ detail::intrusive_compare_key<CharT> key
+ (name, std::char_traits<CharT>::length(name));
+ index_it it = index.find(key);
+
+ //Initialize return values
+ void *ret_ptr = 0;
+ length = 0;
+
+ //If found, assign values
+ if(it != index.end()){
+ //Get header
+ block_header_t *ctrl_data = it->get_block_header();
+
+ //Sanity check
+ assert((ctrl_data->m_value_bytes % table.size) == 0);
+ assert(ctrl_data->sizeof_char() == sizeof(CharT));
+ ret_ptr = ctrl_data->value();
+ length = ctrl_data->m_value_bytes/table.size;
+ }
+ return ret_ptr;
+ }
+
+ template <class CharT>
+ void *priv_generic_find
+ (const CharT* name,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table,
+ std::size_t &length,
+ detail::false_ is_intrusive,
+ bool use_lock)
+ {
+ (void)is_intrusive;
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef typename index_type::key_type key_type;
+ typedef typename index_type::iterator index_it;
+
+ //-------------------------------
+ scoped_lock<rmutex> guard(priv_get_lock(use_lock));
+ //-------------------------------
+ //Find name in index
+ index_it it = index.find(key_type(name, std::char_traits<CharT>::length(name)));
+
+ //Initialize return values
+ void *ret_ptr = 0;
+ length = 0;
+
+ //If found, assign values
+ if(it != index.end()){
+ //Get header
+ block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
+ (detail::get_pointer(it->second.m_ptr));
+
+ //Sanity check
+ assert((ctrl_data->m_value_bytes % table.size) == 0);
+ assert(ctrl_data->sizeof_char() == sizeof(CharT));
+ ret_ptr = ctrl_data->value();
+ length = ctrl_data->m_value_bytes/table.size;
+ }
+ return ret_ptr;
+ }
+
+ template <class CharT>
+ bool priv_generic_named_destroy
+ (block_header_t *block_header,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table,
+ detail::true_ is_node_index)
+ {
+ (void)is_node_index;
+ typedef typename IndexType<detail::index_config<CharT, MemoryAlgorithm> >::iterator index_it;
+
+ index_it *ihdr = block_header_t::to_first_header<index_it>(block_header);
+ return this->priv_generic_named_destroy_impl<CharT>(*ihdr, index, table);
+ }
+
+ template <class CharT>
+ bool priv_generic_named_destroy
+ (block_header_t *block_header,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table,
+ detail::false_ is_node_index)
+ {
+ (void)is_node_index;
+ CharT *name = static_cast<CharT*>(block_header->template name<CharT>());
+ return this->priv_generic_named_destroy<CharT>(name, index, table, is_intrusive_t());
+ }
+
+ template <class CharT>
+ bool priv_generic_named_destroy(const CharT *name,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table,
+ detail::true_ is_intrusive_index)
+ {
+ (void)is_intrusive_index;
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef detail::index_key<CharT, void_pointer> index_key_t;
+ typedef typename index_type::iterator index_it;
+ typedef typename index_type::value_type intrusive_value_type;
+
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ //Find name in index
+ detail::intrusive_compare_key<CharT> key
+ (name, std::char_traits<CharT>::length(name));
+ index_it it = index.find(key);
+
+ //If not found, return false
+ if(it == index.end()){
+ //This name is not present in the index, wrong pointer or name!
+ //assert(0);
+ return false;
+ }
+
+ block_header_t *ctrl_data = it->get_block_header();
+ intrusive_value_type *iv = intrusive_value_type::get_intrusive_value_type(ctrl_data);
+ void *memory = iv;
+ void *values = ctrl_data->value();
+ std::size_t num = ctrl_data->m_value_bytes/table.size;
+
+ //Sanity check
+ assert((ctrl_data->m_value_bytes % table.size) == 0);
+ assert(sizeof(CharT) == ctrl_data->sizeof_char());
+
+ //Erase node from index
+ index.erase(it);
+
+ //Destroy the headers
+ ctrl_data->~block_header_t();
+ iv->~intrusive_value_type();
+
+ //Call destructors and free memory
+ std::size_t destroyed;
+ table.destroy_n(values, num, destroyed);
+ this->deallocate(memory);
+ return true;
+ }
+
+ template <class CharT>
+ bool priv_generic_named_destroy(const CharT *name,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table,
+ detail::false_ is_intrusive_index)
+ {
+ (void)is_intrusive_index;
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef typename index_type::iterator index_it;
+ typedef typename index_type::key_type key_type;
+
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ //Try to find the name in the index
+ index_it it = index.find(key_type (name,
+ std::char_traits<CharT>::length(name)));
+
+ //If not found, return false
+ if(it == index.end()){
+ //This name is not present in the index, wrong pointer or name!
+ assert(0);
+ return false;
+ }
+ return this->priv_generic_named_destroy_impl<CharT>(it, index, table);
+ }
+
+ template <class CharT>
+ bool priv_generic_named_destroy_impl
+ (const typename IndexType<detail::index_config<CharT, MemoryAlgorithm> >::iterator &it,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::in_place_interface &table)
+ {
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef typename index_type::iterator index_it;
+
+ //Get allocation parameters
+ block_header_t *ctrl_data = reinterpret_cast<block_header_t*>
+ (detail::get_pointer(it->second.m_ptr));
+ char *stored_name = static_cast<char*>(static_cast<void*>(const_cast<CharT*>(it->first.name())));
+ (void)stored_name;
+
+ //Check if the distance between the name pointer and the memory pointer
+ //is correct (this can detect incorrect type in destruction)
+ std::size_t num = ctrl_data->m_value_bytes/table.size;
+ void *values = ctrl_data->value();
+
+ //Sanity check
+ assert((ctrl_data->m_value_bytes % table.size) == 0);
+ assert(static_cast<void*>(stored_name) == static_cast<void*>(ctrl_data->template name<CharT>()));
+ assert(sizeof(CharT) == ctrl_data->sizeof_char());
+
+ //Erase node from index
+ index.erase(it);
+
+ //Destroy the header
+ ctrl_data->~block_header_t();
+
+ void *memory;
+ if(is_node_index_t::value){
+ index_it *ihdr = block_header_t::
+ to_first_header<index_it>(ctrl_data);
+ ihdr->~index_it();
+ memory = ihdr;
+ }
+ else{
+ memory = ctrl_data;
+ }
+
+ //Call destructors and free memory
+ std::size_t destroyed;
+ table.destroy_n(values, num, destroyed);
+ this->deallocate(memory);
+ return true;
+ }
+
+ template<class CharT>
+ void * priv_generic_named_construct(std::size_t type,
+ const CharT *name,
+ std::size_t num,
+ bool try2find,
+ bool dothrow,
+ detail::in_place_interface &table,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::true_ is_intrusive)
+ {
+ (void)is_intrusive;
+ std::size_t namelen = std::char_traits<CharT>::length(name);
+
+ block_header_t block_info ( table.size*num
+ , table.alignment
+ , type
+ , sizeof(CharT)
+ , namelen);
+
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef typename index_type::iterator index_it;
+ typedef std::pair<index_it, bool> index_ib;
+
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ //Insert the node. This can throw.
+ //First, we want to know if the key is already present before
+ //we allocate any memory, and if the key is not present, we
+ //want to allocate all memory in a single buffer that will
+ //contain the name and the user buffer.
+ //
+ //Since equal_range(key) + insert(hint, value) approach is
+ //quite inefficient in container implementations
+ //(they re-test if the position is correct), I've chosen
+ //to insert the node, do an ugly un-const cast and modify
+ //the key (which is a smart pointer) to an equivalent one
+ index_ib insert_ret;
+
+ typename index_type::insert_commit_data commit_data;
+ typedef typename index_type::value_type intrusive_value_type;
+
+ BOOST_TRY{
+ detail::intrusive_compare_key<CharT> key(name, namelen);
+ insert_ret = index.insert_check(key, commit_data);
+ }
+ //Ignore exceptions
+ BOOST_CATCH(...){
+ if(dothrow)
+ BOOST_RETHROW
+ return 0;
+ }
+ BOOST_CATCH_END
+
+ index_it it = insert_ret.first;
+
+ //If found and this is find or construct, return data
+ //else return null
+ if(!insert_ret.second){
+ if(try2find){
+ return it->get_block_header()->value();
+ }
+ if(dothrow){
+ throw interprocess_exception(already_exists_error);
+ }
+ else{
+ return 0;
+ }
+ }
+
+ //Allocates buffer for name + data, this can throw (it hurts)
+ void *buffer_ptr;
+
+ //Check if there is enough memory
+ if(dothrow){
+ buffer_ptr = this->allocate
+ (block_info.total_size_with_header<intrusive_value_type>());
+ }
+ else{
+ buffer_ptr = this->allocate
+ (block_info.total_size_with_header<intrusive_value_type>(), std::nothrow_t());
+ if(!buffer_ptr)
+ return 0;
+ }
+
+ //Now construct the intrusive hook plus the header
+ intrusive_value_type * intrusive_hdr = new(buffer_ptr) intrusive_value_type();
+ block_header_t * hdr = new(intrusive_hdr->get_block_header())block_header_t(block_info);
+ void *ptr = 0; //avoid gcc warning
+ ptr = hdr->value();
+
+ //Copy name to memory segment and insert data
+ CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
+ std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
+
+ BOOST_TRY{
+ //Now commit the insertion using previous context data
+ it = index.insert_commit(*intrusive_hdr, commit_data);
+ }
+ //Ignore exceptions
+ BOOST_CATCH(...){
+ if(dothrow)
+ BOOST_RETHROW
+ return 0;
+ }
+ BOOST_CATCH_END
+
+ //Avoid constructions if constructor is trivial
+ //Build scoped ptr to avoid leaks with constructor exception
+ detail::mem_algo_deallocator<segment_manager_base_type> mem
+ (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
+
+ //Initialize the node value_eraser to erase inserted node
+ //if something goes wrong. This will be executed *before*
+ //the memory allocation as the intrusive value is built in that
+ //memory
+ value_eraser<index_type> v_eraser(index, it);
+
+ //Construct array, this can throw
+ detail::array_construct(ptr, num, table);
+
+ //Release rollbacks since construction was successful
+ v_eraser.release();
+ mem.release();
+ return ptr;
+ }
+
+ //!Generic named new function for
+ //!named functions
+ template<class CharT>
+ void * priv_generic_named_construct(std::size_t type,
+ const CharT *name,
+ std::size_t num,
+ bool try2find,
+ bool dothrow,
+ detail::in_place_interface &table,
+ IndexType<detail::index_config<CharT, MemoryAlgorithm> > &index,
+ detail::false_ is_intrusive)
+ {
+ (void)is_intrusive;
+ std::size_t namelen = std::char_traits<CharT>::length(name);
+
+ block_header_t block_info ( table.size*num
+ , table.alignment
+ , type
+ , sizeof(CharT)
+ , namelen);
+
+ typedef IndexType<detail::index_config<CharT, MemoryAlgorithm> > index_type;
+ typedef typename index_type::key_type key_type;
+ typedef typename index_type::mapped_type mapped_type;
+ typedef typename index_type::value_type value_type;
+ typedef typename index_type::iterator index_it;
+ typedef std::pair<index_it, bool> index_ib;
+
+ //-------------------------------
+ scoped_lock<rmutex> guard(m_header);
+ //-------------------------------
+ //Insert the node. This can throw.
+ //First, we want to know if the key is already present before
+ //we allocate any memory, and if the key is not present, we
+ //want to allocate all memory in a single buffer that will
+ //contain the name and the user buffer.
+ //
+ //Since equal_range(key) + insert(hint, value) approach is
+ //quite inefficient in container implementations
+ //(they re-test if the position is correct), I've chosen
+ //to insert the node, do an ugly un-const cast and modify
+ //the key (which is a smart pointer) to an equivalent one
+ index_ib insert_ret;
+ BOOST_TRY{
+ insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0)));
+ }
+ //Ignore exceptions
+ BOOST_CATCH(...){
+ if(dothrow)
+ BOOST_RETHROW;
+ return 0;
+ }
+ BOOST_CATCH_END
+
+ index_it it = insert_ret.first;
+
+ //If found and this is find or construct, return data
+ //else return null
+ if(!insert_ret.second){
+ if(try2find){
+ block_header_t *hdr = static_cast<block_header_t*>
+ (detail::get_pointer(it->second.m_ptr));
+ return hdr->value();
+ }
+ return 0;
+ }
+ //Initialize the node value_eraser to erase inserted node
+ //if something goes wrong
+ value_eraser<index_type> v_eraser(index, it);
+
+ //Allocates buffer for name + data, this can throw (it hurts)
+ void *buffer_ptr;
+ block_header_t * hdr;
+
+ //Allocate and construct the headers
+ if(is_node_index_t::value){
+ std::size_t total_size = block_info.total_size_with_header<index_it>();
+ if(dothrow){
+ buffer_ptr = this->allocate(total_size);
+ }
+ else{
+ buffer_ptr = this->allocate(total_size, std::nothrow_t());
+ if(!buffer_ptr)
+ return 0;
+ }
+ index_it *idr = new(buffer_ptr) index_it(it);
+ hdr = block_header_t::from_first_header<index_it>(idr);
+ }
+ else{
+ if(dothrow){
+ buffer_ptr = this->allocate(block_info.total_size());
+ }
+ else{
+ buffer_ptr = this->allocate(block_info.total_size(), std::nothrow_t());
+ if(!buffer_ptr)
+ return 0;
+ }
+ hdr = static_cast<block_header_t*>(buffer_ptr);
+ }
+
+ hdr = new(hdr)block_header_t(block_info);
+ void *ptr = 0; //avoid gcc warning
+ ptr = hdr->value();
+
+ //Copy name to memory segment and insert data
+ CharT *name_ptr = static_cast<CharT *>(hdr->template name<CharT>());
+ std::char_traits<CharT>::copy(name_ptr, name, namelen+1);
+
+ //Do the ugly cast, please mama, forgive me!
+ //This new key points to an identical string, so it must have the
+ //same position than the overwritten key according to the predicate
+ const_cast<key_type &>(it->first).name(name_ptr);
+ it->second.m_ptr = hdr;
+
+ //Build scoped ptr to avoid leaks with constructor exception
+ detail::mem_algo_deallocator<segment_manager_base_type> mem
+ (buffer_ptr, *static_cast<segment_manager_base_type*>(this));
+
+ //Construct array, this can throw
+ detail::array_construct(ptr, num, table);
+
+ //All constructors successful, we don't want to release memory
+ mem.release();
+
+ //Release node v_eraser since construction was successful
+ v_eraser.release();
+ return ptr;
+ }
+
+ private:
+ //!Returns the this pointer
+ segment_manager *get_this_pointer()
+ { return this; }
+
+ typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex;
+
+ scoped_lock<rmutex> priv_get_lock(bool use_lock)
+ {
+ scoped_lock<rmutex> local(m_header, defer_lock);
+ if(use_lock){
+ local.lock();
+ }
+ return scoped_lock<rmutex>(boost::move(local));
+ }
+
+ //!This struct includes needed data and derives from
+ //!rmutex to allow EBO when using null interprocess_mutex
+ struct header_t
+ : public rmutex
+ {
+ named_index_t m_named_index;
+ unique_index_t m_unique_index;
+
+ header_t(Base *restricted_segment_mngr)
+ : m_named_index (restricted_segment_mngr)
+ , m_unique_index(restricted_segment_mngr)
+ {}
+ } m_header;
+
+ /// @endcond
+};
+
+
+}} //namespace boost { namespace interprocess
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_HPP
+
Added: sandbox/boost/interprocess/shared_memory_object.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/shared_memory_object.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,381 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_SHARED_MEMORY_OBJECT_HPP
+#define BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/os_file_functions.hpp>
+#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
+#include <cstddef>
+#include <string>
+#include <cstdio> //std::remove
+#include <algorithm>
+
+#ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS
+# include <fcntl.h> //O_CREAT, O_*...
+# include <sys/mman.h> //shm_xxx
+# include <unistd.h> //ftruncate, close
+# include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
+#else
+//
+#endif
+
+//!\file
+//!Describes a shared memory object management class.
+
+namespace boost {
+namespace interprocess {
+
+//!A class that wraps a shared memory mapping that can be used to
+//!create mapped regions from the mapped files
+class shared_memory_object
+{
+ /// @cond
+ //Non-copyable and non-assignable
+ shared_memory_object(shared_memory_object &);
+ shared_memory_object &operator=(shared_memory_object &);
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(shared_memory_object)
+
+ //!Default constructor. Represents an empty shared_memory_object.
+ shared_memory_object();
+
+ //!Creates a shared memory object with name "name" and mode "mode", with the access mode "mode"
+ //!If the file previously exists, throws an error.*/
+ shared_memory_object(create_only_t, const char *name, mode_t mode)
+ { this->priv_open_or_create(detail::DoCreate, name, mode); }
+
+ //!Tries to create a shared memory object 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.
+ shared_memory_object(open_or_create_t, const char *name, mode_t mode)
+ { this->priv_open_or_create(detail::DoOpenOrCreate, name, mode); }
+
+ //!Tries to open a shared memory object with name "name", with the access mode "mode".
+ //!If the file does not previously exist, it throws an error.
+ shared_memory_object(open_only_t, const char *name, mode_t mode)
+ { this->priv_open_or_create(detail::DoOpen, name, mode); }
+
+ //!Moves the ownership of "moved"'s shared memory object to *this.
+ //!After the call, "moved" does not represent any shared memory object.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ shared_memory_object(boost::rv<shared_memory_object> &moved)
+ : m_handle(file_handle_t(detail::invalid_file()))
+ { this->swap(moved.get()); }
+ #else
+ shared_memory_object(shared_memory_object &&moved)
+ : m_handle(file_handle_t(detail::invalid_file()))
+ { this->swap(moved); }
+ #endif
+
+ //!Moves the ownership of "moved"'s shared memory to *this.
+ //!After the call, "moved" does not represent any shared memory.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ shared_memory_object &operator=(boost::rv<shared_memory_object> &moved)
+ {
+ shared_memory_object tmp(moved);
+ this->swap(tmp);
+ return *this;
+ }
+ #else
+ shared_memory_object &operator=(shared_memory_object &&moved)
+ {
+ shared_memory_object tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+ #endif
+
+ //!Swaps the shared_memory_objects. Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<shared_memory_object> &moved)
+ { this->swap(moved.get()); }
+ void swap(shared_memory_object &other);
+ #else
+ void swap(shared_memory_object &&other);
+ #endif
+
+ //!Erases a shared memory object from the system.
+ //!Returns false on error. Never throws
+ static bool remove(const char *name);
+
+ //!Sets the size of the shared memory mapping
+ void truncate(offset_t length);
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. All mapped regions 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 resource from the system
+ //!use remove().
+ ~shared_memory_object();
+
+ //!Returns the name of the file.
+ 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
+ mode_t get_mode() const;
+
+ //!Returns mapping handle. Never throws.
+ mapping_handle_t get_mapping_handle() const;
+
+ /// @cond
+ 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;
+ /// @endcond
+};
+
+/// @cond
+
+inline shared_memory_object::shared_memory_object()
+ : m_handle(file_handle_t(detail::invalid_file()))
+{}
+
+inline shared_memory_object::~shared_memory_object()
+{ this->priv_close(); }
+
+
+inline const char *shared_memory_object::get_name() const
+{ return m_filename.c_str(); }
+
+inline bool shared_memory_object::get_size(offset_t &size) const
+{ return detail::get_file_size((file_handle_t)m_handle, size); }
+
+#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+inline void shared_memory_object::swap(shared_memory_object &other)
+#else
+inline void shared_memory_object::swap(shared_memory_object &&other)
+#endif
+{
+ std::swap(m_handle, other.m_handle);
+ std::swap(m_mode, other.m_mode);
+ m_filename.swap(other.m_filename);
+}
+
+inline mapping_handle_t shared_memory_object::get_mapping_handle() const
+{ return detail::mapping_handle_from_file_handle(m_handle); }
+
+inline mode_t shared_memory_object::get_mode() const
+{ return m_mode; }
+
+#if !defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
+
+inline bool shared_memory_object::priv_open_or_create
+ (detail::create_enum_t type, const char *filename, mode_t mode)
+{
+ m_filename = filename;
+ std::string shmfile;
+ detail::create_tmp_dir_and_get_filename(filename, shmfile);
+
+ //Set accesses
+ if (mode != read_write && mode != read_only){
+ error_info err = other_error;
+ throw interprocess_exception(err);
+ }
+
+ switch(type){
+ case detail::DoOpen:
+ m_handle = detail::open_existing_file(shmfile.c_str(), mode, true);
+ break;
+ case detail::DoCreate:
+ m_handle = detail::create_new_file(shmfile.c_str(), mode, true);
+ break;
+ case detail::DoOpenOrCreate:
+ m_handle = detail::create_or_open_file(shmfile.c_str(), mode, true);
+ break;
+ default:
+ {
+ error_info err = other_error;
+ throw interprocess_exception(err);
+ }
+ }
+
+ //Check for error
+ if(m_handle == detail::invalid_file()){
+ error_info err = system_error_code();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+
+ //detail::delete_file_on_reboot_if_possible(shmfile.c_str());
+ m_mode = mode;
+ return true;
+}
+
+inline bool shared_memory_object::remove(const char *filename)
+{
+ try{
+ //Make sure a temporary path is created for shared memory
+ std::string shmfile;
+ detail::tmp_filename(filename, shmfile);
+ return detail::delete_file(shmfile.c_str()) == 0;
+ }
+ catch(...){
+ return false;
+ }
+}
+
+inline void shared_memory_object::truncate(offset_t length)
+{
+ if(!detail::truncate_file(m_handle, length)){
+ error_info err = system_error_code();
+ throw interprocess_exception(err);
+ }
+}
+
+inline void shared_memory_object::priv_close()
+{
+ if(m_handle != detail::invalid_file()){
+ detail::close_file(m_handle);
+ m_handle = detail::invalid_file();
+ }
+}
+
+#else //!defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS)
+
+inline bool shared_memory_object::priv_open_or_create
+ (detail::create_enum_t type,
+ const char *filename,
+ mode_t mode)
+{
+ #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
+ detail::add_leading_slash(filename, m_filename);
+ #else
+ detail::create_tmp_dir_and_get_filename(filename, m_filename);
+ #endif
+
+ //Create new mapping
+ int oflag = 0;
+ if(mode == read_only){
+ oflag |= O_RDONLY;
+ }
+ else if(mode == read_write){
+ oflag |= O_RDWR;
+ }
+ else{
+ error_info err(mode_error);
+ throw interprocess_exception(err);
+ }
+
+ switch(type){
+ case detail::DoOpen:
+ //No addition
+ break;
+ case detail::DoCreate:
+ oflag |= (O_CREAT | O_EXCL);
+ break;
+ case detail::DoOpenOrCreate:
+ oflag |= O_CREAT;
+ break;
+ default:
+ {
+ error_info err = other_error;
+ throw interprocess_exception(err);
+ }
+ }
+
+ //Open file using POSIX API
+ m_handle = shm_open(m_filename.c_str(), oflag, S_IRWXO | S_IRWXG | S_IRWXU);
+
+ //Check for error
+ if(m_handle == -1){
+ error_info err = errno;
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+
+ m_filename = filename;
+ m_mode = mode;
+ return true;
+}
+
+inline bool shared_memory_object::remove(const char *filename)
+{
+ try{
+ std::string file_str;
+ #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY
+ detail::add_leading_slash(filename, file_str);
+ #else
+ detail::tmp_filename(filename, file_str);
+ #endif
+ return 0 != shm_unlink(file_str.c_str());
+ }
+ catch(...){
+ return false;
+ }
+}
+
+inline void shared_memory_object::truncate(offset_t length)
+{
+ if(0 != ftruncate(m_handle, length)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+}
+
+inline void shared_memory_object::priv_close()
+{
+ if(m_handle != -1){
+ ::close(m_handle);
+ m_handle = -1;
+ }
+}
+
+#endif
+
+///@endcond
+
+//!A class that stores the name of a shared memory
+//!and calls shared_memory_object::remove(name) in its destructor
+//!Useful to remove temporary shared memory objects in the presence
+//!of exceptions
+class remove_shared_memory_on_destroy
+{
+ const char * m_name;
+ public:
+ remove_shared_memory_on_destroy(const char *name)
+ : m_name(name)
+ {}
+
+ ~remove_shared_memory_on_destroy()
+ { shared_memory_object::remove(m_name); }
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_SHARED_MEMORY_OBJECT_HPP
Added: sandbox/boost/interprocess/smart_ptr/deleter.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/deleter.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,61 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_DELETER_HPP
+#define BOOST_INTERPROCESS_DELETER_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+
+//!\file
+//!Describes the functor to delete objects from the segment.
+
+namespace boost {
+namespace interprocess {
+
+//!A deleter that uses the segment manager's destroy_ptr
+//!function to destroy the passed pointer resource.
+//!
+//!This deleter is used
+template<class T, class SegmentManager>
+class deleter
+{
+ public:
+ typedef typename detail::pointer_to_other
+ <typename SegmentManager::void_pointer, T>::type pointer;
+
+ private:
+ typedef typename detail::pointer_to_other
+ <pointer, SegmentManager>::type segment_manager_pointer;
+
+ segment_manager_pointer mp_mngr;
+
+ public:
+ deleter(segment_manager_pointer pmngr)
+ : mp_mngr(pmngr)
+ {}
+
+ void operator()(const pointer &p)
+ { mp_mngr->destroy_ptr(detail::get_pointer(p)); }
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_DELETER_HPP
Added: sandbox/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,44 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/detail/bad_weak_ptr.hpp
+//
+// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
+// (C) Copyright Ion 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_BAD_WEAK_PTR_HPP_INCLUDED
+#define BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#ifndef BOOST_NO_EXCEPTIONS
+#include <exception>
+#endif
+
+namespace boost{
+namespace interprocess{
+
+class bad_weak_ptr
+ : public std::exception
+{
+ public:
+
+ virtual char const * what() const throw()
+ { return "boost::interprocess::bad_weak_ptr"; }
+};
+
+} // namespace interprocess
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_BAD_WEAK_PTR_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/detail/shared_count.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/detail/shared_count.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,320 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/detail/shared_count.hpp
+//
+// (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003
+// (C) Copyright Peter Dimov 2004-2005
+// (C) Copyright Ion Gaztanaga 2006-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_SHARED_COUNT_HPP_INCLUDED
+#define BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED
+
+// MS compatible compilers support #pragma once
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/checked_delete.hpp>
+#include <boost/interprocess/smart_ptr/detail/bad_weak_ptr.hpp>
+#include <boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <functional> // std::less
+
+namespace boost {
+namespace interprocess {
+namespace detail{
+
+template<class T, class VoidAllocator, class Deleter>
+class weak_count;
+
+template<class T, class VoidAllocator, class Deleter>
+class shared_count
+{
+ public:
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, T>::type pointer;
+
+ private:
+ typedef sp_counted_impl_pd<VoidAllocator, Deleter> counted_impl;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, counted_impl>::type counted_impl_ptr;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, sp_counted_base>::type counted_base_ptr;
+ typedef typename VoidAllocator::template rebind
+ <counted_impl>::other counted_impl_allocator;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, const Deleter>::type const_deleter_pointer;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, const VoidAllocator>::type const_allocator_pointer;
+
+ pointer m_px;
+ counted_impl_ptr m_pi;
+
+ template <class T2, class VoidAllocator2, class Deleter2>
+ friend class weak_count;
+
+ template <class T2, class VoidAllocator2, class Deleter2>
+ friend class shared_count;
+
+ public:
+
+ shared_count()
+ : m_px(0), m_pi(0) // nothrow
+ {}
+
+ template <class Ptr>
+ shared_count(const shared_count &other_shared_count, const Ptr &p)
+ : m_px(p), m_pi(other_shared_count.m_pi)
+ {}
+
+ template <class Ptr>
+ shared_count(const Ptr &p, const VoidAllocator &a, Deleter d)
+ : m_px(p), m_pi(0)
+ {
+ BOOST_TRY{
+ if(p){
+ counted_impl_allocator alloc(a);
+ m_pi = alloc.allocate(1);
+ //Anti-exception deallocator
+ scoped_ptr<counted_impl,
+ scoped_ptr_dealloc_functor<counted_impl_allocator> >
+ deallocator(m_pi, alloc);
+ //It's more correct to use VoidAllocator::construct but
+ //this needs copy constructor and we don't like it
+ new(detail::get_pointer(m_pi))counted_impl(p, a, d);
+ deallocator.release();
+ }
+ }
+ BOOST_CATCH (...){
+ d(p); // delete p
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ ~shared_count() // nothrow
+ {
+ if( m_pi != 0 )
+ m_pi->release();
+ }
+
+ shared_count(shared_count const & r)
+ : m_px(r.m_px), m_pi(r.m_pi) // nothrow
+ { if( m_pi != 0 ) m_pi->add_ref_copy(); }
+
+ //this is a test
+ template<class Y>
+ explicit shared_count(shared_count<Y, VoidAllocator, Deleter> const & r)
+ : m_px(r.m_px), m_pi(r.m_pi) // nothrow
+ { if( m_pi != 0 ) m_pi->add_ref_copy(); }
+
+ //this is a test
+ template<class Y>
+ explicit shared_count(const pointer & ptr, shared_count<Y, VoidAllocator, Deleter> const & r)
+ : m_px(ptr), m_pi(r.m_pi) // nothrow
+ { if( m_pi != 0 ) m_pi->add_ref_copy(); }
+
+/*
+ explicit shared_count(weak_count<Y, VoidAllocator, Deleter> const & r)
+ // throws bad_weak_ptr when r.use_count() == 0
+ : m_pi( r.m_pi )
+ {
+ if( m_pi == 0 || !m_pi->add_ref_lock() ){
+ boost::throw_exception( boost::interprocess::bad_weak_ptr() );
+ }
+ }
+*/
+ template<class Y>
+ explicit shared_count(weak_count<Y, VoidAllocator, Deleter> const & r)
+ // throws bad_weak_ptr when r.use_count() == 0
+ : m_px(r.m_px), m_pi( r.m_pi )
+ {
+ if( m_pi == 0 || !m_pi->add_ref_lock() ){
+ throw( boost::interprocess::bad_weak_ptr() );
+ }
+ }
+
+ const pointer &get_pointer() const
+ { return m_px; }
+
+ pointer &get_pointer()
+ { return m_px; }
+
+ shared_count & operator= (shared_count const & r) // nothrow
+ {
+ m_px = r.m_px;
+ counted_impl_ptr tmp = r.m_pi;
+ if( tmp != m_pi ){
+ if(tmp != 0) tmp->add_ref_copy();
+ if(m_pi != 0) m_pi->release();
+ m_pi = tmp;
+ }
+ return *this;
+ }
+
+ template<class Y>
+ shared_count & operator= (shared_count<Y, VoidAllocator, Deleter> const & r) // nothrow
+ {
+ m_px = r.m_px;
+ counted_impl_ptr tmp = r.m_pi;
+ if( tmp != m_pi ){
+ if(tmp != 0) tmp->add_ref_copy();
+ if(m_pi != 0) m_pi->release();
+ m_pi = tmp;
+ }
+ return *this;
+ }
+
+ void swap(shared_count & r) // nothrow
+ { detail::do_swap(m_px, r.m_px); detail::do_swap(m_pi, r.m_pi); }
+
+ long use_count() const // nothrow
+ { return m_pi != 0? m_pi->use_count(): 0; }
+
+ bool unique() const // nothrow
+ { return use_count() == 1; }
+
+ const_deleter_pointer get_deleter() const
+ { return m_pi ? m_pi->get_deleter() : 0; }
+
+// const_allocator_pointer get_allocator() const
+// { return m_pi ? m_pi->get_allocator() : 0; }
+
+ template<class T2, class VoidAllocator2, class Deleter2>
+ bool internal_equal (shared_count<T2, VoidAllocator2, Deleter2> const & other) const
+ { return this->m_pi == other.m_pi; }
+
+ template<class T2, class VoidAllocator2, class Deleter2>
+ bool internal_less (shared_count<T2, VoidAllocator2, Deleter2> const & other) const
+ { return std::less<counted_base_ptr>()(this->m_pi, other.m_pi); }
+};
+
+template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
+bool operator==(shared_count<T, VoidAllocator, Deleter> const & a, shared_count<T2, VoidAllocator2, Deleter2> const & b)
+{ return a.internal_equal(b); }
+
+template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
+bool operator<(shared_count<T, VoidAllocator, Deleter> const & a, shared_count<T2, VoidAllocator2, Deleter2> const & b)
+{ return a.internal_less(b); }
+
+
+template<class T, class VoidAllocator, class Deleter>
+class weak_count
+{
+ public:
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, T>::type pointer;
+
+ private:
+ typedef sp_counted_impl_pd<VoidAllocator, Deleter> counted_impl;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, counted_impl>::type counted_impl_ptr;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, sp_counted_base>::type counted_base_ptr;
+
+ pointer m_px;
+ counted_impl_ptr m_pi;
+
+ template <class T2, class VoidAllocator2, class Deleter2>
+ friend class weak_count;
+
+ template <class T2, class VoidAllocator2, class Deleter2>
+ friend class shared_count;
+
+ public:
+
+ weak_count(): m_px(0), m_pi(0) // nothrow
+ {}
+
+ template <class Y>
+ explicit weak_count(shared_count<Y, VoidAllocator, Deleter> const & r)
+ : m_px(r.m_px), m_pi(r.m_pi) // nothrow
+ { if(m_pi != 0) m_pi->weak_add_ref(); }
+
+ weak_count(weak_count const & r)
+ : m_px(r.m_px), m_pi(r.m_pi) // nothrow
+ { if(m_pi != 0) m_pi->weak_add_ref(); }
+
+ template<class Y>
+ weak_count(weak_count<Y, VoidAllocator, Deleter> const & r)
+ : m_px(r.m_px), m_pi(r.m_pi) // nothrow
+ { if(m_pi != 0) m_pi->weak_add_ref(); }
+
+ ~weak_count() // nothrow
+ { if(m_pi != 0) m_pi->weak_release(); }
+
+ template<class Y>
+ weak_count & operator= (shared_count<Y, VoidAllocator, Deleter> const & r) // nothrow
+ {
+ m_px = r.m_px;
+ counted_impl_ptr tmp = r.m_pi;
+ if(tmp != 0) tmp->weak_add_ref();
+ if(m_pi != 0) m_pi->weak_release();
+ m_pi = tmp;
+ return *this;
+ }
+
+ weak_count & operator= (weak_count const & r) // nothrow
+ {
+ counted_impl_ptr tmp = r.m_pi;
+ if(tmp != 0) tmp->weak_add_ref();
+ if(m_pi != 0) m_pi->weak_release();
+ m_pi = tmp;
+ return *this;
+ }
+
+ void set_pointer(const pointer &ptr)
+ { m_px = ptr; }
+
+ template<class Y>
+ weak_count & operator= (weak_count<Y, VoidAllocator, Deleter> const& r) // nothrow
+ {
+ counted_impl_ptr tmp = r.m_pi;
+ if(tmp != 0) tmp->weak_add_ref();
+ if(m_pi != 0) m_pi->weak_release();
+ m_pi = tmp;
+ return *this;
+ }
+
+ void swap(weak_count & r) // nothrow
+ { detail::do_swap(m_px, r.m_px); detail::do_swap(m_pi, r.m_pi); }
+
+ long use_count() const // nothrow
+ { return m_pi != 0? m_pi->use_count() : 0; }
+
+ template<class T2, class VoidAllocator2, class Deleter2>
+ bool internal_equal (weak_count<T2, VoidAllocator2, Deleter2> const & other) const
+ { return this->m_pi == other.m_pi; }
+
+ template<class T2, class VoidAllocator2, class Deleter2>
+ bool internal_less (weak_count<T2, VoidAllocator2, Deleter2> const & other) const
+ { return std::less<counted_base_ptr>()(this->m_pi, other.m_pi); }
+};
+
+template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
+bool operator==(weak_count<T, VoidAllocator, Deleter> const & a, weak_count<T2, VoidAllocator2, Deleter2> const & b)
+{ return a.internal_equal(b); }
+
+template<class T, class VoidAllocator, class Deleter, class T2, class VoidAllocator2, class Deleter2> inline
+bool operator<(weak_count<T, VoidAllocator, Deleter> const & a, weak_count<T2, VoidAllocator2, Deleter2> const & b)
+{ return a.internal_less(b); }
+
+} // namespace detail
+} // namespace interprocess
+} // namespace boost
+
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+
+#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SHARED_COUNT_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,18 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_SP_COUNTED_BASE_HPP_INCLUDED
+#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED
+
+# include <boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED
+
Added: sandbox/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,92 @@
+#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED
+#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED
+
+// MS compatible compilers support #pragma once
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
+// Copyright 2004-2005 Peter Dimov
+// Copyright 2007-2008 Ion Gaztanaga
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+//
+// Lock-free algorithm by Alexander Terekhov
+//
+// Thanks to Ben Hitchings for the #weak + (#shared != 0)
+// formulation
+//
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/atomic.hpp>
+#include <typeinfo>
+
+namespace boost {
+
+namespace interprocess {
+
+namespace detail {
+
+class sp_counted_base
+{
+private:
+
+ sp_counted_base( sp_counted_base const & );
+ sp_counted_base & operator= ( sp_counted_base const & );
+
+ boost::uint32_t use_count_; // #shared
+ boost::uint32_t weak_count_; // #weak + (#shared != 0)
+
+public:
+
+ sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
+ {}
+
+ ~sp_counted_base() // nothrow
+ {}
+
+ void add_ref_copy()
+ {
+ detail::atomic_inc32( &use_count_ );
+ }
+
+ bool add_ref_lock() // true on success
+ {
+ for( ;; )
+ {
+ boost::uint32_t tmp = static_cast< boost::uint32_t const volatile& >( use_count_ );
+ if( tmp == 0 ) return false;
+ if( detail::atomic_cas32( &use_count_, tmp + 1, tmp ) == tmp )
+ return true;
+ }
+ }
+
+ bool ref_release() // nothrow
+ { return 1 == detail::atomic_dec32( &use_count_ ); }
+
+ void weak_add_ref() // nothrow
+ { detail::atomic_inc32( &weak_count_ ); }
+
+ bool weak_release() // nothrow
+ { return 1 == detail::atomic_dec32( &weak_count_ ); }
+
+ long use_count() const // nothrow
+ { return (long)static_cast<boost::uint32_t const volatile &>( use_count_ ); }
+};
+
+} // namespace detail
+
+} // namespace interprocess
+
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_BASE_ATOMIC_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,117 @@
+#ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
+#define BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
+
+// MS compatible compilers support #pragma once
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+//
+// This file is the adaptation for shared memory memory mapped
+// files of boost/detail/sp_counted_impl.hpp
+//
+// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
+// Copyright 2004-2005 Peter Dimov
+// Copyright 2006 Ion Gaztanaga
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/smart_ptr/detail/sp_counted_base.hpp>
+#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+namespace detail {
+
+template<class A, class D>
+class sp_counted_impl_pd
+ : public sp_counted_base
+ , A::template rebind< sp_counted_impl_pd<A, D> >::other
+ , D // copy constructor must not throw
+{
+ private:
+ typedef sp_counted_impl_pd<A, D> this_type;
+ typedef typename A::template rebind
+ <this_type>::other this_allocator;
+ typedef typename A::template rebind
+ <const this_type>::other const_this_allocator;
+ typedef typename this_allocator::pointer this_pointer;
+
+ sp_counted_impl_pd( sp_counted_impl_pd const & );
+ sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & );
+
+ typedef typename detail::pointer_to_other
+ <typename A::pointer, const D>::type const_deleter_pointer;
+
+ typedef typename detail::pointer_to_other
+ <typename A::pointer, const A>::type const_allocator_pointer;
+
+ typedef typename D::pointer pointer;
+ pointer m_ptr;
+
+ public:
+ // pre: d(p) must not throw
+ template<class Ptr>
+ sp_counted_impl_pd(const Ptr & p, const A &a, const D &d )
+ : this_allocator(a), D(d), m_ptr(p)
+ {}
+
+ const_deleter_pointer get_deleter() const
+ { return const_deleter_pointer(&static_cast<const D&>(*this)); }
+
+ const_allocator_pointer get_allocator() const
+ { return const_allocator_pointer(&static_cast<const A&>(*this)); }
+
+ void dispose() // nothrow
+ { static_cast<D&>(*this)(m_ptr); }
+
+ void destroy() // nothrow
+ {
+ //Self destruction, so get a copy of the allocator
+ //(in the future we could move it)
+ this_allocator a_copy(*this);
+ BOOST_ASSERT(a_copy == *this);
+ this_pointer this_ptr (this);
+ //Do it now!
+ scoped_ptr< this_type, scoped_ptr_dealloc_functor<this_allocator> >
+ deleter(this_ptr, a_copy);
+ typedef typename this_allocator::value_type value_type;
+ detail::get_pointer(this_ptr)->~value_type();
+ }
+
+ void release() // nothrow
+ {
+ if(this->ref_release()){
+ this->dispose();
+ this->weak_release();
+ }
+ }
+
+ void weak_release() // nothrow
+ {
+ if(sp_counted_base::weak_release()){
+ this->destroy();
+ }
+ }
+};
+
+
+} // namespace detail
+
+} // namespace interprocess
+
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_DETAIL_SP_COUNTED_IMPL_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/enable_shared_from_this.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/enable_shared_from_this.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,79 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/enable_shared_from_this.hpp
+//
+// (C) Copyright Peter Dimov 2002
+// (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_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
+#define BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
+
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/detail/config_begin.hpp>
+
+#include <boost/assert.hpp>
+#include <boost/interprocess/smart_ptr/weak_ptr.hpp>
+#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
+
+//!\file
+//!Describes an utility to form a shared pointer from this
+
+namespace boost{
+namespace interprocess{
+
+//!This class is used as a base class that allows a shared_ptr to the current
+//!object to be obtained from within a member function.
+//!enable_shared_from_this defines two member functions called shared_from_this
+//!that return a shared_ptr<T> and shared_ptr<T const>, depending on constness, to this.
+template<class T, class A, class D>
+class enable_shared_from_this
+{
+ /// @cond
+ protected:
+ enable_shared_from_this()
+ {}
+
+ enable_shared_from_this(enable_shared_from_this const &)
+ {}
+
+ enable_shared_from_this & operator=(enable_shared_from_this const &)
+ { return *this; }
+
+ ~enable_shared_from_this()
+ {}
+ /// @endcond
+
+ public:
+ shared_ptr<T, A, D> shared_from_this()
+ {
+ shared_ptr<T, A, D> p(_internal_weak_this);
+ BOOST_ASSERT(detail::get_pointer(p.get()) == this);
+ return p;
+ }
+
+ shared_ptr<T const, A, D> shared_from_this() const
+ {
+ shared_ptr<T const, A, D> p(_internal_weak_this);
+ BOOST_ASSERT(detail::get_pointer(p.get()) == this);
+ return p;
+ }
+
+ /// @cond
+ typedef T element_type;
+ mutable weak_ptr<element_type, A, D> _internal_weak_this;
+ /// @endcond
+};
+
+} // namespace interprocess
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
+
Added: sandbox/boost/interprocess/smart_ptr/intrusive_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/intrusive_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,293 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/intrusive_ptr.hpp
+//
+// (C) Copyright Peter Dimov 2001, 2002
+// (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_INTRUSIVE_PTR_HPP_INCLUDED
+#define BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED
+
+//!\file
+//!Describes an intrusive ownership pointer.
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/assert.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+
+#include <functional> // for std::less
+#include <iosfwd> // for std::basic_ostream
+
+
+namespace boost {
+namespace interprocess {
+
+//!The intrusive_ptr class template stores a pointer to an object
+//!with an embedded reference count. intrusive_ptr is parameterized on
+//!T (the type of the object pointed to) and VoidPointer(a void pointer type
+//!that defines the type of pointer that intrusive_ptr will store).
+//!intrusive_ptr<T, void *> defines a class with a T* member whereas
+//!intrusive_ptr<T, offset_ptr<void> > defines a class with a offset_ptr<T> member.
+//!Relies on unqualified calls to:
+//!
+//! void intrusive_ptr_add_ref(T * p);
+//! void intrusive_ptr_release(T * p);
+//!
+//! with (p != 0)
+//!
+//!The object is responsible for destroying itself.
+template<class T, class VoidPointer>
+class intrusive_ptr
+{
+ public:
+ //!Provides the type of the internal stored pointer.
+ typedef typename detail::pointer_to_other<VoidPointer, T>::type pointer;
+ //!Provides the type of the stored pointer.
+ typedef T element_type;
+
+ /// @cond
+ private:
+ typedef VoidPointer VP;
+ typedef intrusive_ptr this_type;
+ typedef pointer this_type::*unspecified_bool_type;
+ /// @endcond
+
+ public:
+ //!Constructor. Initializes internal pointer to 0.
+ //!Does not throw
+ intrusive_ptr(): m_ptr(0)
+ {}
+
+ //!Constructor. Copies pointer and if "p" is not zero and
+ //!"add_ref" is true calls intrusive_ptr_add_ref(get_pointer(p)).
+ //!Does not throw
+ intrusive_ptr(const pointer &p, bool add_ref = true): m_ptr(p)
+ {
+ if(m_ptr != 0 && add_ref) intrusive_ptr_add_ref(detail::get_pointer(m_ptr));
+ }
+
+ //!Copy constructor. Copies the internal pointer and if "p" is not
+ //!zero calls intrusive_ptr_add_ref(get_pointer(p)). Does not throw
+ intrusive_ptr(intrusive_ptr const & rhs)
+ : m_ptr(rhs.m_ptr)
+ {
+ if(m_ptr != 0) intrusive_ptr_add_ref(detail::get_pointer(m_ptr));
+ }
+
+ //!Constructor from related. Copies the internal pointer and if "p" is not
+ //!zero calls intrusive_ptr_add_ref(get_pointer(p)). Does not throw
+ template<class U> intrusive_ptr
+ (intrusive_ptr<U, VP> const & rhs)
+ : m_ptr(rhs.get())
+ {
+ if(m_ptr != 0) intrusive_ptr_add_ref(detail::get_pointer(m_ptr));
+ }
+
+ //!Destructor. If internal pointer is not 0, calls
+ //!intrusive_ptr_release(get_pointer(m_ptr)). Does not throw
+ ~intrusive_ptr()
+ {
+ if(m_ptr != 0) intrusive_ptr_release(detail::get_pointer(m_ptr));
+ }
+
+ //!Assignment operator. Equivalent to intrusive_ptr(r).swap(*this).
+ //!Does not throw
+ intrusive_ptr & operator=(intrusive_ptr const & rhs)
+ {
+ this_type(rhs).swap(*this);
+ return *this;
+ }
+
+ //!Assignment from related. Equivalent to intrusive_ptr(r).swap(*this).
+ //!Does not throw
+ template<class U> intrusive_ptr & operator=
+ (intrusive_ptr<U, VP> const & rhs)
+ {
+ this_type(rhs).swap(*this);
+ return *this;
+ }
+
+ //!Assignment from pointer. Equivalent to intrusive_ptr(r).swap(*this).
+ //!Does not throw
+ intrusive_ptr & operator=(pointer rhs)
+ {
+ this_type(rhs).swap(*this);
+ return *this;
+ }
+
+ //!Returns a reference to the internal pointer.
+ //!Does not throw
+ pointer &get()
+ { return m_ptr; }
+
+ //!Returns a reference to the internal pointer.
+ //!Does not throw
+ const pointer &get() const
+ { return m_ptr; }
+
+ //!Returns *get().
+ //!Does not throw
+ T & operator*() const
+ { return *m_ptr; }
+
+ //!Returns *get().
+ //!Does not throw
+ const pointer &operator->() const
+ { return m_ptr; }
+
+ //!Returns get().
+ //!Does not throw
+ pointer &operator->()
+ { return m_ptr; }
+
+ //!Conversion to boolean.
+ //!Does not throw
+ operator unspecified_bool_type () const
+ { return m_ptr == 0? 0: &this_type::m_ptr; }
+
+ //!Not operator.
+ //!Does not throw
+ bool operator! () const
+ { return m_ptr == 0; }
+
+ //!Exchanges the contents of the two smart pointers.
+ //!Does not throw
+ void swap(intrusive_ptr & rhs)
+ { detail::do_swap(m_ptr, rhs.m_ptr); }
+
+ /// @cond
+ private:
+ pointer m_ptr;
+ /// @endcond
+};
+
+//!Returns a.get() == b.get().
+//!Does not throw
+template<class T, class U, class VP> inline
+bool operator==(intrusive_ptr<T, VP> const & a,
+ intrusive_ptr<U, VP> const & b)
+{ return a.get() == b.get(); }
+
+//!Returns a.get() != b.get().
+//!Does not throw
+template<class T, class U, class VP> inline
+bool operator!=(intrusive_ptr<T, VP> const & a,
+ intrusive_ptr<U, VP> const & b)
+{ return a.get() != b.get(); }
+
+//!Returns a.get() == b.
+//!Does not throw
+template<class T, class VP> inline
+bool operator==(intrusive_ptr<T, VP> const & a,
+ const typename intrusive_ptr<T, VP>::pointer &b)
+{ return a.get() == b; }
+
+//!Returns a.get() != b.
+//!Does not throw
+template<class T, class VP> inline
+bool operator!=(intrusive_ptr<T, VP> const & a,
+ const typename intrusive_ptr<T, VP>::pointer &b)
+{ return a.get() != b; }
+
+//!Returns a == b.get().
+//!Does not throw
+template<class T, class VP> inline
+bool operator==(const typename intrusive_ptr<T, VP>::pointer &a,
+ intrusive_ptr<T, VP> const & b)
+{ return a == b.get(); }
+
+//!Returns a != b.get().
+//!Does not throw
+template<class T, class VP> inline
+bool operator!=(const typename intrusive_ptr<T, VP>::pointer &a,
+ intrusive_ptr<T, VP> const & b)
+{ return a != b.get(); }
+
+//!Returns a.get() < b.get().
+//!Does not throw
+template<class T, class VP> inline
+bool operator<(intrusive_ptr<T, VP> const & a,
+ intrusive_ptr<T, VP> const & b)
+{
+ return std::less<typename intrusive_ptr<T, VP>::pointer>()
+ (a.get(), b.get());
+}
+
+//!Exchanges the contents of the two intrusive_ptrs.
+//!Does not throw
+template<class T, class VP> inline
+void swap(intrusive_ptr<T, VP> & lhs,
+ intrusive_ptr<T, VP> & rhs)
+{ lhs.swap(rhs); }
+
+// operator<<
+template<class E, class T, class Y, class VP>
+inline std::basic_ostream<E, T> & operator<<
+ (std::basic_ostream<E, T> & os, intrusive_ptr<Y, VP> const & p)
+{ os << p.get(); return os; }
+
+//!Returns p.get().
+//!Does not throw
+template<class T, class VP>
+inline typename boost::interprocess::intrusive_ptr<T, VP>::pointer
+ get_pointer(intrusive_ptr<T, VP> p)
+{ return p.get(); }
+
+/*Emulates static cast operator. Does not throw*/
+/*
+template<class T, class U, class VP>
+inline boost::interprocess::intrusive_ptr<T, VP> static_pointer_cast
+ (boost::interprocess::intrusive_ptr<U, VP> const & p)
+{ return do_static_cast<U>(p.get()); }
+*/
+/*Emulates const cast operator. Does not throw*/
+/*
+template<class T, class U, class VP>
+inline boost::interprocess::intrusive_ptr<T, VP> const_pointer_cast
+ (boost::interprocess::intrusive_ptr<U, VP> const & p)
+{ return do_const_cast<U>(p.get()); }
+*/
+
+/*Emulates dynamic cast operator. Does not throw*/
+/*
+template<class T, class U, class VP>
+inline boost::interprocess::intrusive_ptr<T, VP> dynamic_pointer_cast
+ (boost::interprocess::intrusive_ptr<U, VP> const & p)
+{ return do_dynamic_cast<U>(p.get()); }
+*/
+
+/*Emulates reinterpret cast operator. Does not throw*/
+/*
+template<class T, class U, class VP>
+inline boost::interprocess::intrusive_ptr<T, VP>reinterpret_pointer_cast
+ (boost::interprocess::intrusive_ptr<U, VP> const & p)
+{ return do_reinterpret_cast<U>(p.get()); }
+*/
+
+} // namespace interprocess
+
+/// @cond
+
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+//!Returns p.get().
+//!Does not throw
+template<class T, class VP>
+inline T *get_pointer(boost::interprocess::intrusive_ptr<T, VP> p)
+{ return p.get(); }
+#endif
+
+/// @endcond
+
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_INTRUSIVE_PTR_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/scoped_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/scoped_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,167 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/scoped_ptr.hpp
+//
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// (C) Copyright Peter Dimov 2001, 2002
+// (C) Copyright Ion 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_SCOPED_PTR_HPP_INCLUDED
+#define BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/detail/pointer_type.hpp>
+#include <boost/assert.hpp>
+
+//!\file
+//!Describes the smart pointer scoped_ptr
+
+namespace boost {
+namespace interprocess {
+
+//!scoped_ptr stores a pointer to a dynamically allocated object.
+//!The object pointed to is guaranteed to be deleted, either on destruction
+//!of the scoped_ptr, or via an explicit reset. The user can avoid this
+//!deletion using release().
+//!scoped_ptr is parameterized on T (the type of the object pointed to) and
+//!Deleter (the functor to be executed to delete the internal pointer).
+//!The internal pointer will be of the same pointer type as typename
+//!Deleter::pointer type (that is, if typename Deleter::pointer is
+//!offset_ptr<void>, the internal pointer will be offset_ptr<T>).
+template<class T, class Deleter>
+class scoped_ptr
+ : private Deleter
+{
+ /// @cond
+ scoped_ptr(scoped_ptr const &);
+ scoped_ptr & operator=(scoped_ptr const &);
+
+ typedef scoped_ptr<T, Deleter> this_type;
+ typedef typename detail::add_reference<T>::type reference;
+ /// @endcond
+
+ public:
+
+ typedef T element_type;
+ typedef Deleter deleter_type;
+ typedef typename detail::pointer_type<T, Deleter>::type pointer;
+
+ //!Provides the type of the internal stored pointer
+// typedef typename detail::pointer_to_other
+// <typename Deleter::pointer, T>::type pointer;
+
+ //!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d.
+ //!Does not throw.
+ explicit scoped_ptr(const pointer &p = 0, const Deleter &d = Deleter())
+ : Deleter(d), m_ptr(p) // throws if pointer/Deleter copy ctor throws
+ {}
+
+ //!If the stored pointer is not 0, destroys the object pointed to by the stored pointer.
+ //!calling the operator() of the stored deleter. Never throws
+ ~scoped_ptr()
+ {
+ if(m_ptr){
+ Deleter &del = static_cast<Deleter&>(*this);
+ del(m_ptr);
+ }
+ }
+
+ //!Deletes the object pointed to by the stored pointer and then
+ //!stores a copy of p. Never throws
+ void reset(const pointer &p = 0) // never throws
+ { BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); }
+
+ //!Deletes the object pointed to by the stored pointer and then
+ //!stores a copy of p and a copy of d.
+ void reset(const pointer &p, const Deleter &d) // never throws
+ { BOOST_ASSERT(p == 0 || p != m_ptr); this_type(p).swap(*this); }
+
+ //!Assigns internal pointer as 0 and returns previous pointer. This will
+ //!avoid deletion on destructor
+ pointer release()
+ { pointer tmp(m_ptr); m_ptr = 0; return tmp; }
+
+ //!Returns a reference to the object pointed to by the stored pointer.
+ //!Never throws.
+ reference operator*() const
+ { BOOST_ASSERT(m_ptr != 0); return *m_ptr; }
+
+ //!Returns the internal stored pointer.
+ //!Never throws.
+ pointer &operator->()
+ { BOOST_ASSERT(m_ptr != 0); return m_ptr; }
+
+ //!Returns the internal stored pointer.
+ //!Never throws.
+ const pointer &operator->() const
+ { BOOST_ASSERT(m_ptr != 0); return m_ptr; }
+
+ //!Returns the stored pointer.
+ //!Never throws.
+ pointer & get()
+ { return m_ptr; }
+
+ //!Returns the stored pointer.
+ //!Never throws.
+ const pointer & get() const
+ { return m_ptr; }
+
+ typedef pointer this_type::*unspecified_bool_type;
+
+ //!Conversion to bool
+ //!Never throws
+ operator unspecified_bool_type() const
+ { return m_ptr == 0? 0: &this_type::m_ptr; }
+
+ //!Returns true if the stored pointer is 0.
+ //!Never throws.
+ bool operator! () const // never throws
+ { return m_ptr == 0; }
+
+ //!Exchanges the internal pointer and deleter with other scoped_ptr
+ //!Never throws.
+ void swap(scoped_ptr & b) // never throws
+ { detail::do_swap<Deleter>(*this, b); detail::do_swap(m_ptr, b.m_ptr); }
+
+ /// @cond
+ private:
+ pointer m_ptr;
+ /// @endcond
+};
+
+//!Exchanges the internal pointer and deleter with other scoped_ptr
+//!Never throws.
+template<class T, class D> inline
+void swap(scoped_ptr<T, D> & a, scoped_ptr<T, D> & b)
+{ a.swap(b); }
+
+//!Returns a copy of the stored pointer
+//!Never throws
+template<class T, class D> inline
+typename scoped_ptr<T, D>::pointer get_pointer(scoped_ptr<T, D> const & p)
+{ return p.get(); }
+
+} // namespace interprocess
+
+/// @cond
+
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+template<class T, class D> inline
+T *get_pointer(boost::interprocess::scoped_ptr<T, D> const & p)
+{ return p.get(); }
+#endif
+
+/// @endcond
+
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_SCOPED_PTR_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/shared_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/shared_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,393 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/shared_ptr.hpp
+//
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// (C) Copyright Peter Dimov 2001, 2002, 2003
+// (C) Copyright Ion Gaztanaga 2006-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_SHARED_PTR_HPP_INCLUDED
+#define BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/cast_tags.hpp>
+#include <boost/assert.hpp>
+#include <boost/interprocess/smart_ptr/detail/shared_count.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/allocators/allocator.hpp>
+#include <boost/interprocess/smart_ptr/deleter.hpp>
+#include <boost/static_assert.hpp>
+
+#include <algorithm> // for std::swap
+#include <functional> // for std::less
+#include <typeinfo> // for std::bad_cast
+#include <iosfwd> // for std::basic_ostream
+
+//!\file
+//!Describes the smart pointer shared_ptr
+
+namespace boost{
+namespace interprocess{
+
+template<class T, class VoidAllocator, class Deleter> class weak_ptr;
+template<class T, class VoidAllocator, class Deleter> class enable_shared_from_this;
+
+namespace detail{
+
+template<class T, class VoidAllocator, class Deleter>
+inline void sp_enable_shared_from_this
+ (shared_count<T, VoidAllocator, Deleter> const & pn
+ ,enable_shared_from_this<T, VoidAllocator, Deleter> *pe
+ ,T *ptr)
+
+{
+ (void)ptr;
+ if(pe != 0){
+ pe->_internal_weak_this._internal_assign(pn);
+ }
+}
+
+template<class T, class VoidAllocator, class Deleter>
+inline void sp_enable_shared_from_this(shared_count<T, VoidAllocator, Deleter> const &, ...)
+{}
+
+} // namespace detail
+
+//!shared_ptr stores a pointer to a dynamically allocated object.
+//!The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to
+//!it is destroyed or reset.
+//!
+//!shared_ptr is parameterized on
+//!T (the type of the object pointed to), VoidAllocator (the void allocator to be used
+//!to allocate the auxiliary data) and Deleter (the deleter whose
+//!operator() will be used to delete the object.
+//!
+//!The internal pointer will be of the same pointer type as typename
+//!VoidAllocator::pointer type (that is, if typename VoidAllocator::pointer is
+//!offset_ptr<void>, the internal pointer will be offset_ptr<T>).
+//!
+//!Because the implementation uses reference counting, cycles of shared_ptr
+//!instances will not be reclaimed. For example, if main() holds a
+//!shared_ptr to A, which directly or indirectly holds a shared_ptr back
+//!to A, A's use count will be 2. Destruction of the original shared_ptr
+//!will leave A dangling with a use count of 1.
+//!Use weak_ptr to "break cycles."
+template<class T, class VoidAllocator, class Deleter>
+class shared_ptr
+{
+ /// @cond
+ private:
+ typedef shared_ptr<T, VoidAllocator, Deleter> this_type;
+ /// @endcond
+
+ public:
+
+ typedef T element_type;
+ typedef T value_type;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, T>::type pointer;
+ typedef typename detail::add_reference
+ <value_type>::type reference;
+ typedef typename detail::add_reference
+ <const value_type>::type const_reference;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, const Deleter>::type const_deleter_pointer;
+ typedef typename detail::pointer_to_other
+ <typename VoidAllocator::pointer, const VoidAllocator>::type const_allocator_pointer;
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(shared_ptr)
+
+ //!Constructs an empty shared_ptr.
+ //!Use_count() == 0 && get()== 0.
+ shared_ptr()
+ : m_pn() // never throws
+ {}
+
+ //!Constructs a shared_ptr that owns the pointer p. Auxiliary data will be allocated
+ //!with a copy of a and the object will be deleted with a copy of d.
+ //!Requirements: Deleter and A's copy constructor must not throw.
+ explicit shared_ptr(const pointer&p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter())
+ : m_pn(p, a, d)
+ {
+ //Check that the pointer passed is of the same type that
+ //the pointer the allocator defines or it's a raw pointer
+ typedef typename detail::pointer_to_other<pointer, T>::type ParameterPointer;
+ BOOST_STATIC_ASSERT((detail::is_same<pointer, ParameterPointer>::value) ||
+ (detail::is_pointer<pointer>::value));
+ detail::sp_enable_shared_from_this<T, VoidAllocator, Deleter>( m_pn, detail::get_pointer(p), detail::get_pointer(p) );
+ }
+
+
+ //!Constructs a shared_ptr that shares ownership with r and stores p.
+ //!Postconditions: get() == p && use_count() == r.use_count().
+ //!Throws: nothing.
+ shared_ptr(const shared_ptr &other, const pointer &p)
+ : m_pn(other.m_pn, p)
+ {}
+
+ //!If r is empty, constructs an empty shared_ptr. Otherwise, constructs
+ //!a shared_ptr that shares ownership with r. Never throws.
+ template<class Y>
+ shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r)
+ : m_pn(r.m_pn) // never throws
+ {}
+
+ //!Constructs a shared_ptr that shares ownership with r and stores
+ //!a copy of the pointer stored in r.
+ template<class Y>
+ explicit shared_ptr(weak_ptr<Y, VoidAllocator, Deleter> const & r)
+ : m_pn(r.m_pn) // may throw
+ {}
+
+ //!Move-Constructs a shared_ptr that takes ownership of other resource and
+ //!other is put in default-constructed state.
+ //!Throws: nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ explicit shared_ptr(boost::rv<shared_ptr> &other)
+ : m_pn()
+ { this->swap(other.get()); }
+ #else
+ explicit shared_ptr(shared_ptr &&other)
+ : m_pn()
+ { this->swap(other); }
+ #endif
+
+ /// @cond
+ template<class Y>
+ shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, detail::static_cast_tag)
+ : m_pn( pointer(static_cast<T*>(detail::get_pointer(r.m_pn.get_pointer())))
+ , r.m_pn)
+ {}
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, detail::const_cast_tag)
+ : m_pn( pointer(const_cast<T*>(detail::get_pointer(r.m_pn.get_pointer())))
+ , r.m_pn)
+ {}
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y, VoidAllocator, Deleter> const & r, detail::dynamic_cast_tag)
+ : m_pn( pointer(dynamic_cast<T*>(detail::get_pointer(r.m_pn.get_pointer())))
+ , r.m_pn)
+ {
+ if(!m_pn.get_pointer()){ // need to allocate new counter -- the cast failed
+ m_pn = detail::shared_count<T, VoidAllocator, Deleter>();
+ }
+ }
+ /// @endcond
+
+ //!Equivalent to shared_ptr(r).swap(*this).
+ //!Never throws
+ template<class Y>
+ shared_ptr & operator=(shared_ptr<Y, VoidAllocator, Deleter> const & r)
+ {
+ m_pn = r.m_pn; // shared_count::op= doesn't throw
+ return *this;
+ }
+
+ //!Move-assignment. Equivalent to shared_ptr(other).swap(*this).
+ //!Never throws
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ shared_ptr & operator=(boost::rv<shared_ptr> &other) // never throws
+ {
+ this_type(other).swap(*this);
+ return *this;
+ }
+ #else
+ shared_ptr & operator=(shared_ptr &&other) // never throws
+ {
+ this_type(other).swap(*this);
+ return *this;
+ }
+ #endif
+
+ //!This is equivalent to:
+ //!this_type().swap(*this);
+ void reset()
+ {
+ this_type().swap(*this);
+ }
+
+ //!This is equivalent to:
+ //!this_type(p, a, d).swap(*this);
+ template<class Pointer>
+ void reset(const Pointer &p, const VoidAllocator &a = VoidAllocator(), const Deleter &d = Deleter())
+ {
+ //Check that the pointer passed is of the same type that
+ //the pointer the allocator defines or it's a raw pointer
+ typedef typename detail::pointer_to_other<Pointer, T>::type ParameterPointer;
+ BOOST_STATIC_ASSERT((detail::is_same<pointer, ParameterPointer>::value) ||
+ (detail::is_pointer<Pointer>::value));
+ this_type(p, a, d).swap(*this);
+ }
+
+ template<class Y>
+ void reset(shared_ptr<Y, VoidAllocator, Deleter> const & r, const pointer &p)
+ {
+ this_type(r, p).swap(*this);
+ }
+
+ //!Returns a reference to the
+ //!pointed type
+ reference operator* () const // never throws
+ { BOOST_ASSERT(m_pn.get_pointer() != 0); return *m_pn.get_pointer(); }
+
+ //!Returns the pointer pointing
+ //!to the owned object
+ pointer operator-> () const // never throws
+ { BOOST_ASSERT(m_pn.get_pointer() != 0); return m_pn.get_pointer(); }
+
+ //!Returns the pointer pointing
+ //!to the owned object
+ pointer get() const // never throws
+ { return m_pn.get_pointer(); }
+
+ /// @cond
+ // implicit conversion to "bool"
+ void unspecified_bool_type_func() const {}
+ typedef void (this_type::*unspecified_bool_type)() const;
+
+ operator unspecified_bool_type() const // never throws
+ { return !m_pn.get_pointer() ? 0 : &this_type::unspecified_bool_type_func; }
+ /// @endcond
+
+ //!Not operator.
+ //!Returns true if this->get() != 0, false otherwise
+ bool operator! () const // never throws
+ { return !m_pn.get_pointer(); }
+
+ //!Returns use_count() == 1.
+ //!unique() might be faster than use_count()
+ bool unique() const // never throws
+ { return m_pn.unique(); }
+
+ //!Returns the number of shared_ptr objects, *this included,
+ //!that share ownership with *this, or an unspecified nonnegative
+ //!value when *this is empty.
+ //!use_count() is not necessarily efficient. Use only for
+ //!debugging and testing purposes, not for production code.
+ long use_count() const // never throws
+ { return m_pn.use_count(); }
+
+ //!Exchanges the contents of the two
+ //!smart pointers.
+ void swap(shared_ptr<T, VoidAllocator, Deleter> & other) // never throws
+ { m_pn.swap(other.m_pn); }
+
+ /// @cond
+
+ template<class T2, class A2, class Deleter2>
+ bool _internal_less(shared_ptr<T2, A2, Deleter2> const & rhs) const
+ { return m_pn < rhs.m_pn; }
+
+ const_deleter_pointer get_deleter() const
+ { return m_pn.get_deleter(); }
+
+// const_allocator_pointer get_allocator() const
+// { return m_pn.get_allocator(); }
+
+ private:
+
+ template<class T2, class A2, class Deleter2> friend class shared_ptr;
+ template<class T2, class A2, class Deleter2> friend class weak_ptr;
+
+ detail::shared_count<T, VoidAllocator, Deleter> m_pn; // reference counter
+ /// @endcond
+}; // shared_ptr
+
+template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
+bool operator==(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
+{ return a.get() == b.get(); }
+
+template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
+bool operator!=(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
+{ return a.get() != b.get(); }
+
+template<class T, class VoidAllocator, class Deleter, class U, class VoidAllocator2, class Deleter2> inline
+bool operator<(shared_ptr<T, VoidAllocator, Deleter> const & a, shared_ptr<U, VoidAllocator2, Deleter2> const & b)
+{ return a._internal_less(b); }
+
+template<class T, class VoidAllocator, class Deleter> inline
+void swap(shared_ptr<T, VoidAllocator, Deleter> & a, shared_ptr<T, VoidAllocator, Deleter> & b)
+{ a.swap(b); }
+
+template<class T, class VoidAllocator, class Deleter, class U> inline
+shared_ptr<T, VoidAllocator, Deleter> static_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
+{ return shared_ptr<T, VoidAllocator, Deleter>(r, detail::static_cast_tag()); }
+
+template<class T, class VoidAllocator, class Deleter, class U> inline
+shared_ptr<T, VoidAllocator, Deleter> const_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
+{ return shared_ptr<T, VoidAllocator, Deleter>(r, detail::const_cast_tag()); }
+
+template<class T, class VoidAllocator, class Deleter, class U> inline
+shared_ptr<T, VoidAllocator, Deleter> dynamic_pointer_cast(shared_ptr<U, VoidAllocator, Deleter> const & r)
+{ return shared_ptr<T, VoidAllocator, Deleter>(r, detail::dynamic_cast_tag()); }
+
+// get_pointer() enables boost::mem_fn to recognize shared_ptr
+template<class T, class VoidAllocator, class Deleter> inline
+T * get_pointer(shared_ptr<T, VoidAllocator, Deleter> const & p)
+{ return p.get(); }
+
+// operator<<
+template<class E, class T, class Y, class VoidAllocator, class Deleter> inline
+std::basic_ostream<E, T> & operator<<
+ (std::basic_ostream<E, T> & os, shared_ptr<Y, VoidAllocator, Deleter> const & p)
+{ os << p.get(); return os; }
+
+//!Returns the type of a shared pointer
+//!of type T with the allocator boost::interprocess::allocator allocator
+//!and boost::interprocess::deleter deleter
+//!that can be constructed in the given managed segment type.
+template<class T, class ManagedMemory>
+struct managed_shared_ptr
+{
+ typedef typename ManagedMemory::template allocator<void>::type void_allocator;
+ typedef typename ManagedMemory::template deleter<T>::type deleter;
+ typedef shared_ptr< T, void_allocator, deleter> type;
+};
+
+//!Returns an instance of a shared pointer constructed
+//!with the default allocator and deleter from a pointer
+//!of type T that has been allocated in the passed managed segment
+template<class T, class ManagedMemory>
+inline typename managed_shared_ptr<T, ManagedMemory>::type
+ make_managed_shared_ptr(T *constructed_object, ManagedMemory &managed_memory)
+{
+ return typename managed_shared_ptr<T, ManagedMemory>::type
+ ( constructed_object
+ , managed_memory.template get_allocator<void>()
+ , managed_memory.template get_deleter<T>()
+ );
+}
+
+} // namespace interprocess
+
+/// @cond
+
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+// get_pointer() enables boost::mem_fn to recognize shared_ptr
+template<class T, class VoidAllocator, class Deleter> inline
+T * get_pointer(boost::interprocess::shared_ptr<T, VoidAllocator, Deleter> const & p)
+{ return p.get(); }
+#endif
+
+/// @endcond
+
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_SHARED_PTR_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/unique_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/unique_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,603 @@
+//////////////////////////////////////////////////////////////////////////////
+// I, Howard Hinnant, hereby place this code in the public domain.
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of
+// Howard Hinnant's unique_ptr emulation code.
+//
+// (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_UNIQUE_PTR_HPP_INCLUDED
+#define BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/assert.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/pointer_type.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/compressed_pair.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/smart_ptr/deleter.hpp>
+#include <cstddef>
+
+//!\file
+//!Describes the smart pointer unique_ptr
+
+namespace boost{
+namespace interprocess{
+
+/// @cond
+template <class T, class D> class unique_ptr;
+
+namespace detail {
+
+template <class T> struct unique_ptr_error;
+
+template <class T, class D>
+struct unique_ptr_error<const unique_ptr<T, D> >
+{
+ typedef unique_ptr<T, D> type;
+};
+
+} //namespace detail {
+/// @endcond
+
+//!Template unique_ptr stores a pointer to an object and deletes that object
+//!using the associated deleter when it is itself destroyed (such as when
+//!leaving block scope.
+//!
+//!The unique_ptr provides a semantics of strict ownership. A unique_ptr owns the
+//!object it holds a pointer to.
+//!
+//!A unique_ptr is not CopyConstructible, nor CopyAssignable, however it is
+//!MoveConstructible and Move-Assignable.
+//!
+//!The uses of unique_ptr include providing exception safety for dynamically
+//!allocated memory, passing ownership of dynamically allocated memory to a
+//!function, and returning dynamically allocated memory from a function
+//!
+//!A client-supplied template argument D must be a
+//!function pointer or functor for which, given a value d of type D and a pointer
+//!ptr to a type T*, the expression d(ptr) is
+//!valid and has the effect of deallocating the pointer as appropriate for that
+//!deleter. D may also be an lvalue-reference to a deleter.
+//!
+//!If the deleter D maintains state, it is intended that this state stay with
+//!the associated pointer as ownership is transferred
+//!from unique_ptr to unique_ptr. The deleter state need never be copied,
+//!only moved or swapped as pointer ownership
+//!is moved around. That is, the deleter need only be MoveConstructible,
+//!MoveAssignable, and Swappable, and need not be CopyConstructible
+//!(unless copied into the unique_ptr) nor CopyAssignable.
+template <class T, class D>
+class unique_ptr
+{
+ /// @cond
+ struct nat {int for_bool_;};
+ typedef typename detail::add_reference<D>::type deleter_reference;
+ typedef typename detail::add_reference<const D>::type deleter_const_reference;
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(unique_ptr)
+
+ typedef T element_type;
+ typedef D deleter_type;
+ typedef typename detail::pointer_type<T, D>::type pointer;
+
+ //!Requires: D must be default constructible, and that construction must not
+ //!throw an exception. D must not be a reference type.
+ //!
+ //!Effects: Constructs a unique_ptr which owns nothing.
+ //!
+ //!Postconditions: get() == 0. get_deleter() returns a reference to a
+ //!default constructed deleter D.
+ //!
+ //!Throws: nothing.
+ unique_ptr()
+ : ptr_(pointer(0))
+ {}
+
+ //!Requires: The expression D()(p) must be well formed. The default constructor
+ //!of D must not throw an exception.
+ //!
+ //!D must not be a reference type.
+ //!
+ //!Effects: Constructs a unique_ptr which owns p.
+ //!
+ //!Postconditions: get() == p. get_deleter() returns a reference to a default constructed deleter D.
+ //!
+ //!Throws: nothing.
+ explicit unique_ptr(pointer p)
+ : ptr_(p)
+ {}
+
+ //!Requires: The expression d(p) must be well formed.
+ //!
+ //!Postconditions: get() == p. get_deleter() returns a reference to the
+ //!internally stored deleter. If D is a
+ //!reference type then get_deleter() returns a reference to the lvalue d.
+ //!
+ //!Throws: nothing.
+ unique_ptr(pointer p
+ ,typename detail::if_<detail::is_reference<D>
+ ,D
+ ,typename detail::add_reference<const D>::type>::type d)
+ : ptr_(p, d)
+ {}
+
+ //!Requires: If the deleter is not a reference type, construction of the
+ //!deleter D from an lvalue D must not throw an exception.
+ //!
+ //!Effects: Constructs a unique_ptr which owns the pointer which u owns
+ //!(if any). If the deleter is not a reference type, it is move constructed
+ //!from u's deleter, otherwise the reference is copy constructed from u's deleter.
+ //!
+ //!After the construction, u no longer owns a pointer.
+ //![ Note: The deleter constructor can be implemented with
+ //! boost::forward_constructor<D>. -end note ]
+ //!
+ //!Postconditions: get() == value u.get() had before the construction.
+ //!get_deleter() returns a reference to the internally stored deleter which
+ //!was constructed from u.get_deleter(). If D is a reference type then get_-
+ //!deleter() and u.get_deleter() both reference the same lvalue deleter.
+ //!
+ //!Throws: nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ unique_ptr(boost::rv<unique_ptr> &u)
+ : ptr_(u.get().release(), boost::move(u.get().get_deleter()))
+ {}
+ #else
+ unique_ptr(unique_ptr &&u)
+ : ptr_(u.release(), boost::forward_constructor<D>(u.get_deleter()))
+ {}
+ #endif
+
+ //!Requires: If D is not a reference type, construction of the deleter
+ //!D from an rvalue of type E must be well formed
+ //!and not throw an exception. If D is a reference type, then E must be
+ //!the same type as D (diagnostic required). unique_ptr<U, E>::pointer
+ //!must be implicitly convertible to pointer.
+ //!
+ //!Effects: Constructs a unique_ptr which owns the pointer which u owns
+ //!(if any). If the deleter is not a reference
+ //!type, it is move constructed from u's deleter, otherwise the reference
+ //!is copy constructed from u's deleter.
+ //!
+ //!After the construction, u no longer owns a pointer.
+ //!
+ //!postconditions get() == value u.get() had before the construction,
+ //!modulo any required offset adjustments
+ //!resulting from the cast from U* to T*. get_deleter() returns a reference to the internally stored deleter which
+ //!was constructed from u.get_deleter().
+ //!
+ //!Throws: nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template <class U, class E>
+ unique_ptr(boost::rv<unique_ptr<U, E> > &u,
+ typename detail::enable_if_c<
+ detail::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
+ detail::is_convertible<E, D>::value &&
+ (
+ !detail::is_reference<D>::value ||
+ detail::is_same<D, E>::value
+ )
+ ,
+ nat
+ >::type = nat())
+ : ptr_(const_cast<unique_ptr<U,E>&>(u.get()).release(), boost::move(u.get().get_deleter()))
+ {}
+ #else
+ template <class U, class E>
+ unique_ptr(unique_ptr<U, E> && u,
+ typename detail::enable_if_c<
+ detail::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
+ detail::is_convertible<E, D>::value &&
+ (
+ !detail::is_reference<D>::value ||
+ detail::is_same<D, E>::value
+ )
+ ,
+ nat
+ >::type = nat())
+ : ptr_(const_cast<unique_ptr<U,E>&>(u).release(), boost::forward_constructor<D>(u.get_deleter()))
+ {}
+ #endif
+
+ //!Effects: If get() == 0 there are no effects. Otherwise get_deleter()(get()).
+ //!
+ //!Throws: nothing.
+ ~unique_ptr()
+ { reset(); }
+
+ // assignment
+
+ //!Requires: Assignment of the deleter D from an rvalue D must not throw an exception.
+ //!
+ //!Effects: reset(u.release()) followed by a move assignment from u's deleter to
+ //!this deleter.
+ //!
+ //!Postconditions: This unique_ptr now owns the pointer which u owned, and u no
+ //!longer owns it.
+ //!
+ //!Returns: *this.
+ //!
+ //!Throws: nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ unique_ptr& operator=(boost::rv<unique_ptr> &u)
+ {
+ reset(u.get().release());
+ ptr_.second() = boost::move(u.get().get_deleter());
+ return *this;
+ }
+ #else
+ unique_ptr& operator=(unique_ptr && u)
+ {
+ reset(u.release());
+ ptr_.second() = boost::move(u.get_deleter());
+ return *this;
+ }
+ #endif
+
+ //!Requires: Assignment of the deleter D from an rvalue D must not
+ //!throw an exception. U* must be implicitly convertible to T*.
+ //!
+ //!Effects: reset(u.release()) followed by a move assignment from
+ //!u's deleter to this deleter. If either D or E is
+ //!a reference type, then the referenced lvalue deleter participates
+ //!in the move assignment.
+ //!
+ //!Postconditions: This unique_ptr now owns the pointer which u owned,
+ //!and u no longer owns it.
+ //!
+ //!Returns: *this.
+ //!
+ //!Throws: nothing.
+ template <class U, class E>
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ unique_ptr& operator=(boost::rv<unique_ptr<U, E> > &mu)
+ {
+ reset(mu.get().release());
+ ptr_.second() = boost::move(mu.get().get_deleter());
+ return *this;
+ }
+ #else
+ unique_ptr& operator=(unique_ptr<U, E> && u)
+ {
+ reset(u.release());
+ ptr_.second() = boost::move(u.get_deleter());
+ return *this;
+ }
+ #endif
+
+ //!Assigns from the literal 0 or NULL.
+ //!
+ //!Effects: reset().
+ //!
+ //!Postcondition: get() == 0
+ //!
+ //!Returns: *this.
+ //!
+ //!Throws: nothing.
+ unique_ptr& operator=(int nat::*)
+ {
+ reset();
+ return *this;
+ }
+
+ //!Requires: get() != 0.
+ //!Returns: *get().
+ //!Throws: nothing.
+ typename detail::add_reference<T>::type operator*() const
+ { return *ptr_.first(); }
+
+ //!Requires: get() != 0.
+ //!Returns: get().
+ //!Throws: nothing.
+ pointer operator->() const
+ { return ptr_.first(); }
+
+ //!Returns: The stored pointer.
+ //!Throws: nothing.
+ pointer get() const
+ { return ptr_.first(); }
+
+ //!Returns: A reference to the stored deleter.
+ //!
+ //!Throws: nothing.
+ deleter_reference get_deleter()
+ { return ptr_.second(); }
+
+ //!Returns: A const reference to the stored deleter.
+ //!
+ //!Throws: nothing.
+ deleter_const_reference get_deleter() const
+ { return ptr_.second(); }
+
+ //!Returns: An unspecified value that, when used in boolean
+ //!contexts, is equivalent to get() != 0.
+ //!
+ //!Throws: nothing.
+ operator int nat::*() const
+ { return ptr_.first() ? &nat::for_bool_ : 0; }
+
+ //!Postcondition: get() == 0.
+ //!
+ //!Returns: The value get() had at the start of the call to release.
+ //!
+ //!Throws: nothing.
+ pointer release()
+ {
+ pointer tmp = ptr_.first();
+ ptr_.first() = 0;
+ return tmp;
+ }
+
+ //!Effects: If p == get() there are no effects. Otherwise get_deleter()(get()).
+ //!
+ //!Postconditions: get() == p.
+ //!
+ //!Throws: nothing.
+ void reset(pointer p = 0)
+ {
+ if (ptr_.first() != p){
+ if (ptr_.first())
+ ptr_.second()(ptr_.first());
+ ptr_.first() = p;
+ }
+ }
+
+ //!Requires: The deleter D is Swappable and will not throw an exception under swap.
+ //!
+ //!Effects: The stored pointers of this and u are exchanged.
+ //! The stored deleters are swapped (unqualified).
+ //!Throws: nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(unique_ptr& u)
+ { ptr_.swap(u.ptr_); }
+
+ void swap(boost::rv<unique_ptr> &mu)
+ { ptr_.swap(mu.get().ptr_); }
+ #else
+ void swap(unique_ptr&&u)
+ { ptr_.swap(u.ptr_); }
+ #endif
+
+ /// @cond
+ private:
+ boost::compressed_pair<pointer, D> ptr_;
+
+ unique_ptr(unique_ptr&);
+ template <class U, class E> unique_ptr(unique_ptr<U, E>&);
+ template <class U> unique_ptr(U&, typename detail::unique_ptr_error<U>::type = 0);
+
+ unique_ptr& operator=(unique_ptr&);
+ template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&);
+ template <class U> typename detail::unique_ptr_error<U>::type operator=(U&);
+ /// @endcond
+};
+/*
+template <class T, class D>
+class unique_ptr<T[], D>
+{
+ struct nat {int for_bool_;};
+ typedef typename detail::add_reference<D>::type deleter_reference;
+ typedef typename detail::add_reference<const D>::type deleter_const_reference;
+public:
+ typedef T element_type;
+ typedef D deleter_type;
+ typedef typename detail::pointer_type<T, D>::type pointer;
+
+ // constructors
+ unique_ptr() : ptr_(pointer()) {}
+ explicit unique_ptr(pointer p) : ptr_(p) {}
+ unique_ptr(pointer p, typename if_<
+ boost::is_reference<D>,
+ D,
+ typename detail::add_reference<const D>::type>::type d)
+ : ptr_(p, d) {}
+ unique_ptr(const unique_ptr& u)
+ : ptr_(const_cast<unique_ptr&>(u).release(), u.get_deleter()) {}
+
+ // destructor
+ ~unique_ptr() {reset();}
+
+ // assignment
+ unique_ptr& operator=(const unique_ptr& cu)
+ {
+ unique_ptr& u = const_cast<unique_ptr&>(cu);
+ reset(u.release());
+ ptr_.second() = u.get_deleter();
+ return *this;
+ }
+ unique_ptr& operator=(int nat::*)
+ {
+ reset();
+ return *this;
+ }
+
+ // observers
+ typename detail::add_reference<T>::type operator[](std::size_t i) const {return ptr_.first()[i];}
+ pointer get() const {return ptr_.first();}
+ deleter_reference get_deleter() {return ptr_.second();}
+ deleter_const_reference get_deleter() const {return ptr_.second();}
+ operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
+
+ // modifiers
+ pointer release()
+ {
+ pointer tmp = ptr_.first();
+ ptr_.first() = 0;
+ return tmp;
+ }
+ void reset(pointer p = 0)
+ {
+ if (ptr_.first() != p)
+ {
+ if (ptr_.first())
+ ptr_.second()(ptr_.first());
+ ptr_.first() = p;
+ }
+ }
+ void swap(unique_ptr& u) {ptr_.swap(u.ptr_);}
+private:
+ boost::compressed_pair<pointer, D> ptr_;
+
+ template <class U, class E> unique_ptr(U p, E,
+ typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
+ template <class U> explicit unique_ptr(U,
+ typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
+
+ unique_ptr(unique_ptr&);
+ template <class U> unique_ptr(U&, typename detail::unique_ptr_error<U>::type = 0);
+
+ unique_ptr& operator=(unique_ptr&);
+ template <class U> typename detail::unique_ptr_error<U>::type operator=(U&);
+};
+
+template <class T, class D, std::size_t N>
+class unique_ptr<T[N], D>
+{
+ struct nat {int for_bool_;};
+ typedef typename detail::add_reference<D>::type deleter_reference;
+ typedef typename detail::add_reference<const D>::type deleter_const_reference;
+public:
+ typedef T element_type;
+ typedef D deleter_type;
+ typedef typename detail::pointer_type<T, D>::type pointer;
+ static const std::size_t size = N;
+
+ // constructors
+ unique_ptr() : ptr_(0) {}
+ explicit unique_ptr(pointer p) : ptr_(p) {}
+ unique_ptr(pointer p, typename if_<
+ boost::is_reference<D>,
+ D,
+ typename detail::add_reference<const D>::type>::type d)
+ : ptr_(p, d) {}
+ unique_ptr(const unique_ptr& u)
+ : ptr_(const_cast<unique_ptr&>(u).release(), u.get_deleter()) {}
+
+ // destructor
+ ~unique_ptr() {reset();}
+
+ // assignment
+ unique_ptr& operator=(const unique_ptr& cu)
+ {
+ unique_ptr& u = const_cast<unique_ptr&>(cu);
+ reset(u.release());
+ ptr_.second() = u.get_deleter();
+ return *this;
+ }
+ unique_ptr& operator=(int nat::*)
+ {
+ reset();
+ return *this;
+ }
+
+ // observers
+ typename detail::add_reference<T>::type operator[](std::size_t i) const {return ptr_.first()[i];}
+ pointer get() const {return ptr_.first();}
+ deleter_reference get_deleter() {return ptr_.second();}
+ deleter_const_reference get_deleter() const {return ptr_.second();}
+ operator int nat::*() const {return ptr_.first() ? &nat::for_bool_ : 0;}
+
+ // modifiers
+ pointer release()
+ {
+ pointer tmp = ptr_.first();
+ ptr_.first() = 0;
+ return tmp;
+ }
+ void reset(pointer p = 0)
+ {
+ if (ptr_.first() != p)
+ {
+ if (ptr_.first())
+ ptr_.second()(ptr_.first(), N);
+ ptr_.first() = p;
+ }
+ }
+ void swap(unique_ptr& u) {ptr_.swap(u.ptr_);}
+private:
+ boost::compressed_pair<pointer, D> ptr_;
+
+ template <class U, class E> unique_ptr(U p, E,
+ typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
+ template <class U> explicit unique_ptr(U,
+ typename boost::enable_if<boost::is_convertible<U, pointer> >::type* = 0);
+
+ unique_ptr(unique_ptr&);
+ template <class U> unique_ptr(U&, typename detail::unique_ptr_error<U>::type = 0);
+
+ unique_ptr& operator=(unique_ptr&);
+ template <class U> typename detail::unique_ptr_error<U>::type operator=(U&);
+};
+*/
+template <class T, class D> inline
+void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y)
+{ x.swap(y); }
+
+template <class T1, class D1, class T2, class D2> inline
+bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
+{ return x.get() == y.get(); }
+
+template <class T1, class D1, class T2, class D2> inline
+bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
+{ return x.get() != y.get(); }
+
+template <class T1, class D1, class T2, class D2> inline
+bool operator <(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
+{ return x.get() < y.get(); }
+
+template <class T1, class D1, class T2, class D2> inline
+bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
+{ return x.get() <= y.get(); }
+
+template <class T1, class D1, class T2, class D2> inline
+bool operator >(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
+{ return x.get() > y.get(); }
+
+template <class T1, class D1, class T2, class D2> inline
+bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y)
+{ return x.get() >= y.get(); }
+
+
+//!Returns the type of a unique pointer
+//!of type T with boost::interprocess::deleter deleter
+//!that can be constructed in the given managed segment type.
+template<class T, class ManagedMemory>
+struct managed_unique_ptr
+{
+ typedef unique_ptr
+ < T
+ , typename ManagedMemory::template deleter<T>::type
+ > type;
+};
+
+//!Returns an instance of a unique pointer constructed
+//!with boost::interproces::deleter from a pointer
+//!of type T that has been allocated in the passed managed segment
+template<class T, class ManagedMemory>
+inline typename managed_unique_ptr<T, ManagedMemory>::type
+ make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory)
+{
+ return typename managed_unique_ptr<T, ManagedMemory>::type
+ (constructed_object, managed_memory.template get_deleter<T>());
+}
+
+} //namespace interprocess{
+} //namespace boost{
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_UNIQUE_PTR_HPP_INCLUDED
Added: sandbox/boost/interprocess/smart_ptr/weak_ptr.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/smart_ptr/weak_ptr.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,258 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file is the adaptation for Interprocess of boost/weak_ptr.hpp
+//
+// (C) Copyright Peter Dimov 2001, 2002, 2003
+// (C) Copyright Ion Gaztanaga 2006-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_WEAK_PTR_HPP_INCLUDED
+#define BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/interprocess/allocators/allocator.hpp>
+#include <boost/interprocess/smart_ptr/deleter.hpp>
+
+//!\file
+//!Describes the smart pointer weak_ptr.
+
+namespace boost{
+namespace interprocess{
+
+//!The weak_ptr class template stores a "weak reference" to an object
+//!that's already managed by a shared_ptr. To access the object, a weak_ptr
+//!can be converted to a shared_ptr using the shared_ptr constructor or the
+//!member function lock. When the last shared_ptr to the object goes away
+//!and the object is deleted, the attempt to obtain a shared_ptr from the
+//!weak_ptr instances that refer to the deleted object will fail: the constructor
+//!will throw an exception of type bad_weak_ptr, and weak_ptr::lock will
+//!return an empty shared_ptr.
+//!
+//!Every weak_ptr meets the CopyConstructible and Assignable requirements
+//!of the C++ Standard Library, and so can be used in standard library containers.
+//!Comparison operators are supplied so that weak_ptr works with the standard
+//!library's associative containers.
+//!
+//!weak_ptr operations never throw exceptions.
+//!
+//!The class template is parameterized on T, the type of the object pointed to.
+template<class T, class A, class D>
+class weak_ptr
+{
+ /// @cond
+ private:
+ // Borland 5.5.1 specific workarounds
+ typedef weak_ptr<T, A, D> this_type;
+ typedef typename detail::pointer_to_other
+ <typename A::pointer, T>::type pointer;
+ typedef typename detail::add_reference
+ <T>::type reference;
+ typedef typename detail::add_reference
+ <T>::type const_reference;
+ /// @endcond
+
+ public:
+ typedef T element_type;
+ typedef T value_type;
+
+ //!Effects: Constructs an empty weak_ptr.
+ //!Postconditions: use_count() == 0.
+ weak_ptr()
+ : m_pn() // never throws
+ {}
+ // generated copy constructor, assignment, destructor are fine
+ //
+ // The "obvious" converting constructor implementation:
+ //
+ // template<class Y>
+ // weak_ptr(weak_ptr<Y> const & r): m_px(r.m_px), m_pn(r.m_pn) // never throws
+ // {
+ // }
+ //
+ // has a serious problem.
+ //
+ // r.m_px may already have been invalidated. The m_px(r.m_px)
+ // conversion may require access to *r.m_px (virtual inheritance).
+ //
+ // It is not possible to avoid spurious access violations since
+ // in multithreaded programs r.m_px may be invalidated at any point.
+
+ //!Effects: If r is empty, constructs an empty weak_ptr; otherwise,
+ //!constructs a weak_ptr that shares ownership with r as if by storing a
+ //!copy of the pointer stored in r.
+ //!
+ //!Postconditions: use_count() == r.use_count().
+ //!
+ //!Throws: nothing.
+ template<class Y>
+ weak_ptr(weak_ptr<Y, A, D> const & r)
+ : m_pn(r.m_pn) // never throws
+ {
+ //Construct a temporary shared_ptr so that nobody
+ //can destroy the value while constructing this
+ const shared_ptr<T, A, D> &ref = r.lock();
+ m_pn.set_pointer(ref.get());
+ }
+
+ //!Effects: If r is empty, constructs an empty weak_ptr; otherwise,
+ //!constructs a weak_ptr that shares ownership with r as if by storing a
+ //!copy of the pointer stored in r.
+ //!
+ //!Postconditions: use_count() == r.use_count().
+ //!
+ //!Throws: nothing.
+ template<class Y>
+ weak_ptr(shared_ptr<Y, A, D> const & r)
+ : m_pn(r.m_pn) // never throws
+ {}
+
+ //!Effects: Equivalent to weak_ptr(r).swap(*this).
+ //!
+ //!Throws: nothing.
+ //!
+ //!Notes: The implementation is free to meet the effects (and the
+ //!implied guarantees) via different means, without creating a temporary.
+ template<class Y>
+ weak_ptr & operator=(weak_ptr<Y, A, D> const & r) // never throws
+ {
+ //Construct a temporary shared_ptr so that nobody
+ //can destroy the value while constructing this
+ const shared_ptr<T, A, D> &ref = r.lock();
+ m_pn = r.m_pn;
+ m_pn.set_pointer(ref.get());
+ return *this;
+ }
+
+ //!Effects: Equivalent to weak_ptr(r).swap(*this).
+ //!
+ //!Throws: nothing.
+ //!
+ //!Notes: The implementation is free to meet the effects (and the
+ //!implied guarantees) via different means, without creating a temporary.
+ template<class Y>
+ weak_ptr & operator=(shared_ptr<Y, A, D> const & r) // never throws
+ { m_pn = r.m_pn; return *this; }
+
+ //!Returns: expired()? shared_ptr<T>(): shared_ptr<T>(*this).
+ //!
+ //!Throws: nothing.
+ shared_ptr<T, A, D> lock() const // never throws
+ {
+ // optimization: avoid throw overhead
+ if(expired()){
+ return shared_ptr<element_type, A, D>();
+ }
+ BOOST_TRY{
+ return shared_ptr<element_type, A, D>(*this);
+ }
+ BOOST_CATCH(bad_weak_ptr const &){
+ // Q: how can we get here?
+ // A: another thread may have invalidated r after the use_count test above.
+ return shared_ptr<element_type, A, D>();
+ }
+ BOOST_CATCH_END
+ }
+
+ //!Returns: 0 if *this is empty; otherwise, the number of shared_ptr objects
+ //!that share ownership with *this.
+ //!
+ //!Throws: nothing.
+ //!
+ //!Notes: use_count() is not necessarily efficient. Use only for debugging and
+ //!testing purposes, not for production code.
+ long use_count() const // never throws
+ { return m_pn.use_count(); }
+
+ //!Returns: Returns: use_count() == 0.
+ //!
+ //!Throws: nothing.
+ //!
+ //!Notes: expired() may be faster than use_count().
+ bool expired() const // never throws
+ { return m_pn.use_count() == 0; }
+
+ //!Effects: Equivalent to:
+ //!weak_ptr().swap(*this).
+ void reset() // never throws in 1.30+
+ { this_type().swap(*this); }
+
+ //!Effects: Exchanges the contents of the two
+ //!smart pointers.
+ //!
+ //!Throws: nothing.
+ void swap(this_type & other) // never throws
+ { detail::do_swap(m_pn, other.m_pn); }
+
+ /// @cond
+ template<class T2, class A2, class D2>
+ bool _internal_less(weak_ptr<T2, A2, D2> const & rhs) const
+ { return m_pn < rhs.m_pn; }
+
+ template<class Y>
+ void _internal_assign(const detail::shared_count<Y, A, D> & pn2)
+ {
+
+ m_pn = pn2;
+ }
+
+ private:
+
+ template<class T2, class A2, class D2> friend class shared_ptr;
+ template<class T2, class A2, class D2> friend class weak_ptr;
+
+ detail::weak_count<T, A, D> m_pn; // reference counter
+ /// @endcond
+}; // weak_ptr
+
+template<class T, class A, class D, class U, class A2, class D2> inline
+bool operator<(weak_ptr<T, A, D> const & a, weak_ptr<U, A2, D2> const & b)
+{ return a._internal_less(b); }
+
+template<class T, class A, class D> inline
+void swap(weak_ptr<T, A, D> & a, weak_ptr<T, A, D> & b)
+{ a.swap(b); }
+
+//!Returns the type of a weak pointer
+//!of type T with the allocator boost::interprocess::allocator allocator
+//!and boost::interprocess::deleter deleter
+//!that can be constructed in the given managed segment type.
+template<class T, class ManagedMemory>
+struct managed_weak_ptr
+{
+ typedef weak_ptr
+ < T
+ , typename ManagedMemory::template allocator<void>::type
+ , typename ManagedMemory::template deleter<T>::type
+ > type;
+};
+
+//!Returns an instance of a weak pointer constructed
+//!with the default allocator and deleter from a pointer
+//!of type T that has been allocated in the passed managed segment
+template<class T, class ManagedMemory>
+inline typename managed_weak_ptr<T, ManagedMemory>::type
+ make_managed_weak_ptr(T *constructed_object, ManagedMemory &managed_memory)
+{
+ return typename managed_weak_ptr<T, ManagedMemory>::type
+ ( constructed_object
+ , managed_memory.template get_allocator<void>()
+ , managed_memory.template get_deleter<T>()
+ );
+}
+
+} // namespace interprocess
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // #ifndef BOOST_INTERPROCESS_WEAK_PTR_HPP_INCLUDED
Added: sandbox/boost/interprocess/streams/bufferstream.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/streams/bufferstream.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,444 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005.
+// Changed internal SGI string to a buffer. Added efficient
+// internal buffer get/set/swap functions, so that we can obtain/establish the
+// internal buffer without any reallocation or copy. Kill those temporaries!
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (c) 1998
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+//!\file
+//!This file defines basic_bufferbuf, basic_ibufferstream,
+//!basic_obufferstream, and basic_bufferstream classes. These classes
+//!represent streamsbufs and streams whose sources or destinations
+//!are fixed size character buffers.
+
+#ifndef BOOST_INTERPROCESS_BUFFERSTREAM_HPP
+#define BOOST_INTERPROCESS_BUFFERSTREAM_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <iosfwd>
+#include <ios>
+#include <istream>
+#include <ostream>
+#include <string> // char traits
+#include <cstddef> // ptrdiff_t
+#include <cassert>
+#include <boost/interprocess/interprocess_fwd.hpp>
+
+namespace boost { namespace interprocess {
+
+//!A streambuf class that controls the transmission of elements to and from
+//!a basic_xbufferstream. The elements are transmitted from a to a fixed
+//!size buffer
+template <class CharT, class CharTraits>
+class basic_bufferbuf
+ : public std::basic_streambuf<CharT, CharTraits>
+{
+ public:
+ typedef CharT char_type;
+ typedef typename CharTraits::int_type int_type;
+ typedef typename CharTraits::pos_type pos_type;
+ typedef typename CharTraits::off_type off_type;
+ typedef CharTraits traits_type;
+ typedef std::basic_streambuf<char_type, traits_type> base_t;
+
+ public:
+ //!Constructor.
+ //!Does not throw.
+ explicit basic_bufferbuf(std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : base_t(), m_mode(mode), m_buffer(0), m_length(0)
+ {}
+
+ //!Constructor. Assigns formatting buffer.
+ //!Does not throw.
+ explicit basic_bufferbuf(CharT *buffer, std::size_t length,
+ std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : base_t(), m_mode(mode), m_buffer(buffer), m_length(length)
+ { this->set_pointers(); }
+
+ virtual ~basic_bufferbuf(){}
+
+ public:
+ //!Returns the pointer and size of the internal buffer.
+ //!Does not throw.
+ std::pair<CharT *, std::size_t> buffer() const
+ { return std::pair<CharT *, std::size_t>(m_buffer, m_length); }
+
+ //!Sets the underlying buffer to a new value
+ //!Does not throw.
+ void buffer(CharT *buffer, std::size_t length)
+ { m_buffer = buffer; m_length = length; this->set_pointers(); }
+
+ /// @cond
+ private:
+ void set_pointers()
+ {
+ // The initial read position is the beginning of the buffer.
+ if(m_mode & std::ios_base::in)
+ this->setg(m_buffer, m_buffer, m_buffer + m_length);
+
+ // The initial write position is the beginning of the buffer.
+ if(m_mode & std::ios_base::out)
+ this->setp(m_buffer, m_buffer + m_length);
+ }
+
+ protected:
+ virtual int_type underflow()
+ {
+ // Precondition: gptr() >= egptr(). Returns a character, if available.
+ return this->gptr() != this->egptr() ?
+ CharTraits::to_int_type(*this->gptr()) : CharTraits::eof();
+ }
+
+ virtual int_type pbackfail(int_type c = CharTraits::eof())
+ {
+ if(this->gptr() != this->eback()) {
+ if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
+ if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
+ this->gbump(-1);
+ return c;
+ }
+ else if(m_mode & std::ios_base::out) {
+ this->gbump(-1);
+ *this->gptr() = c;
+ return c;
+ }
+ else
+ return CharTraits::eof();
+ }
+ else {
+ this->gbump(-1);
+ return CharTraits::not_eof(c);
+ }
+ }
+ else
+ return CharTraits::eof();
+ }
+
+ virtual int_type overflow(int_type c = CharTraits::eof())
+ {
+ if(m_mode & std::ios_base::out) {
+ if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
+// if(!(m_mode & std::ios_base::in)) {
+// if(this->pptr() != this->epptr()) {
+// *this->pptr() = CharTraits::to_char_type(c);
+// this->pbump(1);
+// return c;
+// }
+// else
+// return CharTraits::eof();
+// }
+// else {
+ if(this->pptr() == this->epptr()) {
+ //We can't append to a static buffer
+ return CharTraits::eof();
+ }
+ else {
+ *this->pptr() = CharTraits::to_char_type(c);
+ this->pbump(1);
+ return c;
+ }
+// }
+ }
+ else // c is EOF, so we don't have to do anything
+ return CharTraits::not_eof(c);
+ }
+ else // Overflow always fails if it's read-only.
+ return CharTraits::eof();
+ }
+
+ virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
+ std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ {
+ bool in = false;
+ bool out = false;
+
+ const std::ios_base::openmode inout =
+ std::ios_base::in | std::ios_base::out;
+
+ if((mode & inout) == inout) {
+ if(dir == std::ios_base::beg || dir == std::ios_base::end)
+ in = out = true;
+ }
+ else if(mode & std::ios_base::in)
+ in = true;
+ else if(mode & std::ios_base::out)
+ out = true;
+
+ if(!in && !out)
+ return pos_type(off_type(-1));
+ else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) ||
+ (out && (!(m_mode & std::ios_base::out) || this->pptr() == 0)))
+ return pos_type(off_type(-1));
+
+ std::streamoff newoff;
+ switch(dir) {
+ case std::ios_base::beg:
+ newoff = 0;
+ break;
+ case std::ios_base::end:
+ newoff = static_cast<std::streamoff>(m_length);
+ break;
+ case std::ios_base::cur:
+ newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
+ : static_cast<std::streamoff>(this->pptr() - this->pbase());
+ break;
+ default:
+ return pos_type(off_type(-1));
+ }
+
+ off += newoff;
+
+ if(in) {
+ std::ptrdiff_t n = this->egptr() - this->eback();
+
+ if(off < 0 || off > n)
+ return pos_type(off_type(-1));
+ else
+ this->setg(this->eback(), this->eback() + off, this->eback() + n);
+ }
+
+ if(out) {
+ std::ptrdiff_t n = this->epptr() - this->pbase();
+
+ if(off < 0 || off > n)
+ return pos_type(off_type(-1));
+ else {
+ this->setp(this->pbase(), this->pbase() + n);
+ this->pbump(off);
+ }
+ }
+
+ return pos_type(off);
+ }
+
+ virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); }
+
+ private:
+ std::ios_base::openmode m_mode;
+ CharT * m_buffer;
+ std::size_t m_length;
+ /// @endcond
+};
+
+//!A basic_istream class that uses a fixed size character buffer
+//!as its formatting buffer.
+template <class CharT, class CharTraits>
+class basic_ibufferstream
+ : public std::basic_istream<CharT, CharTraits>
+{
+ public: // Typedefs
+ typedef typename std::basic_ios
+ <CharT, CharTraits>::char_type char_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
+
+ private:
+ typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
+ typedef std::basic_istream<char_type, CharTraits> base_t;
+
+ public:
+ //!Constructor.
+ //!Does not throw.
+ basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in)
+ : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in)
+ { basic_ios_t::init(&m_buf); }
+
+ //!Constructor. Assigns formatting buffer.
+ //!Does not throw.
+ basic_ibufferstream(const CharT *buffer, std::size_t length,
+ std::ios_base::openmode mode = std::ios_base::in)
+ : basic_ios_t(), base_t(0),
+ m_buf(const_cast<CharT*>(buffer), length, mode | std::ios_base::in)
+ { basic_ios_t::init(&m_buf); }
+
+ ~basic_ibufferstream(){};
+
+ public:
+ //!Returns the address of the stored
+ //!stream buffer.
+ basic_bufferbuf<CharT, CharTraits>* rdbuf() const
+ { return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&m_buf); }
+
+ //!Returns the pointer and size of the internal buffer.
+ //!Does not throw.
+ std::pair<const CharT *, std::size_t> buffer() const
+ { return m_buf.buffer(); }
+
+ //!Sets the underlying buffer to a new value. Resets
+ //!stream position. Does not throw.
+ void buffer(const CharT *buffer, std::size_t length)
+ { m_buf.buffer(const_cast<CharT*>(buffer), length); }
+
+ /// @cond
+ private:
+ basic_bufferbuf<CharT, CharTraits> m_buf;
+ /// @endcond
+};
+
+//!A basic_ostream class that uses a fixed size character buffer
+//!as its formatting buffer.
+template <class CharT, class CharTraits>
+class basic_obufferstream
+ : public std::basic_ostream<CharT, CharTraits>
+{
+ public:
+ typedef typename std::basic_ios
+ <CharT, CharTraits>::char_type char_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
+
+ /// @cond
+ private:
+ typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
+ typedef std::basic_ostream<char_type, CharTraits> base_t;
+ /// @endcond
+ public:
+ //!Constructor.
+ //!Does not throw.
+ basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out)
+ { basic_ios_t::init(&m_buf); }
+
+ //!Constructor. Assigns formatting buffer.
+ //!Does not throw.
+ basic_obufferstream(CharT *buffer, std::size_t length,
+ std::ios_base::openmode mode = std::ios_base::out)
+ : basic_ios_t(), base_t(0),
+ m_buf(buffer, length, mode | std::ios_base::out)
+ { basic_ios_t::init(&m_buf); }
+
+ ~basic_obufferstream(){}
+
+ public:
+ //!Returns the address of the stored
+ //!stream buffer.
+ basic_bufferbuf<CharT, CharTraits>* rdbuf() const
+ { return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&m_buf); }
+
+ //!Returns the pointer and size of the internal buffer.
+ //!Does not throw.
+ std::pair<CharT *, std::size_t> buffer() const
+ { return m_buf.buffer(); }
+
+ //!Sets the underlying buffer to a new value. Resets
+ //!stream position. Does not throw.
+ void buffer(CharT *buffer, std::size_t length)
+ { m_buf.buffer(buffer, length); }
+
+ /// @cond
+ private:
+ basic_bufferbuf<CharT, CharTraits> m_buf;
+ /// @endcond
+};
+
+
+//!A basic_iostream class that uses a fixed size character buffer
+//!as its formatting buffer.
+template <class CharT, class CharTraits>
+class basic_bufferstream
+ : public std::basic_iostream<CharT, CharTraits>
+
+{
+ public: // Typedefs
+ typedef typename std::basic_ios
+ <CharT, CharTraits>::char_type char_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
+
+ /// @cond
+ private:
+ typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
+ typedef std::basic_iostream<char_type, CharTraits> base_t;
+ /// @endcond
+
+ public:
+ //!Constructor.
+ //!Does not throw.
+ basic_bufferstream(std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(mode)
+ { basic_ios_t::init(&m_buf); }
+
+ //!Constructor. Assigns formatting buffer.
+ //!Does not throw.
+ basic_bufferstream(CharT *buffer, std::size_t length,
+ std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(buffer, length, mode)
+ { basic_ios_t::init(&m_buf); }
+
+ ~basic_bufferstream(){}
+
+ public:
+ //!Returns the address of the stored
+ //!stream buffer.
+ basic_bufferbuf<CharT, CharTraits>* rdbuf() const
+ { return const_cast<basic_bufferbuf<CharT, CharTraits>*>(&m_buf); }
+
+ //!Returns the pointer and size of the internal buffer.
+ //!Does not throw.
+ std::pair<CharT *, std::size_t> buffer() const
+ { return m_buf.buffer(); }
+
+ //!Sets the underlying buffer to a new value. Resets
+ //!stream position. Does not throw.
+ void buffer(CharT *buffer, std::size_t length)
+ { m_buf.buffer(buffer, length); }
+
+ /// @cond
+ private:
+ basic_bufferbuf<CharT, CharTraits> m_buf;
+ /// @endcond
+};
+
+//Some typedefs to simplify usage
+typedef basic_bufferbuf<char> bufferbuf;
+typedef basic_bufferstream<char> bufferstream;
+typedef basic_ibufferstream<char> ibufferstream;
+typedef basic_obufferstream<char> obufferstream;
+
+typedef basic_bufferbuf<wchar_t> wbufferbuf;
+typedef basic_bufferstream<wchar_t> wbufferstream;
+typedef basic_ibufferstream<wchar_t> wibufferstream;
+typedef basic_obufferstream<wchar_t> wobufferstream;
+
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_BUFFERSTREAM_HPP */
Added: sandbox/boost/interprocess/streams/vectorstream.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/streams/vectorstream.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,593 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This file comes from SGI's sstream file. Modified by Ion Gaztanaga 2005.
+// Changed internal SGI string to a generic, templatized vector. Added efficient
+// internal buffer get/set/swap functions, so that we can obtain/establish the
+// internal buffer without any reallocation or copy. Kill those temporaries!
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright (c) 1998
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+//!\file
+//!This file defines basic_vectorbuf, basic_ivectorstream,
+//!basic_ovectorstream, and basic_vectorstreamclasses. These classes
+//!represent streamsbufs and streams whose sources or destinations are
+//!STL-like vectors that can be swapped with external vectors to avoid
+//!unnecessary allocations/copies.
+
+#ifndef BOOST_INTERPROCESS_VECTORSTREAM_HPP
+#define BOOST_INTERPROCESS_VECTORSTREAM_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <iosfwd>
+#include <ios>
+#include <istream>
+#include <ostream>
+#include <string> // char traits
+#include <cstddef> // ptrdiff_t
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <cassert>
+
+namespace boost { namespace interprocess {
+
+//!A streambuf class that controls the transmission of elements to and from
+//!a basic_ivectorstream, basic_ovectorstream or basic_vectorstream.
+//!It holds a character vector specified by CharVector template parameter
+//!as its formatting buffer. The vector must have contiguous storage, like
+//!std::vector, boost::interprocess::vector or boost::interprocess::basic_string
+template <class CharVector, class CharTraits>
+class basic_vectorbuf
+ : public std::basic_streambuf<typename CharVector::value_type, CharTraits>
+{
+ public:
+ typedef CharVector vector_type;
+ typedef typename CharVector::value_type char_type;
+ typedef typename CharTraits::int_type int_type;
+ typedef typename CharTraits::pos_type pos_type;
+ typedef typename CharTraits::off_type off_type;
+ typedef CharTraits traits_type;
+
+ /// @cond
+ private:
+ typedef std::basic_streambuf<char_type, traits_type> base_t;
+
+ basic_vectorbuf(const basic_vectorbuf&);
+ basic_vectorbuf & operator =(const basic_vectorbuf&);
+ /// @endcond
+
+ public:
+ //!Constructor. Throws if vector_type default
+ //!constructor throws.
+ explicit basic_vectorbuf(std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : base_t(), m_mode(mode)
+ { this->initialize_pointers(); }
+
+ //!Constructor. Throws if
+ //!vector_type(const VectorParameter ¶m) throws.
+ template<class VectorParameter>
+ explicit basic_vectorbuf(const VectorParameter ¶m,
+ std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : base_t(), m_mode(mode), m_vect(param)
+ { this->initialize_pointers(); }
+
+ virtual ~basic_vectorbuf(){}
+
+ public:
+
+ //!Swaps the underlying vector with the passed vector.
+ //!This function resets the read/write position in the stream.
+ //!Does not throw.
+ void swap_vector(vector_type &vect)
+ {
+ if (this->m_mode & std::ios_base::out){
+ //Update high water if necessary
+ //And resize vector to remove extra size
+ if (mp_high_water < base_t::pptr()){
+ //Restore the vector's size if necessary
+ mp_high_water = base_t::pptr();
+ }
+ m_vect.resize(mp_high_water - (m_vect.size() ? &m_vect[0] : 0));
+
+ //Now swap vector
+ m_vect.swap(vect);
+
+ //If the stream is writable put the high water mark
+ //and maximize the size.
+ typename vector_type::size_type old_size = m_vect.size();
+ m_vect.resize(m_vect.capacity());
+ this->initialize_pointers();
+ mp_high_water = old_size ? &m_vect[0] + old_size : 0;
+ }
+ else{
+ //Now swap vector
+ m_vect.swap(vect);
+ this->initialize_pointers();
+ }
+ }
+
+ //!Returns a const reference to the internal vector.
+ //!Does not throw.
+ const vector_type &vector() const
+ {
+ if (this->m_mode & std::ios_base::out){
+ if (mp_high_water < base_t::pptr()){
+ //Restore the vector's size if necessary
+ mp_high_water = base_t::pptr();
+ }
+ m_vect.resize(mp_high_water - (m_vect.size() ? &m_vect[0] : 0));
+ const_cast<basic_vectorbuf * const>(this)->initialize_pointers();
+ }
+ return m_vect;
+ }
+
+ //!Preallocates memory from the internal vector.
+ //!Resets the stream to the first position.
+ //!Throws if the internals vector's memory allocation throws.
+ void reserve(typename vector_type::size_type size)
+ {
+ m_vect.reserve(size);
+ //Now update pointer data
+ typename vector_type::size_type old_size = m_vect.size();
+ m_vect.resize(m_vect.capacity());
+ this->initialize_pointers();
+ mp_high_water = old_size ? &m_vect[0] + old_size : 0;
+ }
+
+ //!Calls clear() method of the internal vector.
+ //!Resets the stream to the first position.
+ void clear()
+ { m_vect.clear(); this->initialize_pointers(); }
+
+ /// @cond
+ private:
+ void initialize_pointers()
+ {
+ // The initial read position is the beginning of the vector.
+ if(m_mode & std::ios_base::in){
+ if(m_vect.empty()){
+ this->setg(0, 0, 0);
+ }
+ else{
+ this->setg(&m_vect[0], &m_vect[0], &m_vect[0] + m_vect.size());
+ }
+ }
+
+ // The initial write position is the beginning of the vector.
+ if(m_mode & std::ios_base::out){
+ if(m_vect.empty()){
+ this->setp(0, 0);
+ }
+ else{
+ this->setp(&m_vect[0], &m_vect[0] + m_vect.size());
+ }
+
+ if (m_mode & (std::ios_base::app | std::ios_base::ate))
+ base_t::pbump((int)m_vect.size());
+ }
+ mp_high_water = m_vect.empty() ? 0 : (&m_vect[0] + m_vect.size());
+ }
+
+ protected:
+ virtual int_type underflow()
+ {
+ if (base_t::gptr() == 0)
+ return CharTraits::eof();
+ if (mp_high_water < base_t::pptr())
+ mp_high_water = base_t::pptr();
+ if (base_t::egptr() < mp_high_water)
+ base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water);
+ if (base_t::gptr() < base_t::egptr())
+ return CharTraits::to_int_type(*base_t::gptr());
+ return CharTraits::eof();
+ }
+
+ virtual int_type pbackfail(int_type c = CharTraits::eof())
+ {
+ if(this->gptr() != this->eback()) {
+ if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
+ if(CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) {
+ this->gbump(-1);
+ return c;
+ }
+ else if(m_mode & std::ios_base::out) {
+ this->gbump(-1);
+ *this->gptr() = c;
+ return c;
+ }
+ else
+ return CharTraits::eof();
+ }
+ else {
+ this->gbump(-1);
+ return CharTraits::not_eof(c);
+ }
+ }
+ else
+ return CharTraits::eof();
+ }
+
+ virtual int_type overflow(int_type c = CharTraits::eof())
+ {
+ if(m_mode & std::ios_base::out) {
+ if(!CharTraits::eq_int_type(c, CharTraits::eof())) {
+// if(!(m_mode & std::ios_base::in)) {
+// if(this->pptr() < this->epptr()) {
+// *this->pptr() = CharTraits::to_char_type(c);
+// this->pbump(1);
+// if (mp_high_water < base_t::pptr())
+// mp_high_water = base_t::pptr();
+// if ((m_mode & std::ios_base::in) && base_t::egptr() < mp_high_water)
+// base_t::setg(base_t::eback(), base_t::gptr(), mp_high_water);
+// return c;
+// }
+// else
+// return CharTraits::eof();
+// }
+// else {
+// try{
+ typedef typename vector_type::difference_type dif_t;
+ dif_t inpos = base_t::gptr() - base_t::eback();
+ //The new output position is the previous one plus one
+ //because 'overflow' requires putting 'c' on the buffer
+ dif_t new_outpos = base_t::pptr() - base_t::pbase() + 1;
+ //Adjust high water if necessary
+ dif_t hipos = mp_high_water - base_t::pbase();
+ if (hipos < new_outpos)
+ hipos = new_outpos;
+ //Insert the new data
+ m_vect.push_back(CharTraits::to_char_type(c));
+ m_vect.resize(m_vect.capacity());
+ char_type* p = const_cast<char_type*>(&m_vect[0]);
+ //A reallocation has happened, update pointers
+ if (m_mode & std::ios_base::in)
+ base_t::setg(p, p + inpos, p + hipos);
+ base_t::setp(p, p + (dif_t)m_vect.size());
+ //Update write position to the old position + 1
+ base_t::pbump((int)new_outpos);
+ //Update high water pointer, since the buffer has been reallocated
+ mp_high_water = base_t::pbase() + hipos;
+ return c;
+// }
+// catch(...){
+// return CharTraits::eof();
+// }
+// }
+ }
+ else // c is EOF, so we don't have to do anything
+ return CharTraits::not_eof(c);
+ }
+ else // Overflow always fails if it's read-only.
+ return CharTraits::eof();
+ }
+
+ virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
+ std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ {
+ bool in = false, out = false;
+
+ const std::ios_base::openmode inout =
+ std::ios_base::in | std::ios_base::out;
+
+ if((mode & inout) == inout) {
+ if(dir == std::ios_base::beg || dir == std::ios_base::end)
+ in = out = true;
+ }
+ else if(mode & std::ios_base::in)
+ in = true;
+ else if(mode & std::ios_base::out)
+ out = true;
+
+ if(!in && !out)
+ return pos_type(off_type(-1));
+ else if((in && (!(m_mode & std::ios_base::in) || this->gptr() == 0)) ||
+ (out && (!(m_mode & std::ios_base::out) || this->pptr() == 0)))
+ return pos_type(off_type(-1));
+
+ off_type newoff;
+ //Just calculate the end of the stream. If the stream is read-only
+ //the limit is the size of the vector. Otherwise, the high water mark
+ //will mark the real size.
+ off_type limit = static_cast<off_type> (mode & std::ios_base::out ?
+ mp_high_water - base_t::pbase() : m_vect.size()/*mp_high_water - base_t::eback()*/);
+
+ switch(dir) {
+ case std::ios_base::beg:
+ newoff = 0;
+ break;
+ case std::ios_base::end:
+ newoff = limit;
+ break;
+ case std::ios_base::cur:
+ newoff = in ? static_cast<std::streamoff>(this->gptr() - this->eback())
+ : static_cast<std::streamoff>(this->pptr() - this->pbase());
+ break;
+ default:
+ return pos_type(off_type(-1));
+ }
+
+ newoff += off;
+
+ if (newoff < 0 || newoff > limit)
+ return pos_type(-1);
+ if (m_mode & std::ios_base::app && mode & std::ios_base::out && newoff != limit)
+ return pos_type(-1);
+ if (in)
+ base_t::setg(base_t::eback(), base_t::eback() + newoff, base_t::egptr());
+ if (out){
+ base_t::setp(base_t::pbase(), base_t::epptr());
+ base_t::pbump(newoff);
+ }
+ return pos_type(newoff);
+ }
+
+ virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ { return seekoff(pos - pos_type(off_type(0)), std::ios_base::beg, mode); }
+
+ private:
+ std::ios_base::openmode m_mode;
+ mutable vector_type m_vect;
+ mutable char_type* mp_high_water;
+ /// @endcond
+};
+
+//!A basic_istream class that holds a character vector specified by CharVector
+//!template parameter as its formatting buffer. The vector must have
+//!contiguous storage, like std::vector, boost::interprocess::vector or
+//!boost::interprocess::basic_string
+template <class CharVector, class CharTraits>
+class basic_ivectorstream
+ : public std::basic_istream<typename CharVector::value_type, CharTraits>
+{
+ public:
+ typedef CharVector vector_type;
+ typedef typename std::basic_ios
+ <typename CharVector::value_type, CharTraits>::char_type char_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
+
+ /// @cond
+ private:
+ typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
+ typedef std::basic_istream<char_type, CharTraits> base_t;
+ /// @endcond
+
+ public:
+ //!Constructor. Throws if vector_type default
+ //!constructor throws.
+ basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in)
+ : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in)
+ { basic_ios_t::init(&m_buf); }
+
+ //!Constructor. Throws if vector_type(const VectorParameter ¶m)
+ //!throws.
+ template<class VectorParameter>
+ basic_ivectorstream(const VectorParameter ¶m,
+ std::ios_base::openmode mode = std::ios_base::in)
+ : basic_ios_t(), base_t(0),
+ m_buf(param, mode | std::ios_base::in)
+ { basic_ios_t::init(&m_buf); }
+
+ ~basic_ivectorstream(){};
+
+ public:
+ //!Returns the address of the stored
+ //!stream buffer.
+ basic_vectorbuf<CharVector, CharTraits>* rdbuf() const
+ { return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); }
+
+ //!Swaps the underlying vector with the passed vector.
+ //!This function resets the read position in the stream.
+ //!Does not throw.
+ void swap_vector(vector_type &vect)
+ { m_buf.swap_vector(vect); }
+
+ //!Returns a const reference to the internal vector.
+ //!Does not throw.
+ const vector_type &vector() const
+ { return m_buf.vector(); }
+
+ //!Calls reserve() method of the internal vector.
+ //!Resets the stream to the first position.
+ //!Throws if the internals vector's reserve throws.
+ void reserve(typename vector_type::size_type size)
+ { m_buf.reserve(size); }
+
+ //!Calls clear() method of the internal vector.
+ //!Resets the stream to the first position.
+ void clear()
+ { m_buf.clear(); }
+
+ /// @cond
+ private:
+ basic_vectorbuf<CharVector, CharTraits> m_buf;
+ /// @endcond
+};
+
+//!A basic_ostream class that holds a character vector specified by CharVector
+//!template parameter as its formatting buffer. The vector must have
+//!contiguous storage, like std::vector, boost::interprocess::vector or
+//!boost::interprocess::basic_string
+template <class CharVector, class CharTraits>
+class basic_ovectorstream
+ : public std::basic_ostream<typename CharVector::value_type, CharTraits>
+{
+ public:
+ typedef CharVector vector_type;
+ typedef typename std::basic_ios
+ <typename CharVector::value_type, CharTraits>::char_type char_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
+
+ /// @cond
+ private:
+ typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
+ typedef std::basic_ostream<char_type, CharTraits> base_t;
+ /// @endcond
+
+ public:
+ //!Constructor. Throws if vector_type default
+ //!constructor throws.
+ basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out)
+ { basic_ios_t::init(&m_buf); }
+
+ //!Constructor. Throws if vector_type(const VectorParameter ¶m)
+ //!throws.
+ template<class VectorParameter>
+ basic_ovectorstream(const VectorParameter ¶m,
+ std::ios_base::openmode mode = std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(param, mode | std::ios_base::out)
+ { basic_ios_t::init(&m_buf); }
+
+ ~basic_ovectorstream(){}
+
+ public:
+ //!Returns the address of the stored
+ //!stream buffer.
+ basic_vectorbuf<CharVector, CharTraits>* rdbuf() const
+ { return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); }
+
+ //!Swaps the underlying vector with the passed vector.
+ //!This function resets the write position in the stream.
+ //!Does not throw.
+ void swap_vector(vector_type &vect)
+ { m_buf.swap_vector(vect); }
+
+ //!Returns a const reference to the internal vector.
+ //!Does not throw.
+ const vector_type &vector() const
+ { return m_buf.vector(); }
+
+ //!Calls reserve() method of the internal vector.
+ //!Resets the stream to the first position.
+ //!Throws if the internals vector's reserve throws.
+ void reserve(typename vector_type::size_type size)
+ { m_buf.reserve(size); }
+
+ /// @cond
+ private:
+ basic_vectorbuf<CharVector, CharTraits> m_buf;
+ /// @endcond
+};
+
+
+//!A basic_iostream class that holds a character vector specified by CharVector
+//!template parameter as its formatting buffer. The vector must have
+//!contiguous storage, like std::vector, boost::interprocess::vector or
+//!boost::interprocess::basic_string
+template <class CharVector, class CharTraits>
+class basic_vectorstream
+ : public std::basic_iostream<typename CharVector::value_type, CharTraits>
+
+{
+ public:
+ typedef CharVector vector_type;
+ typedef typename std::basic_ios
+ <typename CharVector::value_type, CharTraits>::char_type char_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type;
+ typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type;
+
+ /// @cond
+ private:
+ typedef std::basic_ios<char_type, CharTraits> basic_ios_t;
+ typedef std::basic_iostream<char_type, CharTraits> base_t;
+ /// @endcond
+
+ public:
+ //!Constructor. Throws if vector_type default
+ //!constructor throws.
+ basic_vectorstream(std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(mode)
+ { basic_ios_t::init(&m_buf); }
+
+ //!Constructor. Throws if vector_type(const VectorParameter ¶m)
+ //!throws.
+ template<class VectorParameter>
+ basic_vectorstream(const VectorParameter ¶m, std::ios_base::openmode mode
+ = std::ios_base::in | std::ios_base::out)
+ : basic_ios_t(), base_t(0), m_buf(param, mode)
+ { basic_ios_t::init(&m_buf); }
+
+ ~basic_vectorstream(){}
+
+ public:
+ //Returns the address of the stored stream buffer.
+ basic_vectorbuf<CharVector, CharTraits>* rdbuf() const
+ { return const_cast<basic_vectorbuf<CharVector, CharTraits>*>(&m_buf); }
+
+ //!Swaps the underlying vector with the passed vector.
+ //!This function resets the read/write position in the stream.
+ //!Does not throw.
+ void swap_vector(vector_type &vect)
+ { m_buf.swap_vector(vect); }
+
+ //!Returns a const reference to the internal vector.
+ //!Does not throw.
+ const vector_type &vector() const
+ { return m_buf.vector(); }
+
+ //!Calls reserve() method of the internal vector.
+ //!Resets the stream to the first position.
+ //!Throws if the internals vector's reserve throws.
+ void reserve(typename vector_type::size_type size)
+ { m_buf.reserve(size); }
+
+ //!Calls clear() method of the internal vector.
+ //!Resets the stream to the first position.
+ void clear()
+ { m_buf.clear(); }
+
+ /// @cond
+ private:
+ basic_vectorbuf<CharVector, CharTraits> m_buf;
+ /// @endcond
+};
+
+//Some typedefs to simplify usage
+//!
+//!typedef basic_vectorbuf<std::vector<char> > vectorbuf;
+//!typedef basic_vectorstream<std::vector<char> > vectorstream;
+//!typedef basic_ivectorstream<std::vector<char> > ivectorstream;
+//!typedef basic_ovectorstream<std::vector<char> > ovectorstream;
+//!
+//!typedef basic_vectorbuf<std::vector<wchar_t> > wvectorbuf;
+//!typedef basic_vectorstream<std::vector<wchar_t> > wvectorstream;
+//!typedef basic_ivectorstream<std::vector<wchar_t> > wivectorstream;
+//!typedef basic_ovectorstream<std::vector<wchar_t> > wovectorstream;
+
+}} //namespace boost { namespace interprocess {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif /* BOOST_INTERPROCESS_VECTORSTREAM_HPP */
Added: sandbox/boost/interprocess/sync/emulation/interprocess_barrier.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/emulation/interprocess_barrier.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,46 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include<boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+
+namespace boost {
+namespace interprocess {
+
+inline barrier::barrier(unsigned int count)
+ : m_threshold(count), m_count(count), m_generation(0)
+{
+ if (count == 0)
+ throw std::invalid_argument("count cannot be zero.");
+}
+
+inline barrier::~barrier(){}
+
+inline bool barrier::wait()
+{
+ scoped_lock<interprocess_mutex> lock(m_mutex);
+ unsigned int gen = m_generation;
+
+ if (--m_count == 0){
+ m_generation++;
+ m_count = m_threshold;
+ m_cond.notify_all();
+ return true;
+ }
+
+ while (gen == m_generation){
+ m_cond.wait(lock);
+ }
+ return false;
+}
+
+} //namespace interprocess {
+} //namespace boost {
Added: sandbox/boost/interprocess/sync/emulation/interprocess_condition.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/emulation/interprocess_condition.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,216 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/move_semantics/move.hpp>
+namespace boost {
+namespace interprocess {
+
+inline interprocess_condition::interprocess_condition()
+{
+ //Note that this class is initialized to zero.
+ //So zeroed memory can be interpreted as an initialized
+ //condition variable
+ m_command = SLEEP;
+ m_num_waiters = 0;
+}
+
+inline interprocess_condition::~interprocess_condition()
+{
+ //Trivial destructor
+}
+
+inline void interprocess_condition::notify_one()
+{
+ this->notify(NOTIFY_ONE);
+}
+
+inline void interprocess_condition::notify_all()
+{
+ this->notify(NOTIFY_ALL);
+}
+
+inline void interprocess_condition::notify(boost::uint32_t command)
+{
+ //This interprocess_mutex guarantees that no other thread can enter to the
+ //do_timed_wait method logic, so that thread count will be
+ //constant until the function writes a NOTIFY_ALL command.
+ //It also guarantees that no other notification can be signaled
+ //on this interprocess_condition before this one ends
+ m_enter_mut.lock();
+
+ //Return if there are no waiters
+ if(!detail::atomic_read32(&m_num_waiters)) {
+ m_enter_mut.unlock();
+ return;
+ }
+
+ //Notify that all threads should execute wait logic
+ while(SLEEP != detail::atomic_cas32(const_cast<boost::uint32_t*>(&m_command), command, SLEEP)){
+ detail::thread_yield();
+ }
+/*
+ //Wait until the threads are woken
+ while(SLEEP != detail::atomic_cas32(const_cast<boost::uint32_t*>(&m_command), 0)){
+ detail::thread_yield();
+ }
+*/
+ //The enter interprocess_mutex will rest locked until the last waiting thread unlocks it
+}
+
+inline void interprocess_condition::do_wait(interprocess_mutex &mut)
+{
+ this->do_timed_wait(false, boost::posix_time::ptime(), mut);
+}
+
+inline bool interprocess_condition::do_timed_wait
+ (const boost::posix_time::ptime &abs_time, interprocess_mutex &mut)
+{
+ return this->do_timed_wait(true, abs_time, mut);
+}
+
+inline bool interprocess_condition::do_timed_wait(bool tout_enabled,
+ const boost::posix_time::ptime &abs_time,
+ interprocess_mutex &mut)
+{
+ boost::posix_time::ptime now = microsec_clock::universal_time();
+
+ if(tout_enabled){
+ if(now >= abs_time) return false;
+ }
+
+ typedef boost::interprocess::scoped_lock<interprocess_mutex> InternalLock;
+ //The enter interprocess_mutex guarantees that while executing a notification,
+ //no other thread can execute the do_timed_wait method.
+ {
+ //---------------------------------------------------------------
+ InternalLock lock;
+ if(tout_enabled){
+ InternalLock dummy(m_enter_mut, abs_time);
+ lock = boost::move(dummy);
+ }
+ else{
+ InternalLock dummy(m_enter_mut);
+ lock = boost::move(dummy);
+ }
+
+ if(!lock)
+ return false;
+ //---------------------------------------------------------------
+ //We increment the waiting thread count protected so that it will be
+ //always constant when another thread enters the notification logic.
+ //The increment marks this thread as "waiting on interprocess_condition"
+ detail::atomic_inc32(const_cast<boost::uint32_t*>(&m_num_waiters));
+
+ //We unlock the external interprocess_mutex atomically with the increment
+ mut.unlock();
+ }
+
+ //By default, we suppose that no timeout has happened
+ bool timed_out = false, unlock_enter_mut= false;
+
+ //Loop until a notification indicates that the thread should
+ //exit or timeout occurs
+ while(1){
+ //The thread sleeps/spins until a interprocess_condition commands a notification
+ //Notification occurred, we will lock the checking interprocess_mutex so that
+ while(detail::atomic_read32(&m_command) == SLEEP){
+ detail::thread_yield();
+
+ //Check for timeout
+ if(tout_enabled){
+ now = microsec_clock::universal_time();
+
+ if(now >= abs_time){
+ //If we can lock the interprocess_mutex it means that no notification
+ //is being executed in this interprocess_condition variable
+ timed_out = m_enter_mut.try_lock();
+
+ //If locking fails, indicates that another thread is executing
+ //notification, so we play the notification game
+ if(!timed_out){
+ //There is an ongoing notification, we will try again later
+ continue;
+ }
+ //No notification in execution, since enter interprocess_mutex is locked.
+ //We will execute time-out logic, so we will decrement count,
+ //release the enter interprocess_mutex and return false.
+ break;
+ }
+ }
+ }
+
+ //If a timeout occurred, the interprocess_mutex will not execute checking logic
+ if(tout_enabled && timed_out){
+ //Decrement wait count
+ detail::atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
+ unlock_enter_mut = true;
+ break;
+ }
+ else{
+ //Notification occurred, we will lock the checking interprocess_mutex so that
+ //if a notify_one notification occurs, only one thread can exit
+ //---------------------------------------------------------------
+ InternalLock lock;
+ if(tout_enabled){
+ InternalLock dummy(m_check_mut, abs_time);
+ lock = boost::move(dummy);
+ }
+ else{
+ InternalLock dummy(m_check_mut);
+ lock = boost::move(dummy);
+ }
+
+ if(!lock)
+ return false;
+ //---------------------------------------------------------------
+ boost::uint32_t result = detail::atomic_cas32
+ (const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ONE);
+ if(result == SLEEP){
+ //Other thread has been notified and since it was a NOTIFY one
+ //command, this thread must sleep again
+ continue;
+ }
+ else if(result == NOTIFY_ONE){
+ //If it was a NOTIFY_ONE command, only this thread should
+ //exit. This thread has atomically marked command as sleep before
+ //so no other thread will exit.
+ //Decrement wait count.
+ unlock_enter_mut = true;
+ detail::atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
+ break;
+ }
+ else{
+ //If it is a NOTIFY_ALL command, all threads should return
+ //from do_timed_wait function. Decrement wait count.
+ unlock_enter_mut = 1 == detail::atomic_dec32(const_cast<boost::uint32_t*>(&m_num_waiters));
+ //Check if this is the last thread of notify_all waiters
+ //Only the last thread will release the interprocess_mutex
+ if(unlock_enter_mut){
+ detail::atomic_cas32(const_cast<boost::uint32_t*>(&m_command), SLEEP, NOTIFY_ALL);
+ }
+ break;
+ }
+ }
+ }
+
+ //Unlock the enter interprocess_mutex if it is a single notification, if this is
+ //the last notified thread in a notify_all or a timeout has occurred
+ if(unlock_enter_mut){
+ m_enter_mut.unlock();
+ }
+
+ //Lock external again before returning from the method
+ mut.lock();
+ return !timed_out;
+}
+
+} //namespace interprocess
+} // namespace boost
Added: sandbox/boost/interprocess/sync/emulation/interprocess_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/emulation/interprocess_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,81 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+inline interprocess_mutex::interprocess_mutex()
+ : m_s(0)
+{
+ //Note that this class is initialized to zero.
+ //So zeroed memory can be interpreted as an
+ //initialized mutex
+}
+
+inline interprocess_mutex::~interprocess_mutex()
+{
+ //Trivial destructor
+}
+
+inline void interprocess_mutex::lock(void)
+{
+ do{
+ boost::uint32_t prev_s = detail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 1, 0);
+
+ if (m_s == 1 && prev_s == 0){
+ break;
+ }
+ // relinquish current timeslice
+ detail::thread_yield();
+ }while (true);
+}
+
+inline bool interprocess_mutex::try_lock(void)
+{
+ boost::uint32_t prev_s = detail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 1, 0);
+ return m_s == 1 && prev_s == 0;
+}
+
+inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ //Obtain current count and target time
+ boost::posix_time::ptime now = microsec_clock::universal_time();
+
+ if(now >= abs_time) return false;
+
+ do{
+ if(this->try_lock()){
+ break;
+ }
+ now = microsec_clock::universal_time();
+
+ if(now >= abs_time){
+ return false;
+ }
+ // relinquish current time slice
+ detail::thread_yield();
+ }while (true);
+
+ return true;
+}
+
+inline void interprocess_mutex::unlock(void)
+{ detail::atomic_cas32(const_cast<boost::uint32_t*>(&m_s), 0, 1); }
+
+} //namespace interprocess {
+
+} //namespace boost {
Added: sandbox/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,118 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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 the pthread code come from Boost Threads code:
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. William E. Kempf makes no representations
+// about the suitability of this software for any purpose.
+// It is provided "as is" without express or implied warranty.
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/detail/os_thread_functions.hpp>
+#include <boost/interprocess/exceptions.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+inline interprocess_recursive_mutex::interprocess_recursive_mutex()
+ : m_nLockCount(0), m_nOwner(detail::get_invalid_systemwide_thread_id()){}
+
+inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){}
+
+inline void interprocess_recursive_mutex::lock()
+{
+ const detail::OS_systemwide_thread_id_t thr_id = detail::get_current_systemwide_thread_id();
+ const detail::OS_systemwide_thread_id_t old_id = m_nOwner;
+ if(detail::equal_systemwide_thread_id(thr_id , old_id)){
+ if((unsigned int)(m_nLockCount+1) == 0){
+ //Overflow, throw an exception
+ throw interprocess_exception();
+ }
+ ++m_nLockCount;
+ }
+ else{
+ m_mutex.lock();
+ m_nOwner = thr_id ;
+ m_nLockCount = 1;
+ }
+}
+
+inline bool interprocess_recursive_mutex::try_lock()
+{
+ const detail::OS_systemwide_thread_id_t thr_id = detail::get_current_systemwide_thread_id();
+ const detail::OS_systemwide_thread_id_t old_id = m_nOwner;
+ if(detail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
+ if((unsigned int)(m_nLockCount+1) == 0){
+ //Overflow, throw an exception
+ throw interprocess_exception();
+ }
+ ++m_nLockCount;
+ return true;
+ }
+ if(m_mutex.try_lock()){
+ m_nOwner = thr_id ;
+ m_nLockCount = 1;
+ return true;
+ }
+ return false;
+}
+
+inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ const detail::OS_systemwide_thread_id_t thr_id = detail::get_current_systemwide_thread_id();
+ const detail::OS_systemwide_thread_id_t old_id = m_nOwner;
+ if(detail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
+ if((unsigned int)(m_nLockCount+1) == 0){
+ //Overflow, throw an exception
+ throw interprocess_exception();
+ }
+ ++m_nLockCount;
+ return true;
+ }
+ if(m_mutex.timed_lock(abs_time)){
+ m_nOwner = thr_id ;
+ m_nLockCount = 1;
+ return true;
+ }
+ return false;
+}
+
+inline void interprocess_recursive_mutex::unlock()
+{
+ const detail::OS_systemwide_thread_id_t old_id = m_nOwner;
+ const detail::OS_systemwide_thread_id_t thr_id = detail::get_current_systemwide_thread_id();
+ (void)old_id;
+ assert(detail::equal_systemwide_thread_id(thr_id, old_id));
+ --m_nLockCount;
+ if(!m_nLockCount){
+ m_nOwner = thr_id;
+ m_mutex.unlock();
+ }
+}
+
+} //namespace interprocess {
+
+} //namespace boost {
+
Added: sandbox/boost/interprocess/sync/emulation/interprocess_semaphore.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/emulation/interprocess_semaphore.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,75 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include<boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+
+namespace boost {
+namespace interprocess {
+
+inline interprocess_semaphore::~interprocess_semaphore()
+{}
+
+inline interprocess_semaphore::interprocess_semaphore(int initialCount)
+ : m_mut(), m_cond(), m_count(initialCount)
+{}
+
+inline void interprocess_semaphore::post()
+{
+ scoped_lock<interprocess_mutex> lock(m_mut);
+ if(m_count == 0){
+ m_cond.notify_one();
+ }
+ ++m_count;
+}
+
+inline void interprocess_semaphore::wait()
+{
+ scoped_lock<interprocess_mutex> lock(m_mut);
+ while(m_count == 0){
+ m_cond.wait(lock);
+ }
+ --m_count;
+}
+
+inline bool interprocess_semaphore::try_wait()
+{
+ scoped_lock<interprocess_mutex> lock(m_mut);
+ if(m_count == 0){
+ return false;
+ }
+ --m_count;
+ return true;
+}
+
+inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait();
+ return true;
+ }
+ scoped_lock<interprocess_mutex> lock(m_mut);
+ while(m_count == 0){
+ if(!m_cond.timed_wait(lock, abs_time))
+ return m_count != 0;
+ }
+ --m_count;
+ return true;
+}
+/*
+inline int interprocess_semaphore::get_count() const
+{
+ scoped_lock<interprocess_mutex> lock(m_mut);
+ return count;
+}*/
+
+} //namespace interprocess {
+} //namespace boost {
Added: sandbox/boost/interprocess/sync/emulation/named_creation_functor.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/emulation/named_creation_functor.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,68 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_SYNC_NAMED_CREATION_FUNCTOR_HPP
+#define BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
+
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+
+namespace boost {
+namespace interprocess {
+namespace detail {
+
+struct named_creation_functor_no_arg{};
+
+template <class T, class Arg = named_creation_functor_no_arg>
+class named_creation_functor
+{
+ typedef named_creation_functor_no_arg no_arg_t;
+ public:
+ named_creation_functor(detail::create_enum_t type, Arg arg = Arg())
+ : m_creation_type(type), m_arg(arg){}
+
+ template<class ArgType>
+ void construct(void *address, typename enable_if_c<is_same<ArgType, no_arg_t>::value>::type * = 0) const
+ { new(address)T; }
+
+ template<class ArgType>
+ void construct(void *address, typename enable_if_c<!is_same<ArgType, no_arg_t>::value>::type * = 0) const
+ { new(address)T(m_arg); }
+
+ bool operator()(void *address, std::size_t, bool created) const
+ {
+ switch(m_creation_type){
+ case detail::DoOpen:
+ return true;
+ break;
+ case detail::DoCreate:
+ case detail::DoOpenOrCreate:
+ if(created){
+ construct<Arg>(address);
+ }
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+ private:
+ detail::create_enum_t m_creation_type;
+ Arg m_arg;
+};
+
+} //namespace detail {
+} //namespace interprocess {
+} //namespace boost {
+
+#endif //BOOST_INTERPROCESS_SYNC_NAMED_CREATION_FUNCTOR_HPP
Added: sandbox/boost/interprocess/sync/file_lock.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/file_lock.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,323 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_LOCK_HPP
+#define BOOST_INTERPROCESS_FILE_LOCK_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/os_file_functions.hpp>
+#include <boost/interprocess/detail/os_thread_functions.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/move_semantics/move.hpp>
+
+//!\file
+//!Describes a class that wraps file locking capabilities.
+
+namespace boost {
+namespace interprocess {
+
+
+//!A file lock, is a mutual exclusion utility similar to a mutex using a
+//!file. A file lock has sharable and exclusive locking capabilities and
+//!can be used with scoped_lock and sharable_lock classes.
+//!A file lock can't guarantee synchronization between threads of the same
+//!process so just use file locks to synchronize threads from different processes.
+class file_lock
+{
+ /// @cond
+ //Non-copyable
+ file_lock(const file_lock &);
+ file_lock &operator=(const file_lock &);
+ /// @endcond
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(file_lock)
+
+ //!Constructs an empty file mapping.
+ //!Does not throw
+ file_lock()
+ : m_file_hnd(file_handle_t(detail::invalid_file()))
+ {}
+
+ //!Opens a file lock. Throws interprocess_exception if the file does not
+ //!exist or there are no operating system resources.
+ file_lock(const char *name);
+
+ //!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
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ file_lock(boost::rv<file_lock> &moved)
+ : m_file_hnd(file_handle_t(detail::invalid_file()))
+ { this->swap(moved.get()); }
+ #else
+ file_lock(file_lock &&moved)
+ : m_file_hnd(file_handle_t(detail::invalid_file()))
+ { this->swap(moved); }
+ #endif
+
+ //!Moves the ownership of "moved"'s file mapping to *this.
+ //!After the call, "moved" does not represent any file mapping.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ file_lock &operator=(boost::rv<file_lock> &moved)
+ #else
+ file_lock &operator=(file_lock &&moved)
+ #endif
+ {
+ file_lock tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Closes a file lock. Does not throw.
+ ~file_lock();
+
+ //!Swaps two file_locks.
+ //!Does not throw.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<file_lock> &moved)
+ { this->swap(moved.get()); }
+ void swap(file_lock &other)
+ #else
+ void swap(file_lock &&other)
+ #endif
+ {
+ file_handle_t tmp = m_file_hnd;
+ m_file_hnd = other.m_file_hnd;
+ other.m_file_hnd = tmp;
+ }
+
+ //Exclusive locking
+
+ //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
+ //! and if another thread has exclusive, or sharable ownership of
+ //! the mutex, it waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock();
+
+ //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
+ //! without waiting. If no other thread has exclusive, or sharable
+ //! ownership of the mutex this succeeds.
+ //!Returns: If it can acquire exclusive ownership immediately returns true.
+ //! If it has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock();
+
+ //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive, or sharable
+ //! ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The calling thread releases the exclusive ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock();
+
+ //Sharable locking
+
+ //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
+ //! and if another thread has exclusive ownership of the mutex, waits until
+ //! it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock_sharable();
+
+ //!Effects: The calling thread tries to acquire sharable ownership of the mutex
+ //! without waiting. If no other thread has has exclusive ownership of the
+ //! mutex this succeeds.
+ //!Returns: If it can acquire sharable ownership immediately returns true. If it
+ //! has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock_sharable();
+
+ //!Effects: The calling thread tries to acquire sharable ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive ownership of
+ //! the mutex or abs_time is reached.
+ //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have sharable ownership of the mutex.
+ //!Effects: The calling thread releases the sharable ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_sharable();
+ /// @cond
+ private:
+ file_handle_t m_file_hnd;
+
+ bool timed_acquire_file_lock
+ (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
+ {
+ //Obtain current count and target time
+ boost::posix_time::ptime now = microsec_clock::universal_time();
+ using namespace boost::detail;
+
+ if(now >= abs_time) return false;
+
+ do{
+ if(!detail::try_acquire_file_lock(hnd, acquired))
+ return false;
+
+ if(acquired)
+ return true;
+ else{
+ now = microsec_clock::universal_time();
+
+ if(now >= abs_time){
+ acquired = false;
+ return true;
+ }
+ // relinquish current time slice
+ detail::thread_yield();
+ }
+ }while (true);
+ }
+
+ bool timed_acquire_file_lock_sharable
+ (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time)
+ {
+ //Obtain current count and target time
+ boost::posix_time::ptime now = microsec_clock::universal_time();
+ using namespace boost::detail;
+
+ if(now >= abs_time) return false;
+
+ do{
+ if(!detail::try_acquire_file_lock_sharable(hnd, acquired))
+ return false;
+
+ if(acquired)
+ return true;
+ else{
+ now = microsec_clock::universal_time();
+
+ if(now >= abs_time){
+ acquired = false;
+ return true;
+ }
+ // relinquish current time slice
+ detail::thread_yield();
+ }
+ }while (true);
+ }
+ /// @endcond
+};
+
+inline file_lock::file_lock(const char *name)
+{
+ m_file_hnd = detail::open_existing_file(name);
+
+ if(m_file_hnd == detail::invalid_file()){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+}
+
+inline file_lock::~file_lock()
+{
+ if(m_file_hnd != detail::invalid_file()){
+ detail::close_file(m_file_hnd);
+ m_file_hnd = detail::invalid_file();
+ }
+}
+
+inline void file_lock::lock()
+{
+ if(!detail::acquire_file_lock(m_file_hnd)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+}
+
+inline bool file_lock::try_lock()
+{
+ bool result;
+ if(!detail::try_acquire_file_lock(m_file_hnd, result)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+ return result;
+}
+
+inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ bool result;
+ if(!this->timed_acquire_file_lock(m_file_hnd, result, abs_time)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+ return result;
+}
+
+inline void file_lock::unlock()
+{
+ if(!detail::release_file_lock(m_file_hnd)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+}
+
+inline void file_lock::lock_sharable()
+{
+ if(!detail::acquire_file_lock_sharable(m_file_hnd)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+}
+
+inline bool file_lock::try_lock_sharable()
+{
+ bool result;
+ if(!detail::try_acquire_file_lock_sharable(m_file_hnd, result)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+ return result;
+}
+
+inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock_sharable();
+ return true;
+ }
+ bool result;
+ if(!this->timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+ return result;
+}
+
+inline void file_lock::unlock_sharable()
+{
+ if(!detail::release_file_lock_sharable(m_file_hnd)){
+ error_info err(system_error_code());
+ throw interprocess_exception(err);
+ }
+}
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_FILE_LOCK_HPP
Added: sandbox/boost/interprocess/sync/interprocess_barrier.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/interprocess_barrier.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,111 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// barrier is a modified version of Boost Threads barrier
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002-2003
+// David Moore, William E. Kempf
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. William E. Kempf makes no representations
+// about the suitability of this software for any purpose.
+// It is provided "as is" without express or implied warranty.
+
+#ifndef BOOST_INTERPROCESS_BARRIER_HPP
+#define BOOST_INTERPROCESS_BARRIER_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED && defined BOOST_INTERPROCESS_POSIX_BARRIERS
+# include <pthread.h>
+# include <errno.h>
+# include <boost/interprocess/sync/posix/pthread_helpers.hpp>
+# define BOOST_INTERPROCESS_USE_POSIX
+#else
+# include <boost/interprocess/sync/interprocess_mutex.hpp>
+# include <boost/interprocess/sync/scoped_lock.hpp>
+# include <boost/interprocess/sync/interprocess_condition.hpp>
+# include <stdexcept>
+# define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+#endif
+
+# include <boost/interprocess/exceptions.hpp>
+
+namespace boost {
+namespace interprocess {
+
+//!An object of class barrier is a synchronization primitive that
+//!can be placed in shared memory used to cause a set of threads from
+//!different processes to wait until they each perform a certain
+//!function or each reach a particular point in their execution.
+class barrier
+{
+ public:
+ //!Constructs a barrier object that will cause count threads
+ //!to block on a call to wait().
+ barrier(unsigned int count);
+
+ //!Destroys *this. If threads are still executing their wait()
+ //!operations, the behavior for these threads is undefined.
+ ~barrier();
+
+ //!Effects: Wait until N threads call wait(), where N equals the count
+ //!provided to the constructor for the barrier object.
+ //!Note that if the barrier is destroyed before wait() can return,
+ //!the behavior is undefined.
+ //!Returns: Exactly one of the N threads will receive a return value
+ //!of true, the others will receive a value of false. Precisely which
+ //!thread receives the return value of true will be implementation-defined.
+ //!Applications can use this value to designate one thread as a leader that
+ //!will take a certain action, and the other threads emerging from the barrier
+ //!can wait for that action to take place.
+ bool wait();
+
+ /// @cond
+ private:
+ #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ interprocess_mutex m_mutex;
+ interprocess_condition m_cond;
+ unsigned int m_threshold;
+ unsigned int m_count;
+ unsigned int m_generation;
+ #else //#if defined BOOST_INTERPROCESS_USE_POSIX
+ pthread_barrier_t m_barrier;
+ #endif//#if defined BOOST_INTERPROCESS_USE_POSIX
+ /// @endcond
+};
+
+} // namespace interprocess
+} // namespace boost
+
+
+#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# include <boost/interprocess/sync/emulation/interprocess_barrier.hpp>
+#endif
+
+#ifdef BOOST_INTERPROCESS_USE_POSIX
+# undef BOOST_INTERPROCESS_USE_POSIX
+# include <boost/interprocess/sync/posix/interprocess_barrier.hpp>
+#endif
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif
Added: sandbox/boost/interprocess/sync/interprocess_condition.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/interprocess_condition.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,175 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_CONDITION_HPP
+#define BOOST_INTERPROCESS_CONDITION_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/interprocess/sync/interprocess_condition.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/limits.hpp>
+#include <cassert>
+
+#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+ #include <pthread.h>
+ #include <errno.h>
+ #include <boost/interprocess/sync/posix/pthread_helpers.hpp>
+ #define BOOST_INTERPROCESS_USE_POSIX
+#else
+ #include <boost/interprocess/detail/atomic.hpp>
+ #include <boost/cstdint.hpp>
+ #include <boost/interprocess/detail/os_thread_functions.hpp>
+ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+#endif
+
+//!\file
+//!Describes process-shared variables interprocess_condition class
+
+namespace boost {
+
+namespace posix_time
+{ class ptime; }
+
+namespace interprocess {
+
+class named_condition;
+
+//!This class is a condition variable that can be placed in shared memory or
+//!memory mapped files.
+class interprocess_condition
+{
+ /// @cond
+ //Non-copyable
+ interprocess_condition(const interprocess_condition &);
+ interprocess_condition &operator=(const interprocess_condition &);
+ friend class named_condition;
+ /// @endcond
+ public:
+ //!Constructs a interprocess_condition. On error throws interprocess_exception.
+ interprocess_condition();
+
+ //!Destroys *this
+ //!liberating system resources.
+ ~interprocess_condition();
+
+ //!If there is a thread waiting on *this, change that
+ //!thread's state to ready. Otherwise there is no effect.
+ void notify_one();
+
+ //!Change the state of all threads waiting on *this to ready.
+ //!If there are no waiting threads, notify_all() has no effect.
+ void notify_all();
+
+ //!Releases the lock on the interprocess_mutex object associated with lock, blocks
+ //!the current thread of execution until readied by a call to
+ //!this->notify_one() or this->notify_all(), and then reacquires the lock.
+ template <typename L>
+ void wait(L& lock)
+ {
+ if (!lock)
+ throw lock_exception();
+ do_wait(*lock.mutex());
+ }
+
+ //!The same as:
+ //!while (!pred()) wait(lock)
+ template <typename L, typename Pr>
+ void wait(L& lock, Pr pred)
+ {
+ if (!lock)
+ throw lock_exception();
+
+ while (!pred())
+ do_wait(*lock.mutex());
+ }
+
+ //!Releases the lock on the interprocess_mutex object associated with lock, blocks
+ //!the current thread of execution until readied by a call to
+ //!this->notify_one() or this->notify_all(), or until time abs_time is reached,
+ //!and then reacquires the lock.
+ //!Returns: false if time abs_time is reached, otherwise true.
+ template <typename L>
+ bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
+ {
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait(lock);
+ return true;
+ }
+ if (!lock)
+ throw lock_exception();
+ return do_timed_wait(abs_time, *lock.mutex());
+ }
+
+ //!The same as: while (!pred()) {
+ //! if (!timed_wait(lock, abs_time)) return pred();
+ //! } return true;
+ template <typename L, typename Pr>
+ bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
+ {
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait(lock, pred);
+ return true;
+ }
+ if (!lock)
+ throw lock_exception();
+ while (!pred()){
+ if (!do_timed_wait(abs_time, *lock.mutex()))
+ return pred();
+ }
+
+ return true;
+ }
+
+ /// @cond
+ private:
+ void do_wait(interprocess_mutex &mut);
+
+ bool do_timed_wait(const boost::posix_time::ptime &abs_time, interprocess_mutex &mut);
+
+ #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ enum { SLEEP = 0, NOTIFY_ONE, NOTIFY_ALL };
+ interprocess_mutex m_enter_mut;
+ interprocess_mutex m_check_mut;
+ volatile boost::uint32_t m_command;
+ volatile boost::uint32_t m_num_waiters;
+ bool do_timed_wait(bool tout_enabled, const boost::posix_time::ptime &abs_time, interprocess_mutex &mut);
+ void notify(boost::uint32_t command);
+ #elif defined(BOOST_INTERPROCESS_USE_POSIX)
+ pthread_cond_t m_condition;
+ #endif
+ /// @endcond
+};
+
+} //namespace interprocess
+
+} // namespace boost
+
+#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# include <boost/interprocess/sync/emulation/interprocess_condition.hpp>
+#endif
+
+#ifdef BOOST_INTERPROCESS_USE_POSIX
+# undef BOOST_INTERPROCESS_USE_POSIX
+# include <boost/interprocess/sync/posix/interprocess_condition.hpp>
+#endif
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_CONDITION_HPP
Added: sandbox/boost/interprocess/sync/interprocess_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/interprocess_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,133 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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 the pthread code come from Boost Threads code.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. William E. Kempf makes no representations
+// about the suitability of this software for any purpose.
+// It is provided "as is" without express or implied warranty.
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_MUTEX_HPP
+#define BOOST_INTERPROCESS_MUTEX_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <cassert>
+
+#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+ #include <pthread.h>
+ #include <errno.h>
+ #include <boost/interprocess/sync/posix/pthread_helpers.hpp>
+ #define BOOST_INTERPROCESS_USE_POSIX
+#else
+ #include <boost/interprocess/detail/atomic.hpp>
+ #include <boost/cstdint.hpp>
+ #include <boost/interprocess/detail/os_thread_functions.hpp>
+ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+#endif
+
+//!\file
+//!Describes a mutex class that can be placed in memory shared by
+//!several processes.
+
+namespace boost {
+namespace interprocess {
+
+class interprocess_condition;
+
+//!Wraps a interprocess_mutex that can be placed in shared memory and can be
+//!shared between processes. Allows timed lock tries
+class interprocess_mutex
+{
+ /// @cond
+ //Non-copyable
+ interprocess_mutex(const interprocess_mutex &);
+ interprocess_mutex &operator=(const interprocess_mutex &);
+ friend class interprocess_condition;
+ /// @endcond
+ public:
+
+ //!Constructor.
+ //!Throws interprocess_exception on error.
+ interprocess_mutex();
+
+ //!Destructor. If any process uses the mutex after the destructor is called
+ //!the result is undefined. Does not throw.
+ ~interprocess_mutex();
+
+ //!Effects: The calling thread tries to obtain ownership of the mutex, and
+ //! if another thread has ownership of the mutex, it waits until it can
+ //! obtain the ownership. If a thread takes ownership of the mutex the
+ //! mutex must be unlocked by the same mutex.
+ //!Throws: interprocess_exception on error.
+ void lock();
+
+ //!Effects: The calling thread tries to obtain ownership of the mutex, and
+ //! if another thread has ownership of the mutex returns immediately.
+ //!Returns: If the thread acquires ownership of the mutex, returns true, if
+ //! the another thread has ownership of the mutex, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock();
+
+ //!Effects: The calling thread will try to obtain exclusive ownership of the
+ //! mutex if it can do so in until the specified time is reached. If the
+ //! mutex supports recursive locking, the mutex must be unlocked the same
+ //! number of times it is locked.
+ //!Returns: If the thread acquires ownership of the mutex, returns true, if
+ //! the timeout expires returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Effects: The calling thread releases the exclusive ownership of the mutex.
+ //!Throws: interprocess_exception on error.
+ void unlock();
+ /// @cond
+ private:
+
+ #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ volatile boost::uint32_t m_s;
+ #elif defined(BOOST_INTERPROCESS_USE_POSIX)
+ pthread_mutex_t m_mut;
+ #endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
+ /// @endcond
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# include <boost/interprocess/sync/emulation/interprocess_mutex.hpp>
+#endif
+
+#ifdef BOOST_INTERPROCESS_USE_POSIX
+# undef BOOST_INTERPROCESS_USE_POSIX
+# include <boost/interprocess/sync/posix/interprocess_mutex.hpp>
+#endif
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_MUTEX_HPP
Added: sandbox/boost/interprocess/sync/interprocess_recursive_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/interprocess_recursive_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Parts of the pthread code come from Boost Threads code:
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. William E. Kempf makes no representations
+// about the suitability of this software for any purpose.
+// It is provided "as is" without express or implied warranty.
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
+#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <cassert>
+
+#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \
+ (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES))
+ #include <pthread.h>
+ #include <errno.h>
+ #include <boost/interprocess/sync/posix/pthread_helpers.hpp>
+ #define BOOST_INTERPROCESS_USE_POSIX
+#else
+ #include <boost/interprocess/detail/atomic.hpp>
+ #include <boost/cstdint.hpp>
+ #include <boost/interprocess/detail/os_thread_functions.hpp>
+ #include <boost/interprocess/sync/interprocess_mutex.hpp>
+ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+#endif
+
+//!\file
+//!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes
+
+namespace boost {
+
+namespace interprocess {
+
+//!Wraps a interprocess_mutex that can be placed in shared memory and can be
+//!shared between processes. Allows several locking calls by the same
+//!process. Allows timed lock tries
+class interprocess_recursive_mutex
+{
+ /// @cond
+ //Non-copyable
+ interprocess_recursive_mutex(const interprocess_recursive_mutex &);
+ interprocess_recursive_mutex &operator=(const interprocess_recursive_mutex &);
+ /// @endcond
+ public:
+ //!Constructor.
+ //!Throws interprocess_exception on error.
+ interprocess_recursive_mutex();
+
+ //!Destructor. If any process uses the mutex after the destructor is called
+ //!the result is undefined. Does not throw.
+ ~interprocess_recursive_mutex();
+
+ //!Effects: The calling thread tries to obtain ownership of the mutex, and
+ //! if another thread has ownership of the mutex, it waits until it can
+ //! obtain the ownership. If a thread takes ownership of the mutex the
+ //! mutex must be unlocked by the same mutex. The mutex must be unlocked
+ //! the same number of times it is locked.
+ //!Throws: interprocess_exception on error.
+ void lock(void);
+
+ //!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
+ //!is already locked, returns true when success. The mutex must be unlocked
+ //!the same number of times it is locked.
+ //!Throws: interprocess_exception if a severe error is found
+ bool try_lock(void);
+
+ //!Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before
+ //!abs_time time, returns false. The mutex must be unlocked
+ //! the same number of times it is locked.
+ //!Throws: interprocess_exception if a severe error is found
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Effects: The calling thread releases the exclusive ownership of the mutex.
+ //! If the mutex supports recursive locking, the mutex must be unlocked the
+ //! same number of times it is locked.
+ //!Throws: interprocess_exception on error.
+ void unlock(void);
+ /// @cond
+ private:
+ #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ interprocess_mutex m_mutex;
+ unsigned int m_nLockCount;
+ volatile detail::OS_systemwide_thread_id_t m_nOwner;
+ #else //#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ pthread_mutex_t m_mut;
+ #endif //#if (defined BOOST_INTERPROCESS_WINDOWS)
+ /// @endcond
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# include <boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp>
+#endif
+
+#ifdef BOOST_INTERPROCESS_USE_POSIX
+# undef BOOST_INTERPROCESS_USE_POSIX
+# include <boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp>
+#endif
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
Added: sandbox/boost/interprocess/sync/interprocess_semaphore.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/interprocess_semaphore.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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_SEMAPHORE_HPP
+#define BOOST_INTERPROCESS_SEMAPHORE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \
+ (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES))
+ #include <fcntl.h> //O_CREAT, O_*...
+ #include <unistd.h> //close
+ #include <string> //std::string
+ #include <semaphore.h> //sem_* family, SEM_VALUE_MAX
+ #include <sys/stat.h> //mode_t, S_IRWXG, S_IRWXO, S_IRWXU,
+ #include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
+ #define BOOST_INTERPROCESS_USE_POSIX
+#else
+ #include <boost/interprocess/detail/atomic.hpp>
+ #include <boost/cstdint.hpp>
+ #include <boost/interprocess/detail/os_thread_functions.hpp>
+ #include <boost/interprocess/sync/interprocess_mutex.hpp>
+ #include <boost/interprocess/sync/interprocess_condition.hpp>
+ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+#endif
+
+//!\file
+//!Describes a interprocess_semaphore class for inter-process synchronization
+
+namespace boost {
+
+namespace interprocess {
+
+//!Wraps a interprocess_semaphore that can be placed in shared memory and can be
+//!shared between processes. Allows timed lock tries
+class interprocess_semaphore
+{
+ /// @cond
+ //Non-copyable
+ interprocess_semaphore(const interprocess_semaphore &);
+ interprocess_semaphore &operator=(const interprocess_semaphore &);
+ /// @endcond
+ public:
+ //!Creates a interprocess_semaphore with the given initial count.
+ //!interprocess_exception if there is an error.*/
+ interprocess_semaphore(int initialCount);
+
+ //!Destroys the interprocess_semaphore.
+ //!Does not throw
+ ~interprocess_semaphore();
+
+ //!Increments the interprocess_semaphore count. If there are processes/threads blocked waiting
+ //!for the interprocess_semaphore, then one of these processes will return successfully from
+ //!its wait function. If there is an error an interprocess_exception exception is thrown.
+ void post();
+
+ //!Decrements the interprocess_semaphore. If the interprocess_semaphore value is not greater than zero,
+ //!then the calling process/thread blocks until it can decrement the counter.
+ //!If there is an error an interprocess_exception exception is thrown.
+ void wait();
+
+ //!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater than zero
+ //!and returns true. If the value is not greater than zero returns false.
+ //!If there is an error an interprocess_exception exception is thrown.
+ bool try_wait();
+
+ //!Decrements the interprocess_semaphore if the interprocess_semaphore's value is greater
+ //!than zero and returns true. Otherwise, waits for the interprocess_semaphore
+ //!to the posted or the timeout expires. If the timeout expires, the
+ //!function returns false. If the interprocess_semaphore is posted the function
+ //!returns true. If there is an error throws sem_exception
+ bool timed_wait(const boost::posix_time::ptime &abs_time);
+
+ //!Returns the interprocess_semaphore count
+// int get_count() const;
+ /// @cond
+ private:
+ #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ interprocess_mutex m_mut;
+ interprocess_condition m_cond;
+ int m_count;
+ #else
+ detail::semaphore_wrapper m_sem;
+ #endif //#if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
+ /// @endcond
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#ifdef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
+# include <boost/interprocess/sync/emulation/interprocess_semaphore.hpp>
+#endif
+
+#ifdef BOOST_INTERPROCESS_USE_POSIX
+# undef BOOST_INTERPROCESS_USE_POSIX
+# include <boost/interprocess/sync/posix/interprocess_semaphore.hpp>
+#endif
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_SEMAPHORE_HPP
Added: sandbox/boost/interprocess/sync/interprocess_upgradable_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/interprocess_upgradable_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,658 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_UPGRADABLE_MUTEX_HPP
+#define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/sync/interprocess_condition.hpp>
+#include <climits>
+
+
+//!\file
+//!Describes interprocess_upgradable_mutex class
+
+namespace boost {
+namespace interprocess {
+
+//!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
+//!shared between processes. Allows timed lock tries
+class interprocess_upgradable_mutex
+{
+ //Non-copyable
+ interprocess_upgradable_mutex(const interprocess_upgradable_mutex &);
+ interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &);
+
+ friend class interprocess_condition;
+ public:
+
+ //!Constructs the upgradable lock.
+ //!Throws interprocess_exception on error.
+ interprocess_upgradable_mutex();
+
+ //!Destroys the upgradable lock.
+ //!Does not throw.
+ ~interprocess_upgradable_mutex();
+
+ //Exclusive locking
+
+ //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
+ //! and if another thread has exclusive, sharable or upgradable ownership of
+ //! the mutex, it waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock();
+
+ //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
+ //! without waiting. If no other thread has exclusive, sharable or upgradable
+ //! ownership of the mutex this succeeds.
+ //!Returns: If it can acquire exclusive ownership immediately returns true.
+ //! If it has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock();
+
+ //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive, sharable or
+ //! upgradable ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The calling thread releases the exclusive ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock();
+
+ //Sharable locking
+
+ //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
+ //! and if another thread has exclusive or upgradable ownership of the mutex,
+ //! waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock_sharable();
+
+ //!Effects: The calling thread tries to acquire sharable ownership of the mutex
+ //! without waiting. If no other thread has has exclusive or upgradable ownership
+ //! of the mutex this succeeds.
+ //!Returns: If it can acquire sharable ownership immediately returns true. If it
+ //! has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock_sharable();
+
+ //!Effects: The calling thread tries to acquire sharable ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive or upgradable
+ //! ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have sharable ownership of the mutex.
+ //!Effects: The calling thread releases the sharable ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_sharable();
+
+ //Upgradable locking
+
+ //!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
+ //! and if another thread has exclusive or upgradable ownership of the mutex,
+ //! waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock_upgradable();
+
+ //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
+ //! without waiting. If no other thread has has exclusive or upgradable ownership
+ //! of the mutex this succeeds.
+ //!Returns: If it can acquire upgradable ownership immediately returns true.
+ //! If it has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock_upgradable();
+
+ //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive or upgradable
+ //! ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The calling thread releases the upgradable ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_upgradable();
+
+ //Demotions
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The thread atomically releases exclusive ownership and acquires
+ //! upgradable ownership. This operation is non-blocking.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_and_lock_upgradable();
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The thread atomically releases exclusive ownership and acquires
+ //! sharable ownership. This operation is non-blocking.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_and_lock_sharable();
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and acquires
+ //! sharable ownership. This operation is non-blocking.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_upgradable_and_lock_sharable();
+
+ //Promotions
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and acquires
+ //! exclusive ownership. This operation will block until all threads with
+ //! sharable ownership release their sharable lock.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_upgradable_and_lock();
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and tries to
+ //! acquire exclusive ownership. This operation will fail if there are threads
+ //! with sharable ownership, but it will maintain upgradable ownership.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error.
+ bool try_unlock_upgradable_and_lock();
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and tries to acquire
+ //! exclusive ownership, waiting if necessary until abs_time. This operation will
+ //! fail if there are threads with sharable ownership or timeout reaches, but it
+ //! will maintain upgradable ownership.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error. */
+ bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have sharable ownership of the mutex.
+ //!Effects: The thread atomically releases sharable ownership and tries to acquire
+ //! exclusive ownership. This operation will fail if there are threads with sharable
+ //! or upgradable ownership, but it will maintain sharable ownership.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error.
+ bool try_unlock_sharable_and_lock();
+
+ //!Precondition: The thread must have sharable ownership of the mutex.
+ //!Effects: The thread atomically releases sharable ownership and tries to acquire
+ //! upgradable ownership. This operation will fail if there are threads with sharable
+ //! or upgradable ownership, but it will maintain sharable ownership.
+ //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error.
+ bool try_unlock_sharable_and_lock_upgradable();
+
+ /// @cond
+ private:
+ typedef scoped_lock<interprocess_mutex> scoped_lock_t;
+
+ //Pack all the control data in a word to be able
+ //to use atomic instructions in the future
+ struct control_word_t
+ {
+ unsigned exclusive_in : 1;
+ unsigned upgradable_in : 1;
+ unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2;
+ } m_ctrl;
+
+ interprocess_mutex m_mut;
+ interprocess_condition m_first_gate;
+ interprocess_condition m_second_gate;
+
+ private:
+ //Rollback structures for exceptions or failure return values
+ struct exclusive_rollback
+ {
+ exclusive_rollback(control_word_t &ctrl
+ ,interprocess_condition &first_gate)
+ : mp_ctrl(&ctrl), m_first_gate(first_gate)
+ {}
+
+ void release()
+ { mp_ctrl = 0; }
+
+ ~exclusive_rollback()
+ {
+ if(mp_ctrl){
+ mp_ctrl->exclusive_in = 0;
+ m_first_gate.notify_all();
+ }
+ }
+ control_word_t *mp_ctrl;
+ interprocess_condition &m_first_gate;
+ };
+
+ struct upgradable_to_exclusive_rollback
+ {
+ upgradable_to_exclusive_rollback(control_word_t &ctrl)
+ : mp_ctrl(&ctrl)
+ {}
+
+ void release()
+ { mp_ctrl = 0; }
+
+ ~upgradable_to_exclusive_rollback()
+ {
+ if(mp_ctrl){
+ //Recover upgradable lock
+ mp_ctrl->upgradable_in = 1;
+ ++mp_ctrl->num_upr_shar;
+ //Execute the second half of exclusive locking
+ mp_ctrl->exclusive_in = 0;
+ }
+ }
+ control_word_t *mp_ctrl;
+ };
+
+ template<int Dummy>
+ struct base_constants_t
+ {
+ static const unsigned max_readers
+ = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2));
+ };
+ typedef base_constants_t<0> constants;
+ /// @endcond
+};
+
+/// @cond
+
+template <int Dummy>
+const unsigned interprocess_upgradable_mutex::base_constants_t<Dummy>::max_readers;
+
+inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
+{
+ this->m_ctrl.exclusive_in = 0;
+ this->m_ctrl.upgradable_in = 0;
+ this->m_ctrl.num_upr_shar = 0;
+}
+
+inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
+{}
+
+inline void interprocess_upgradable_mutex::lock()
+{
+ scoped_lock_t lock(m_mut);
+
+ //The exclusive lock must block in the first gate
+ //if an exclusive or upgradable lock has been acquired
+ while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
+ this->m_first_gate.wait(lock);
+ }
+
+ //Mark that exclusive lock has been acquired
+ this->m_ctrl.exclusive_in = 1;
+
+ //Prepare rollback
+ exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
+
+ //Now wait until all readers are gone
+ while (this->m_ctrl.num_upr_shar){
+ this->m_second_gate.wait(lock);
+ }
+ rollback.release();
+}
+
+inline bool interprocess_upgradable_mutex::try_lock()
+{
+ scoped_lock_t lock(m_mut, try_to_lock);
+
+ //If we can't lock or any has there is any exclusive, upgradable
+ //or sharable mark return false;
+ if(!lock.owns()
+ || this->m_ctrl.exclusive_in
+ || this->m_ctrl.num_upr_shar){
+ return false;
+ }
+ this->m_ctrl.exclusive_in = 1;
+ return true;
+}
+
+inline bool interprocess_upgradable_mutex::timed_lock
+ (const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ scoped_lock_t lock(m_mut, abs_time);
+ if(!lock.owns()) return false;
+
+ //The exclusive lock must block in the first gate
+ //if an exclusive or upgradable lock has been acquired
+ while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
+ if(!this->m_first_gate.timed_wait(lock, abs_time))
+ return !(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in);
+ }
+
+ //Mark that exclusive lock has been acquired
+ this->m_ctrl.exclusive_in = 1;
+
+ //Prepare rollback
+ exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
+
+ //Now wait until all readers are gone
+ while (this->m_ctrl.num_upr_shar){
+ if(!this->m_second_gate.timed_wait(lock, abs_time)){
+ return !(this->m_ctrl.num_upr_shar);
+ }
+ }
+ rollback.release();
+ return true;
+}
+
+inline void interprocess_upgradable_mutex::unlock()
+{
+ scoped_lock_t lock(m_mut);
+ this->m_ctrl.exclusive_in = 0;
+ this->m_first_gate.notify_all();
+}
+
+//Upgradable locking
+
+inline void interprocess_upgradable_mutex::lock_upgradable()
+{
+ scoped_lock_t lock(m_mut);
+
+ //The upgradable lock must block in the first gate
+ //if an exclusive or upgradable lock has been acquired
+ //or there are too many sharable locks
+ while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers){
+ this->m_first_gate.wait(lock);
+ }
+
+ //Mark that upgradable lock has been acquired
+ //And add upgradable to the sharable count
+ this->m_ctrl.upgradable_in = 1;
+ ++this->m_ctrl.num_upr_shar;
+}
+
+inline bool interprocess_upgradable_mutex::try_lock_upgradable()
+{
+ scoped_lock_t lock(m_mut, try_to_lock);
+
+ //The upgradable lock must fail
+ //if an exclusive or upgradable lock has been acquired
+ //or there are too many sharable locks
+ if(!lock.owns()
+ || this->m_ctrl.exclusive_in
+ || this->m_ctrl.upgradable_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers){
+ return false;
+ }
+
+ //Mark that upgradable lock has been acquired
+ //And add upgradable to the sharable count
+ this->m_ctrl.upgradable_in = 1;
+ ++this->m_ctrl.num_upr_shar;
+ return true;
+}
+
+inline bool interprocess_upgradable_mutex::timed_lock_upgradable
+ (const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock_upgradable();
+ return true;
+ }
+ scoped_lock_t lock(m_mut, abs_time);
+ if(!lock.owns()) return false;
+
+ //The upgradable lock must block in the first gate
+ //if an exclusive or upgradable lock has been acquired
+ //or there are too many sharable locks
+ while(this->m_ctrl.exclusive_in
+ || this->m_ctrl.upgradable_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers){
+ if(!this->m_first_gate.timed_wait(lock, abs_time)){
+ return!(this->m_ctrl.exclusive_in
+ || this->m_ctrl.upgradable_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers);
+ }
+ }
+
+ //Mark that upgradable lock has been acquired
+ //And add upgradable to the sharable count
+ this->m_ctrl.upgradable_in = 1;
+ ++this->m_ctrl.num_upr_shar;
+ return true;
+}
+
+inline void interprocess_upgradable_mutex::unlock_upgradable()
+{
+ scoped_lock_t lock(m_mut);
+ //Mark that upgradable lock has been acquired
+ //And add upgradable to the sharable count
+ this->m_ctrl.upgradable_in = 0;
+ --this->m_ctrl.num_upr_shar;
+ this->m_first_gate.notify_all();
+}
+
+//Sharable locking
+
+inline void interprocess_upgradable_mutex::lock_sharable()
+{
+ scoped_lock_t lock(m_mut);
+
+ //The sharable lock must block in the first gate
+ //if an exclusive lock has been acquired
+ //or there are too many sharable locks
+ while(this->m_ctrl.exclusive_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers){
+ this->m_first_gate.wait(lock);
+ }
+
+ //Increment sharable count
+ ++this->m_ctrl.num_upr_shar;
+}
+
+inline bool interprocess_upgradable_mutex::try_lock_sharable()
+{
+ scoped_lock_t lock(m_mut, try_to_lock);
+
+ //The sharable lock must fail
+ //if an exclusive lock has been acquired
+ //or there are too many sharable locks
+ if(!lock.owns()
+ || this->m_ctrl.exclusive_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers){
+ return false;
+ }
+
+ //Increment sharable count
+ ++this->m_ctrl.num_upr_shar;
+ return true;
+}
+
+inline bool interprocess_upgradable_mutex::timed_lock_sharable
+ (const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock_sharable();
+ return true;
+ }
+ scoped_lock_t lock(m_mut, abs_time);
+ if(!lock.owns()) return false;
+
+ //The sharable lock must block in the first gate
+ //if an exclusive lock has been acquired
+ //or there are too many sharable locks
+ while (this->m_ctrl.exclusive_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers){
+ if(!this->m_first_gate.timed_wait(lock, abs_time)){
+ return!(this->m_ctrl.exclusive_in
+ || this->m_ctrl.num_upr_shar == constants::max_readers);
+ }
+ }
+
+ //Increment sharable count
+ ++this->m_ctrl.num_upr_shar;
+ return true;
+}
+
+inline void interprocess_upgradable_mutex::unlock_sharable()
+{
+ scoped_lock_t lock(m_mut);
+ //Decrement sharable count
+ --this->m_ctrl.num_upr_shar;
+ if (this->m_ctrl.num_upr_shar == 0){
+ this->m_second_gate.notify_one();
+ }
+ //Check if there are blocked sharables because of
+ //there were too many sharables
+ else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){
+ this->m_first_gate.notify_all();
+ }
+}
+
+//Downgrading
+
+inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
+{
+ scoped_lock_t lock(m_mut);
+ //Unmark it as exclusive
+ this->m_ctrl.exclusive_in = 0;
+ //Mark it as upgradable
+ this->m_ctrl.upgradable_in = 1;
+ //The sharable count should be 0 so increment it
+ this->m_ctrl.num_upr_shar = 1;
+ //Notify readers that they can enter
+ m_first_gate.notify_all();
+}
+
+inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
+{
+ scoped_lock_t lock(m_mut);
+ //Unmark it as exclusive
+ this->m_ctrl.exclusive_in = 0;
+ //The sharable count should be 0 so increment it
+ this->m_ctrl.num_upr_shar = 1;
+ //Notify readers that they can enter
+ m_first_gate.notify_all();
+}
+
+inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
+{
+ scoped_lock_t lock(m_mut);
+ //Unmark it as upgradable (we don't have to decrement count)
+ this->m_ctrl.upgradable_in = 0;
+ //Notify readers/upgradable that they can enter
+ m_first_gate.notify_all();
+}
+
+//Upgrading
+
+inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
+{
+ scoped_lock_t lock(m_mut);
+ //Simulate unlock_upgradable() without
+ //notifying sharables.
+ this->m_ctrl.upgradable_in = 0;
+ --this->m_ctrl.num_upr_shar;
+ //Execute the second half of exclusive locking
+ this->m_ctrl.exclusive_in = 1;
+
+ //Prepare rollback
+ upgradable_to_exclusive_rollback rollback(m_ctrl);
+
+ while (this->m_ctrl.num_upr_shar){
+ this->m_second_gate.wait(lock);
+ }
+ rollback.release();
+}
+
+inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
+{
+ scoped_lock_t lock(m_mut, try_to_lock);
+ //Check if there are no readers
+ if(!lock.owns()
+ || this->m_ctrl.num_upr_shar != 1){
+ return false;
+ }
+ //Now unlock upgradable and mark exclusive
+ this->m_ctrl.upgradable_in = 0;
+ --this->m_ctrl.num_upr_shar;
+ this->m_ctrl.exclusive_in = 1;
+ return true;
+}
+
+inline bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock
+ (const boost::posix_time::ptime &abs_time)
+{
+ scoped_lock_t lock(m_mut, abs_time);
+ if(!lock.owns()) return false;
+
+ //Simulate unlock_upgradable() without
+ //notifying sharables.
+ this->m_ctrl.upgradable_in = 0;
+ --this->m_ctrl.num_upr_shar;
+ //Execute the second half of exclusive locking
+ this->m_ctrl.exclusive_in = 1;
+
+ //Prepare rollback
+ upgradable_to_exclusive_rollback rollback(m_ctrl);
+
+ while (this->m_ctrl.num_upr_shar){
+ if(!this->m_second_gate.timed_wait(lock, abs_time)){
+ return !(this->m_ctrl.num_upr_shar);
+ }
+ }
+ rollback.release();
+ return true;
+}
+
+inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
+{
+ scoped_lock_t lock(m_mut, try_to_lock);
+
+ //If we can't lock or any has there is any exclusive, upgradable
+ //or sharable mark return false;
+ if(!lock.owns()
+ || this->m_ctrl.exclusive_in
+ || this->m_ctrl.upgradable_in
+ || this->m_ctrl.num_upr_shar != 1){
+ return false;
+ }
+ this->m_ctrl.exclusive_in = 1;
+ this->m_ctrl.num_upr_shar = 0;
+ return true;
+}
+
+inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
+{
+ scoped_lock_t lock(m_mut, try_to_lock);
+
+ //The upgradable lock must fail
+ //if an exclusive or upgradable lock has been acquired
+ if(!lock.owns()
+ || this->m_ctrl.exclusive_in
+ || this->m_ctrl.upgradable_in){
+ return false;
+ }
+
+ //Mark that upgradable lock has been acquired
+ this->m_ctrl.upgradable_in = 1;
+ return true;
+}
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
Added: sandbox/boost/interprocess/sync/lock_options.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/lock_options.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,55 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_LOCK_OPTIONS_HPP
+#define BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+//!\file
+//!Describes the lock options with associated with interprocess_mutex lock constructors.
+
+namespace boost {
+
+namespace posix_time
+{ class ptime; }
+
+namespace interprocess {
+
+//!Type to indicate to a mutex lock constructor that must not lock the mutex.
+struct defer_lock_type{};
+//!Type to indicate to a mutex lock constructor that must try to lock the mutex.
+struct try_to_lock_type {};
+//!Type to indicate to a mutex lock constructor that the mutex is already locked.
+struct accept_ownership_type{};
+
+//!An object indicating that the locking
+//!must be deferred.
+static const defer_lock_type defer_lock = defer_lock_type();
+
+//!An object indicating that a try_lock()
+//!operation must be executed.
+static const try_to_lock_type try_to_lock = try_to_lock_type();
+
+//!An object indicating that the ownership of lockable
+//!object must be accepted by the new owner.
+static const accept_ownership_type accept_ownership = accept_ownership_type();
+
+} // namespace interprocess {
+} // namespace boost{
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_LOCK_OPTIONS_HPP
Added: sandbox/boost/interprocess/sync/mutex_family.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/mutex_family.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,56 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MUTEX_FAMILY_HPP
+#define BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
+#include <boost/interprocess/sync/null_mutex.hpp>
+
+//!\file
+//!Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory.
+
+namespace boost {
+
+namespace interprocess {
+
+//!Describes interprocess_mutex family to use with Interprocess framework
+//!based on boost::interprocess synchronization objects.
+struct mutex_family
+{
+ typedef boost::interprocess::interprocess_mutex mutex_type;
+ typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_type;
+};
+
+//!Describes interprocess_mutex family to use with Interprocess frameworks
+//!based on null operation synchronization objects.
+struct null_mutex_family
+{
+ typedef boost::interprocess::null_mutex mutex_type;
+ typedef boost::interprocess::null_mutex recursive_mutex_type;
+};
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
+
+
Added: sandbox/boost/interprocess/sync/named_condition.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/named_condition.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -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_NAMED_CONDITION_HPP
+#define BOOST_INTERPROCESS_NAMED_CONDITION_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/sync/interprocess_condition.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
+#include <boost/interprocess/sync/named_mutex.hpp>
+#if defined BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/sync/scoped_lock.hpp>
+#endif
+
+
+//!\file
+//!Describes process-shared variables interprocess_condition class
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail{ class interprocess_tester; }
+/// @endcond
+
+//! A global condition variable that can be created by name.
+//! This condition variable is designed to work with named_mutex and
+//! can't be placed in shared memory or memory mapped files.
+class named_condition
+{
+ /// @cond
+ //Non-copyable
+ named_condition();
+ named_condition(const named_condition &);
+ named_condition &operator=(const named_condition &);
+ /// @endcond
+ public:
+ //!Creates a global condition with a name.
+ //!If the condition can't be created throws interprocess_exception
+ named_condition(create_only_t create_only, const char *name);
+
+ //!Opens or creates a global condition with a name.
+ //!If the condition is created, this call is equivalent to
+ //!named_condition(create_only_t, ... )
+ //!If the condition is already created, this call is equivalent
+ //!named_condition(open_only_t, ... )
+ //!Does not throw
+ named_condition(open_or_create_t open_or_create, const char *name);
+
+ //!Opens a global condition with a name if that condition is previously
+ //!created. If it is not previously created this function throws
+ //!interprocess_exception.
+ named_condition(open_only_t open_only, const char *name);
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~named_condition();
+
+ //!If there is a thread waiting on *this, change that
+ //!thread's state to ready. Otherwise there is no effect.*/
+ void notify_one();
+
+ //!Change the state of all threads waiting on *this to ready.
+ //!If there are no waiting threads, notify_all() has no effect.
+ void notify_all();
+
+ //!Releases the lock on the named_mutex object associated with lock, blocks
+ //!the current thread of execution until readied by a call to
+ //!this->notify_one() or this->notify_all(), and then reacquires the lock.
+ template <typename L>
+ void wait(L& lock);
+
+ //!The same as:
+ //!while (!pred()) wait(lock)
+ template <typename L, typename Pr>
+ void wait(L& lock, Pr pred);
+
+ //!Releases the lock on the named_mutex object associated with lock, blocks
+ //!the current thread of execution until readied by a call to
+ //!this->notify_one() or this->notify_all(), or until time abs_time is reached,
+ //!and then reacquires the lock.
+ //!Returns: false if time abs_time is reached, otherwise true.
+ template <typename L>
+ bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time);
+
+ //!The same as: while (!pred()) {
+ //! if (!timed_wait(lock, abs_time)) return pred();
+ //! } return true;
+ template <typename L, typename Pr>
+ bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred);
+
+ //!Erases a named condition from the system.
+ //!Returns false on error. Never throws.
+ static bool remove(const char *name);
+
+ /// @cond
+ private:
+
+ struct condition_holder
+ {
+ interprocess_condition cond_;
+ //If named_mutex is implemented using semaphores
+ //we need to store an additional mutex
+ #if defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
+ interprocess_mutex mutex_;
+ #endif
+ };
+
+ interprocess_condition *condition() const
+ { return &static_cast<condition_holder*>(m_shmem.get_user_address())->cond_; }
+
+ template <class Lock>
+ class lock_inverter
+ {
+ Lock &l_;
+ public:
+ lock_inverter(Lock &l)
+ : l_(l)
+ {}
+ void lock() { l_.unlock(); }
+ void unlock() { l_.lock(); }
+ };
+
+ #if defined (BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
+ interprocess_mutex *mutex() const
+ { return &static_cast<condition_holder*>(m_shmem.get_user_address())->mutex_; }
+
+ template <class Lock>
+ void do_wait(Lock& lock)
+ {
+ //named_condition only works with named_mutex
+ BOOST_STATIC_ASSERT((detail::is_same<typename Lock::mutex_type, named_mutex>::value == true));
+ //lock internal before unlocking external to avoid race with a notifier
+ scoped_lock<interprocess_mutex> internal_lock(*this->mutex());
+ lock_inverter<Lock> inverted_lock(lock);
+ scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
+
+ //unlock internal first to avoid deadlock with near simultaneous waits
+ scoped_lock<interprocess_mutex> internal_unlock;
+ internal_lock.swap(internal_unlock);
+ this->condition()->wait(internal_unlock);
+ }
+
+ template <class Lock>
+ bool do_timed_wait(Lock& lock, const boost::posix_time::ptime &abs_time)
+ {
+ //named_condition only works with named_mutex
+ BOOST_STATIC_ASSERT((detail::is_same<typename Lock::mutex_type, named_mutex>::value == true));
+ //lock internal before unlocking external to avoid race with a notifier
+ scoped_lock<interprocess_mutex> internal_lock(*this->mutex(), abs_time);
+ if(!internal_lock) return false;
+ lock_inverter<Lock> inverted_lock(lock);
+ scoped_lock<lock_inverter<Lock> > external_unlock(inverted_lock);
+
+ //unlock internal first to avoid deadlock with near simultaneous waits
+ scoped_lock<interprocess_mutex> internal_unlock;
+ internal_lock.swap(internal_unlock);
+ return this->condition()->timed_wait(internal_unlock, abs_time);
+ }
+ #endif
+
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction();
+
+ detail::managed_open_or_create_impl<shared_memory_object> m_shmem;
+
+ template <class T, class Arg> friend class boost::interprocess::detail::named_creation_functor;
+ typedef detail::named_creation_functor<condition_holder> construct_func_t;
+ /// @endcond
+};
+
+/// @cond
+
+inline named_condition::~named_condition()
+{}
+
+inline named_condition::named_condition(create_only_t, const char *name)
+ : m_shmem (create_only
+ ,name
+ ,sizeof(condition_holder) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoCreate))
+{}
+
+inline named_condition::named_condition(open_or_create_t, const char *name)
+ : m_shmem (open_or_create
+ ,name
+ ,sizeof(condition_holder) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpenOrCreate))
+{}
+
+inline named_condition::named_condition(open_only_t, const char *name)
+ : m_shmem (open_only
+ ,name
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpen))
+{}
+
+inline void named_condition::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_shmem); }
+
+#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
+
+inline void named_condition::notify_one()
+{
+ scoped_lock<interprocess_mutex> internal_lock(*this->mutex());
+ this->condition()->notify_one();
+}
+
+inline void named_condition::notify_all()
+{
+ scoped_lock<interprocess_mutex> internal_lock(*this->mutex());
+ this->condition()->notify_all();
+}
+
+template <typename L>
+inline void named_condition::wait(L& lock)
+{
+ if (!lock)
+ throw lock_exception();
+ this->do_wait(lock);
+}
+
+template <typename L, typename Pr>
+inline void named_condition::wait(L& lock, Pr pred)
+{
+ if (!lock)
+ throw lock_exception();
+ while (!pred())
+ this->do_wait(lock);
+}
+
+template <typename L>
+inline bool named_condition::timed_wait
+ (L& lock, const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait(lock);
+ return true;
+ }
+ if (!lock)
+ throw lock_exception();
+ return this->do_timed_wait(lock, abs_time);
+}
+
+template <typename L, typename Pr>
+inline bool named_condition::timed_wait
+ (L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait(lock, pred);
+ return true;
+ }
+ if (!lock)
+ throw lock_exception();
+
+ while (!pred()){
+ if(!this->do_timed_wait(lock, abs_time)){
+ return pred();
+ }
+ }
+ return true;
+}
+
+#else
+
+inline void named_condition::notify_one()
+{ this->condition()->notify_one(); }
+
+inline void named_condition::notify_all()
+{ this->condition()->notify_all(); }
+
+template <typename L>
+inline void named_condition::wait(L& lock)
+{
+ if (!lock)
+ throw lock_exception();
+ this->condition()->do_wait(*lock.mutex()->mutex());
+}
+
+template <typename L, typename Pr>
+inline void named_condition::wait(L& lock, Pr pred)
+{
+ if (!lock)
+ throw lock_exception();
+
+ while (!pred())
+ this->condition()->do_wait(*lock.mutex()->mutex());
+}
+
+template <typename L>
+inline bool named_condition::timed_wait
+ (L& lock, const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait(lock);
+ return true;
+ }
+ if (!lock)
+ throw lock_exception();
+ return this->condition()->do_timed_wait(abs_time, *lock.mutex()->mutex());
+}
+
+template <typename L, typename Pr>
+inline bool named_condition::timed_wait
+ (L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait(lock, pred);
+ return true;
+ }
+ if (!lock)
+ throw lock_exception();
+
+ while (!pred()){
+ if (!this->condition()->do_timed_wait(abs_time, *lock.mutex()->mutex()))
+ return pred();
+ }
+
+ return true;
+}
+
+#endif
+
+inline bool named_condition::remove(const char *name)
+{ return shared_memory_object::remove(name); }
+
+/// @endcond
+
+} //namespace interprocess
+} //namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_NAMED_CONDITION_HPP
Added: sandbox/boost/interprocess/sync/named_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/named_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,232 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MUTEX_HPP
+#define BOOST_INTERPROCESS_NAMED_MUTEX_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
+#include <boost/interprocess/detail/interprocess_tester.hpp>
+
+#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
+ #include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
+#else
+ #include <boost/interprocess/shared_memory_object.hpp>
+ #include <boost/interprocess/sync/interprocess_mutex.hpp>
+ #include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+ #include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#endif
+
+//!\file
+//!Describes a named mutex class for inter-process synchronization
+
+namespace boost {
+namespace interprocess {
+
+class named_condition;
+
+//!A mutex with a global name, so it can be found from different
+//!processes. This mutex can't be placed in shared memory, and
+//!each process should have it's own named_mutex.
+class named_mutex
+{
+ /// @cond
+
+ //Non-copyable
+ named_mutex();
+ named_mutex(const named_mutex &);
+ named_mutex &operator=(const named_mutex &);
+ friend class named_condition;
+ /// @endcond
+
+ public:
+ //!Creates a global interprocess_mutex with a name.
+ //!Throws interprocess_exception on error.
+ named_mutex(create_only_t create_only, const char *name);
+
+ //!Opens or creates a global mutex with a name.
+ //!If the mutex is created, this call is equivalent to
+ //!named_mutex(create_only_t, ... )
+ //!If the mutex is already created, this call is equivalent
+ //!named_mutex(open_only_t, ... )
+ //!Does not throw
+ named_mutex(open_or_create_t open_or_create, const char *name);
+
+ //!Opens a global mutex with a name if that mutex is previously
+ //!created. If it is not previously created this function throws
+ //!interprocess_exception.
+ named_mutex(open_only_t open_only, const char *name);
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~named_mutex();
+
+ //!Unlocks a previously locked
+ //!interprocess_mutex.
+ void unlock();
+
+ //!Locks interprocess_mutex, sleeps when interprocess_mutex is already locked.
+ //!Throws interprocess_exception if a severe error is found
+ void lock();
+
+ //!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
+ //!is already locked, returns true when success.
+ //!Throws interprocess_exception if a severe error is found
+ bool try_lock();
+
+ //!Tries to lock the interprocess_mutex until time abs_time,
+ //!Returns false when timeout expires, returns true when locks.
+ //!Throws interprocess_exception if a severe error is found
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Erases a named mutex from the system.
+ //!Returns false on error. Never throws.
+ static bool remove(const char *name);
+
+ /// @cond
+ private:
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction();
+
+ #if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
+ detail::named_semaphore_wrapper m_sem;
+ #else
+ interprocess_mutex *mutex() const
+ { return static_cast<interprocess_mutex*>(m_shmem.get_user_address()); }
+
+ detail::managed_open_or_create_impl<shared_memory_object> m_shmem;
+ typedef detail::named_creation_functor<interprocess_mutex> construct_func_t;
+ #endif
+ /// @endcond
+};
+
+/// @cond
+
+#if defined(BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES)
+
+inline named_mutex::named_mutex(create_only_t, const char *name)
+ : m_sem(detail::DoCreate, name, read_write, 1)
+{}
+
+inline named_mutex::named_mutex(open_or_create_t, const char *name)
+ : m_sem(detail::DoOpenOrCreate, name, read_write, 1)
+{}
+
+inline named_mutex::named_mutex(open_only_t, const char *name)
+ : m_sem(detail::DoOpen, name, read_write, 1)
+{}
+
+inline void named_mutex::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_sem); }
+
+inline named_mutex::~named_mutex()
+{}
+
+inline void named_mutex::lock()
+{ m_sem.wait(); }
+
+inline void named_mutex::unlock()
+{ m_sem.post(); }
+
+inline bool named_mutex::try_lock()
+{ return m_sem.try_wait(); }
+
+inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ return m_sem.timed_wait(abs_time);
+}
+
+inline bool named_mutex::remove(const char *name)
+{ return detail::named_semaphore_wrapper::remove(name); }
+
+#else
+
+inline void named_mutex::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_shmem); }
+
+inline named_mutex::~named_mutex()
+{}
+
+inline named_mutex::named_mutex(create_only_t, const char *name)
+ : m_shmem (create_only
+ ,name
+ ,sizeof(interprocess_mutex) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoCreate))
+{}
+
+inline named_mutex::named_mutex(open_or_create_t, const char *name)
+ : m_shmem (open_or_create
+ ,name
+ ,sizeof(interprocess_mutex) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpenOrCreate))
+{}
+
+inline named_mutex::named_mutex(open_only_t, const char *name)
+ : m_shmem (open_only
+ ,name
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpen))
+{}
+
+inline void named_mutex::lock()
+{ this->mutex()->lock(); }
+
+inline void named_mutex::unlock()
+{ this->mutex()->unlock(); }
+
+inline bool named_mutex::try_lock()
+{ return this->mutex()->try_lock(); }
+
+inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ return this->mutex()->timed_lock(abs_time);
+}
+
+inline bool named_mutex::remove(const char *name)
+{ return shared_memory_object::remove(name); }
+
+#endif
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_NAMED_MUTEX_HPP
Added: sandbox/boost/interprocess/sync/named_recursive_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/named_recursive_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,177 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_RECURSIVE_MUTEX_HPP
+#define BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
+#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
+
+//!\file
+//!Describes a named named_recursive_mutex class for inter-process synchronization
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail{ class interprocess_tester; }
+/// @endcond
+
+//!A recursive mutex with a global name, so it can be found from different
+//!processes. This mutex can't be placed in shared memory, and
+//!each process should have it's own named_recursive_mutex.
+class named_recursive_mutex
+{
+ /// @cond
+ //Non-copyable
+ named_recursive_mutex();
+ named_recursive_mutex(const named_recursive_mutex &);
+ named_recursive_mutex &operator=(const named_recursive_mutex &);
+ /// @endcond
+ public:
+
+ //!Creates a global recursive_mutex with a name.
+ //!If the recursive_mutex can't be created throws interprocess_exception
+ named_recursive_mutex(create_only_t create_only, const char *name);
+
+ //!Opens or creates a global recursive_mutex with a name.
+ //!If the recursive_mutex is created, this call is equivalent to
+ //!named_recursive_mutex(create_only_t, ... )
+ //!If the recursive_mutex is already created, this call is equivalent
+ //!named_recursive_mutex(open_only_t, ... )
+ //!Does not throw
+ named_recursive_mutex(open_or_create_t open_or_create, const char *name);
+
+ //!Opens a global recursive_mutex with a name if that recursive_mutex is previously
+ //!created. If it is not previously created this function throws
+ //!interprocess_exception.
+ named_recursive_mutex(open_only_t open_only, const char *name);
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~named_recursive_mutex();
+
+ //!Unlocks a previously locked
+ //!named_recursive_mutex.
+ void unlock();
+
+ //!Locks named_recursive_mutex, sleeps when named_recursive_mutex is already locked.
+ //!Throws interprocess_exception if a severe error is found.
+ void lock();
+
+ //!Tries to lock the named_recursive_mutex, returns false when named_recursive_mutex
+ //!is already locked, returns true when success.
+ //!Throws interprocess_exception if a severe error is found.
+ bool try_lock();
+
+ //!Tries to lock the named_recursive_mutex until time abs_time,
+ //!Returns false when timeout expires, returns true when locks.
+ //!Throws interprocess_exception if a severe error is found
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Erases a named recursive mutex
+ //!from the system
+ static bool remove(const char *name);
+
+ /// @cond
+ private:
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction();
+
+ interprocess_recursive_mutex *mutex() const
+ { return static_cast<interprocess_recursive_mutex*>(m_shmem.get_user_address()); }
+
+ detail::managed_open_or_create_impl<shared_memory_object> m_shmem;
+ typedef detail::named_creation_functor<interprocess_recursive_mutex> construct_func_t;
+ /// @endcond
+};
+
+/// @cond
+
+inline named_recursive_mutex::~named_recursive_mutex()
+{}
+
+inline void named_recursive_mutex::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_shmem); }
+
+inline named_recursive_mutex::named_recursive_mutex(create_only_t, const char *name)
+ : m_shmem (create_only
+ ,name
+ ,sizeof(interprocess_recursive_mutex) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoCreate))
+{}
+
+inline named_recursive_mutex::named_recursive_mutex(open_or_create_t, const char *name)
+ : m_shmem (open_or_create
+ ,name
+ ,sizeof(interprocess_recursive_mutex) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpenOrCreate))
+{}
+
+inline named_recursive_mutex::named_recursive_mutex(open_only_t, const char *name)
+ : m_shmem (open_only
+ ,name
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpen))
+{}
+
+inline void named_recursive_mutex::lock()
+{ this->mutex()->lock(); }
+
+inline void named_recursive_mutex::unlock()
+{ this->mutex()->unlock(); }
+
+inline bool named_recursive_mutex::try_lock()
+{ return this->mutex()->try_lock(); }
+
+inline bool named_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ return this->mutex()->timed_lock(abs_time);
+}
+
+inline bool named_recursive_mutex::remove(const char *name)
+{ return shared_memory_object::remove(name); }
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_NAMED_RECURSIVE_MUTEX_HPP
Added: sandbox/boost/interprocess/sync/named_semaphore.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/named_semaphore.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,240 @@
+ //////////////////////////////////////////////////////////////////////////////
+//
+// (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_SEMAPHORE_HPP
+#define BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/interprocess_tester.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+#if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES)
+#include <boost/interprocess/sync/posix/semaphore_wrapper.hpp>
+#else
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+#include <boost/interprocess/sync/interprocess_semaphore.hpp>
+#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
+#endif
+
+//!\file
+//!Describes a named semaphore class for inter-process synchronization
+
+namespace boost {
+namespace interprocess {
+
+//!A semaphore with a global name, so it can be found from different
+//!processes. Allows several resource sharing patterns and efficient
+//!acknowledgment mechanisms.
+class named_semaphore
+{
+ /// @cond
+
+ //Non-copyable
+ named_semaphore();
+ named_semaphore(const named_semaphore &);
+ named_semaphore &operator=(const named_semaphore &);
+ /// @endcond
+
+ public:
+ //!Creates a global semaphore with a name, and an initial count.
+ //!If the semaphore can't be created throws interprocess_exception
+ named_semaphore(create_only_t, const char *name, int initialCount);
+
+ //!Opens or creates a global semaphore with a name, and an initial count.
+ //!If the semaphore is created, this call is equivalent to
+ //!named_semaphore(create_only_t, ...)
+ //!If the semaphore is already created, this call is equivalent to
+ //!named_semaphore(open_only_t, ... )
+ //!and initialCount is ignored.
+ named_semaphore(open_or_create_t, const char *name, int initialCount);
+
+ //!Opens a global semaphore with a name if that semaphore is previously.
+ //!created. If it is not previously created this function throws
+ //!interprocess_exception.
+ named_semaphore(open_only_t, const char *name);
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~named_semaphore();
+
+ //!Increments the semaphore count. If there are processes/threads blocked waiting
+ //!for the semaphore, then one of these processes will return successfully from
+ //!its wait function. If there is an error an interprocess_exception exception is thrown.
+ void post();
+
+ //!Decrements the semaphore. If the semaphore value is not greater than zero,
+ //!then the calling process/thread blocks until it can decrement the counter.
+ //!If there is an error an interprocess_exception exception is thrown.
+ void wait();
+
+ //!Decrements the semaphore if the semaphore's value is greater than zero
+ //!and returns true. If the value is not greater than zero returns false.
+ //!If there is an error an interprocess_exception exception is thrown.
+ bool try_wait();
+
+ //!Decrements the semaphore if the semaphore's value is greater
+ //!than zero and returns true. Otherwise, waits for the semaphore
+ //!to the posted or the timeout expires. If the timeout expires, the
+ //!function returns false. If the semaphore is posted the function
+ //!returns true. If there is an error throws sem_exception
+ bool timed_wait(const boost::posix_time::ptime &abs_time);
+
+ //!Erases a named semaphore from the system.
+ //!Returns false on error. Never throws.
+ static bool remove(const char *name);
+
+ /// @cond
+ private:
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction();
+
+ #if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES)
+ detail::named_semaphore_wrapper m_sem;
+ #else
+ interprocess_semaphore *semaphore() const
+ { return static_cast<interprocess_semaphore*>(m_shmem.get_user_address()); }
+
+ detail::managed_open_or_create_impl<shared_memory_object> m_shmem;
+ typedef detail::named_creation_functor<interprocess_semaphore, int> construct_func_t;
+ #endif
+ /// @endcond
+};
+
+/// @cond
+
+#if defined(BOOST_INTERPROCESS_NAMED_SEMAPHORE_USES_POSIX_SEMAPHORES)
+
+inline named_semaphore::named_semaphore
+ (create_only_t, const char *name, int initialCount)
+ : m_sem(detail::DoCreate, name, read_write, initialCount)
+{}
+
+inline named_semaphore::named_semaphore
+ (open_or_create_t, const char *name, int initialCount)
+ : m_sem(detail::DoOpenOrCreate, name, read_write, initialCount)
+{}
+
+inline named_semaphore::named_semaphore
+ (open_only_t, const char *name)
+ : m_sem(detail::DoOpen, name, read_write, 1)
+{}
+
+inline named_semaphore::~named_semaphore()
+{}
+
+inline void named_semaphore::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_sem); }
+
+inline void named_semaphore::wait()
+{ m_sem.wait(); }
+
+inline void named_semaphore::post()
+{ m_sem.post(); }
+
+inline bool named_semaphore::try_wait()
+{ return m_sem.try_wait(); }
+
+inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait();
+ return true;
+ }
+ return m_sem.timed_wait(abs_time);
+}
+
+inline bool named_semaphore::remove(const char *name)
+{ return detail::named_semaphore_wrapper::remove(name); }
+
+#else
+
+inline named_semaphore::~named_semaphore()
+{}
+
+inline void named_semaphore::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_shmem); }
+
+inline named_semaphore::named_semaphore
+ (create_only_t, const char *name, int initialCount)
+ : m_shmem (create_only
+ ,name
+ ,sizeof(interprocess_semaphore) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoCreate, initialCount))
+{}
+
+inline named_semaphore::named_semaphore
+ (open_or_create_t, const char *name, int initialCount)
+ : m_shmem (open_or_create
+ ,name
+ ,sizeof(interprocess_semaphore) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpenOrCreate, initialCount))
+{}
+
+inline named_semaphore::named_semaphore
+ (open_only_t, const char *name)
+ : m_shmem (open_only
+ ,name
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpen, 0))
+{}
+
+inline void named_semaphore::post()
+{ semaphore()->post(); }
+
+inline void named_semaphore::wait()
+{ semaphore()->wait(); }
+
+inline bool named_semaphore::try_wait()
+{ return semaphore()->try_wait(); }
+
+inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait();
+ return true;
+ }
+ return semaphore()->timed_wait(abs_time);
+}
+
+inline bool named_semaphore::remove(const char *name)
+{ return shared_memory_object::remove(name); }
+
+#endif
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_NAMED_SEMAPHORE_HPP
Added: sandbox/boost/interprocess/sync/named_upgradable_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/named_upgradable_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,369 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_upgradable_mutex_HPP
+#define BOOST_INTERPROCESS_named_upgradable_mutex_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
+#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/sync/emulation/named_creation_functor.hpp>
+
+//!\file
+//!Describes a named upgradable mutex class for inter-process synchronization
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail{ class interprocess_tester; }
+/// @endcond
+
+class named_condition;
+
+//!A upgradable mutex with a global name, so it can be found from different
+//!processes. This mutex can't be placed in shared memory, and
+//!each process should have it's own named upgradable mutex.
+class named_upgradable_mutex
+{
+ /// @cond
+ //Non-copyable
+ named_upgradable_mutex();
+ named_upgradable_mutex(const named_upgradable_mutex &);
+ named_upgradable_mutex &operator=(const named_upgradable_mutex &);
+ friend class named_condition;
+ /// @endcond
+ public:
+
+ //!Creates a global upgradable mutex with a name.
+ //!If the upgradable mutex can't be created throws interprocess_exception
+ named_upgradable_mutex(create_only_t create_only, const char *name);
+
+ //!Opens or creates a global upgradable mutex with a name, and an initial count.
+ //!If the upgradable mutex is created, this call is equivalent to
+ //!named_upgradable_mutex(create_only_t, ...)
+ //!If the upgradable mutex is already created, this call is equivalent to
+ //!named_upgradable_mutex(open_only_t, ... ).
+ named_upgradable_mutex(open_or_create_t open_or_create, const char *name);
+
+ //!Opens a global upgradable mutex with a name if that upgradable mutex
+ //!is previously.
+ //!created. If it is not previously created this function throws
+ //!interprocess_exception.
+ named_upgradable_mutex(open_only_t open_only, const char *name);
+
+ //!Destroys *this and indicates that the calling process is finished using
+ //!the resource. 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 resource from the system
+ //!use remove().
+ ~named_upgradable_mutex();
+
+ //Exclusive locking
+
+ //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
+ //! and if another thread has exclusive, sharable or upgradable ownership of
+ //! the mutex, it waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock();
+
+ //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
+ //! without waiting. If no other thread has exclusive, sharable or upgradable
+ //! ownership of the mutex this succeeds.
+ //!Returns: If it can acquire exclusive ownership immediately returns true.
+ //! If it has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock();
+
+ //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive, sharable or
+ //! upgradable ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The calling thread releases the exclusive ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock();
+
+ //Sharable locking
+
+ //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
+ //! and if another thread has exclusive or upgradable ownership of the mutex,
+ //! waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock_sharable();
+
+ //!Effects: The calling thread tries to acquire sharable ownership of the mutex
+ //! without waiting. If no other thread has has exclusive or upgradable ownership
+ //! of the mutex this succeeds.
+ //!Returns: If it can acquire sharable ownership immediately returns true. If it
+ //! has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock_sharable();
+
+ //!Effects: The calling thread tries to acquire sharable ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive or upgradable
+ //! ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock_sharable(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have sharable ownership of the mutex.
+ //!Effects: The calling thread releases the sharable ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_sharable();
+
+ //Upgradable locking
+
+ //!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
+ //! and if another thread has exclusive or upgradable ownership of the mutex,
+ //! waits until it can obtain the ownership.
+ //!Throws: interprocess_exception on error.
+ void lock_upgradable();
+
+ //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
+ //! without waiting. If no other thread has has exclusive or upgradable ownership
+ //! of the mutex this succeeds.
+ //!Returns: If it can acquire upgradable ownership immediately returns true.
+ //! If it has to wait, returns false.
+ //!Throws: interprocess_exception on error.
+ bool try_lock_upgradable();
+
+ //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
+ //! waiting if necessary until no other thread has has exclusive or upgradable
+ //! ownership of the mutex or abs_time is reached.
+ //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
+ //!Throws: interprocess_exception on error.
+ bool timed_lock_upgradable(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The calling thread releases the upgradable ownership of the mutex.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_upgradable();
+
+ //Demotions
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The thread atomically releases exclusive ownership and acquires
+ //! upgradable ownership. This operation is non-blocking.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_and_lock_upgradable();
+
+ //!Precondition: The thread must have exclusive ownership of the mutex.
+ //!Effects: The thread atomically releases exclusive ownership and acquires
+ //! sharable ownership. This operation is non-blocking.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_and_lock_sharable();
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and acquires
+ //! sharable ownership. This operation is non-blocking.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_upgradable_and_lock_sharable();
+
+ //Promotions
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and acquires
+ //! exclusive ownership. This operation will block until all threads with
+ //! sharable ownership release it.
+ //!Throws: An exception derived from interprocess_exception on error.
+ void unlock_upgradable_and_lock();
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and tries to
+ //! acquire exclusive ownership. This operation will fail if there are threads
+ //! with sharable ownership, but it will maintain upgradable ownership.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error.
+ bool try_unlock_upgradable_and_lock();
+
+ //!Precondition: The thread must have upgradable ownership of the mutex.
+ //!Effects: The thread atomically releases upgradable ownership and tries to acquire
+ //! exclusive ownership, waiting if necessary until abs_time. This operation will
+ //! fail if there are threads with sharable ownership or timeout reaches, but it
+ //! will maintain upgradable ownership.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error.
+ bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &abs_time);
+
+ //!Precondition: The thread must have sharable ownership of the mutex.
+ //!Effects: The thread atomically releases sharable ownership and tries to acquire
+ //! exclusive ownership. This operation will fail if there are threads with sharable
+ //! or upgradable ownership, but it will maintain sharable ownership.
+ //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
+ //!Throws: An exception derived from interprocess_exception on error.
+ bool try_unlock_sharable_and_lock();
+
+ bool try_unlock_sharable_and_lock_upgradable();
+
+ //!Erases a named upgradable mutex from the system.
+ //!Returns false on error. Never throws.
+ static bool remove(const char *name);
+
+ /// @cond
+ private:
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction();
+
+ interprocess_upgradable_mutex *mutex() const
+ { return static_cast<interprocess_upgradable_mutex*>(m_shmem.get_user_address()); }
+
+ detail::managed_open_or_create_impl<shared_memory_object> m_shmem;
+ typedef detail::named_creation_functor<interprocess_upgradable_mutex> construct_func_t;
+ /// @endcond
+};
+
+/// @cond
+
+inline named_upgradable_mutex::~named_upgradable_mutex()
+{}
+
+inline named_upgradable_mutex::named_upgradable_mutex
+ (create_only_t, const char *name)
+ : m_shmem (create_only
+ ,name
+ ,sizeof(interprocess_upgradable_mutex) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoCreate))
+{}
+
+inline named_upgradable_mutex::named_upgradable_mutex
+ (open_or_create_t, const char *name)
+ : m_shmem (open_or_create
+ ,name
+ ,sizeof(interprocess_upgradable_mutex) +
+ detail::managed_open_or_create_impl<shared_memory_object>::
+ ManagedOpenOrCreateUserOffset
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpenOrCreate))
+{}
+
+inline named_upgradable_mutex::named_upgradable_mutex
+ (open_only_t, const char *name)
+ : m_shmem (open_only
+ ,name
+ ,read_write
+ ,0
+ ,construct_func_t(detail::DoOpen))
+{}
+
+inline void named_upgradable_mutex::dont_close_on_destruction()
+{ detail::interprocess_tester::dont_close_on_destruction(m_shmem); }
+
+inline void named_upgradable_mutex::lock()
+{ this->mutex()->lock(); }
+
+inline void named_upgradable_mutex::unlock()
+{ this->mutex()->unlock(); }
+
+inline bool named_upgradable_mutex::try_lock()
+{ return this->mutex()->try_lock(); }
+
+inline bool named_upgradable_mutex::timed_lock
+ (const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ return this->mutex()->timed_lock(abs_time);
+}
+
+inline void named_upgradable_mutex::lock_upgradable()
+{ this->mutex()->lock_upgradable(); }
+
+inline void named_upgradable_mutex::unlock_upgradable()
+{ this->mutex()->unlock_upgradable(); }
+
+inline bool named_upgradable_mutex::try_lock_upgradable()
+{ return this->mutex()->try_lock_upgradable(); }
+
+inline bool named_upgradable_mutex::timed_lock_upgradable
+ (const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock_upgradable();
+ return true;
+ }
+ return this->mutex()->timed_lock_upgradable(abs_time);
+}
+
+inline void named_upgradable_mutex::lock_sharable()
+{ this->mutex()->lock_sharable(); }
+
+inline void named_upgradable_mutex::unlock_sharable()
+{ this->mutex()->unlock_sharable(); }
+
+inline bool named_upgradable_mutex::try_lock_sharable()
+{ return this->mutex()->try_lock_sharable(); }
+
+inline bool named_upgradable_mutex::timed_lock_sharable
+ (const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock_sharable();
+ return true;
+ }
+ return this->mutex()->timed_lock_sharable(abs_time);
+}
+
+inline void named_upgradable_mutex::unlock_and_lock_upgradable()
+{ this->mutex()->unlock_and_lock_upgradable(); }
+
+inline void named_upgradable_mutex::unlock_and_lock_sharable()
+{ this->mutex()->unlock_and_lock_sharable(); }
+
+inline void named_upgradable_mutex::unlock_upgradable_and_lock_sharable()
+{ this->mutex()->unlock_upgradable_and_lock_sharable(); }
+
+inline void named_upgradable_mutex::unlock_upgradable_and_lock()
+{ this->mutex()->unlock_upgradable_and_lock(); }
+
+inline bool named_upgradable_mutex::try_unlock_upgradable_and_lock()
+{ return this->mutex()->try_unlock_upgradable_and_lock(); }
+
+inline bool named_upgradable_mutex::timed_unlock_upgradable_and_lock
+ (const boost::posix_time::ptime &abs_time)
+{ return this->mutex()->timed_unlock_upgradable_and_lock(abs_time); }
+
+inline bool named_upgradable_mutex::try_unlock_sharable_and_lock()
+{ return this->mutex()->try_unlock_sharable_and_lock(); }
+
+inline bool named_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
+{ return this->mutex()->try_unlock_sharable_and_lock_upgradable(); }
+
+inline bool named_upgradable_mutex::remove(const char *name)
+{ return shared_memory_object::remove(name); }
+
+/// @endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_named_upgradable_mutex_HPP
Added: sandbox/boost/interprocess/sync/null_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/null_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,147 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_MUTEX_HPP
+#define BOOST_INTERPROCESS_NULL_MUTEX_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+
+
+//!\file
+//!Describes null_mutex classes
+
+namespace boost {
+
+namespace posix_time
+{ class ptime; }
+
+namespace interprocess {
+
+//!Implements a mutex that simulates a mutex without doing any operation and
+//!simulates a successful operation.
+class null_mutex
+{
+ /// @cond
+ null_mutex(const null_mutex&);
+ null_mutex &operator= (const null_mutex&);
+ /// @endcond
+ public:
+
+ //!Constructor.
+ //!Empty.
+ null_mutex(){}
+
+ //!Destructor.
+ //!Empty.
+ ~null_mutex(){}
+
+ //!Simulates a mutex lock() operation. Empty function.
+ void lock(){}
+
+ //!Simulates a mutex try_lock() operation.
+ //!Equivalent to "return true;"
+ bool try_lock()
+ { return true; }
+
+ //!Simulates a mutex timed_lock() operation.
+ //!Equivalent to "return true;"
+ bool timed_lock(const boost::posix_time::ptime &)
+ { return true; }
+
+ //!Simulates a mutex unlock() operation.
+ //!Empty function.
+ void unlock(){}
+
+ //!Simulates a mutex lock_sharable() operation.
+ //!Empty function.
+ void lock_sharable(){}
+
+ //!Simulates a mutex try_lock_sharable() operation.
+ //!Equivalent to "return true;"
+ bool try_lock_sharable()
+ { return true; }
+
+ //!Simulates a mutex timed_lock_sharable() operation.
+ //!Equivalent to "return true;"
+ bool timed_lock_sharable(const boost::posix_time::ptime &)
+ { return true; }
+
+ //!Simulates a mutex unlock_sharable() operation.
+ //!Empty function.
+ void unlock_sharable(){}
+
+ //!Simulates a mutex lock_upgradable() operation.
+ //!Empty function.
+ void lock_upgradable(){}
+
+ //!Simulates a mutex try_lock_upgradable() operation.
+ //!Equivalent to "return true;"
+ bool try_lock_upgradable()
+ { return true; }
+
+ //!Simulates a mutex timed_lock_upgradable() operation.
+ //!Equivalent to "return true;"
+ bool timed_lock_upgradable(const boost::posix_time::ptime &)
+ { return true; }
+
+ //!Simulates a mutex unlock_upgradable() operation.
+ //!Empty function.
+ void unlock_upgradable(){}
+
+ //!Simulates unlock_and_lock_upgradable().
+ //!Empty function.
+ void unlock_and_lock_upgradable(){}
+
+ //!Simulates unlock_and_lock_sharable().
+ //!Empty function.
+ void unlock_and_lock_sharable(){}
+
+ //!Simulates unlock_upgradable_and_lock_sharable().
+ //!Empty function.
+ void unlock_upgradable_and_lock_sharable(){}
+
+ //Promotions
+
+ //!Simulates unlock_upgradable_and_lock().
+ //!Empty function.
+ void unlock_upgradable_and_lock(){}
+
+ //!Simulates try_unlock_upgradable_and_lock().
+ //!Equivalent to "return true;"
+ bool try_unlock_upgradable_and_lock()
+ { return true; }
+
+ //!Simulates timed_unlock_upgradable_and_lock().
+ //!Equivalent to "return true;"
+ bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &)
+ { return true; }
+
+ //!Simulates try_unlock_sharable_and_lock().
+ //!Equivalent to "return true;"
+ bool try_unlock_sharable_and_lock()
+ { return true; }
+
+ //!Simulates try_unlock_sharable_and_lock_upgradable().
+ //!Equivalent to "return true;"
+ bool try_unlock_sharable_and_lock_upgradable()
+ { return true; }
+};
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP
Added: sandbox/boost/interprocess/sync/posix/interprocess_barrier.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/interprocess_barrier.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,44 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include<boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+namespace boost {
+namespace interprocess {
+
+inline barrier::barrier(unsigned int count)
+{
+ if (count == 0)
+ throw std::invalid_argument("count cannot be zero.");
+ detail::barrierattr_wrapper barrier_attr;
+ detail::barrier_initializer barrier
+ (m_barrier, barrier_attr, static_cast<int>(count));
+ barrier.release();
+}
+
+inline barrier::~barrier()
+{
+ int res = pthread_barrier_destroy(&m_barrier);
+ assert(res == 0);(void)res;
+}
+
+inline bool barrier::wait()
+{
+ int res = pthread_barrier_wait(&m_barrier);
+
+ if (res != PTHREAD_BARRIER_SERIAL_THREAD && res != 0){
+ throw interprocess_exception(res);
+ }
+ return res == PTHREAD_BARRIER_SERIAL_THREAD;
+}
+
+} //namespace interprocess {
+} //namespace boost {
Added: sandbox/boost/interprocess/sync/posix/interprocess_condition.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/interprocess_condition.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,81 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+inline interprocess_condition::interprocess_condition()
+{
+ int res;
+ pthread_condattr_t cond_attr;
+ res = pthread_condattr_init(&cond_attr);
+ if(res != 0){
+ throw interprocess_exception();
+ }
+ res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
+ if(res != 0){
+ pthread_condattr_destroy(&cond_attr);
+ throw interprocess_exception(res);
+ }
+ res = pthread_cond_init(&m_condition, &cond_attr);
+ pthread_condattr_destroy(&cond_attr);
+ if(res != 0){
+ throw interprocess_exception(res);
+ }
+}
+
+inline interprocess_condition::~interprocess_condition()
+{
+ int res = 0;
+ res = pthread_cond_destroy(&m_condition);
+ assert(res == 0);
+}
+
+inline void interprocess_condition::notify_one()
+{
+ int res = 0;
+ res = pthread_cond_signal(&m_condition);
+ assert(res == 0);
+}
+
+inline void interprocess_condition::notify_all()
+{
+ int res = 0;
+ res = pthread_cond_broadcast(&m_condition);
+ assert(res == 0);
+}
+
+inline void interprocess_condition::do_wait(interprocess_mutex &mut)
+{
+ pthread_mutex_t* pmutex = &mut.m_mut;
+ int res = 0;
+ res = pthread_cond_wait(&m_condition, pmutex);
+ assert(res == 0);
+}
+
+inline bool interprocess_condition::do_timed_wait
+ (const boost::posix_time::ptime &abs_time, interprocess_mutex &mut)
+{
+ timespec ts = detail::ptime_to_timespec(abs_time);
+ pthread_mutex_t* pmutex = &mut.m_mut;
+ int res = 0;
+ res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
+ assert(res == 0 || res == ETIMEDOUT);
+
+ return res != ETIMEDOUT;
+}
+
+} //namespace interprocess
+
+} // namespace boost
Added: sandbox/boost/interprocess/sync/posix/interprocess_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/interprocess_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,110 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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 the pthread code come from Boost Threads code:
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. William E. Kempf makes no representations
+// about the suitability of this software for any purpose.
+// It is provided "as is" without express or implied warranty.
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+# include <boost/interprocess/detail/os_thread_functions.hpp>
+#endif
+
+namespace boost {
+namespace interprocess {
+
+inline interprocess_mutex::interprocess_mutex()
+{
+ detail::mutexattr_wrapper mut_attr;
+ detail::mutex_initializer mut(m_mut, mut_attr);
+ mut.release();
+}
+
+inline interprocess_mutex::~interprocess_mutex()
+{
+ int res = pthread_mutex_destroy(&m_mut);
+ assert(res == 0);(void)res;
+}
+
+inline void interprocess_mutex::lock()
+{
+ if (pthread_mutex_lock(&m_mut) != 0)
+ throw lock_exception();
+}
+
+inline bool interprocess_mutex::try_lock()
+{
+ int res = pthread_mutex_trylock(&m_mut);
+ if (!(res == 0 || res == EBUSY))
+ throw lock_exception();
+ return res == 0;
+}
+
+inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+
+ timespec ts = detail::ptime_to_timespec(abs_time);
+ int res = pthread_mutex_timedlock(&m_mut, &ts);
+ if (res != 0 && res != ETIMEDOUT)
+ throw lock_exception();
+ return res == 0;
+
+ #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS
+
+ //Obtain current count and target time
+ boost::posix_time::ptime now = microsec_clock::universal_time();
+
+ if(now >= abs_time) return false;
+
+ do{
+ if(this->try_lock()){
+ break;
+ }
+ now = microsec_clock::universal_time();
+
+ if(now >= abs_time){
+ return false;
+ }
+ // relinquish current time slice
+ detail::thread_yield();
+ }while (true);
+ return true;
+
+ #endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
+}
+
+inline void interprocess_mutex::unlock()
+{
+ int res = 0;
+ res = pthread_mutex_unlock(&m_mut);
+ assert(res == 0);
+}
+
+} //namespace interprocess {
+} //namespace boost {
Added: sandbox/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,111 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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 the pthread code come from Boost Threads code:
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Permission to use, copy, modify, distribute and sell this software
+// and its documentation for any purpose is hereby granted without fee,
+// provided that the above copyright notice appear in all copies and
+// that both that copyright notice and this permission notice appear
+// in supporting documentation. William E. Kempf makes no representations
+// about the suitability of this software for any purpose.
+// It is provided "as is" without express or implied warranty.
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+# include <boost/interprocess/detail/os_thread_functions.hpp>
+#endif
+
+namespace boost {
+
+namespace interprocess {
+
+inline interprocess_recursive_mutex::interprocess_recursive_mutex()
+{
+ detail::mutexattr_wrapper mut_attr(true);
+ detail::mutex_initializer mut(m_mut, mut_attr);
+ mut.release();
+}
+
+inline interprocess_recursive_mutex::~interprocess_recursive_mutex()
+{
+ int res = pthread_mutex_destroy(&m_mut);
+ assert(res == 0);(void)res;
+}
+
+inline void interprocess_recursive_mutex::lock()
+{
+ if (pthread_mutex_lock(&m_mut) != 0)
+ throw lock_exception();
+}
+
+inline bool interprocess_recursive_mutex::try_lock()
+{
+ int res = pthread_mutex_trylock(&m_mut);
+ if (!(res == 0 || res == EBUSY))
+ throw lock_exception();
+ return res == 0;
+}
+
+inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->lock();
+ return true;
+ }
+ #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+
+ timespec ts = detail::ptime_to_timespec(abs_time);
+ int res = pthread_mutex_timedlock(&m_mut, &ts);
+ if (res != 0 && res != ETIMEDOUT)
+ throw lock_exception();
+ return res == 0;
+
+ #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS
+
+ //Obtain current count and target time
+ boost::posix_time::ptime now = microsec_clock::universal_time();
+
+ if(now >= abs_time) return false;
+
+ do{
+ if(this->try_lock()){
+ break;
+ }
+ now = microsec_clock::universal_time();
+
+ if(now >= abs_time){
+ return false;
+ }
+ // relinquish current time slice
+ detail::thread_yield();
+ }while (true);
+ return true;
+
+ #endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
+}
+
+inline void interprocess_recursive_mutex::unlock()
+{
+ int res = 0;
+ res = pthread_mutex_unlock(&m_mut);
+ assert(res == 0);
+}
+
+} //namespace interprocess {
+} //namespace boost {
Added: sandbox/boost/interprocess/sync/posix/interprocess_semaphore.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/interprocess_semaphore.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,49 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+inline interprocess_semaphore::~interprocess_semaphore()
+{}
+
+inline interprocess_semaphore::interprocess_semaphore(int initialCount)
+ : m_sem(initialCount)
+{}
+
+inline void interprocess_semaphore::post()
+{ m_sem.post(); }
+
+inline void interprocess_semaphore::wait()
+{ m_sem.wait(); }
+
+inline bool interprocess_semaphore::try_wait()
+{ return m_sem.try_wait(); }
+
+inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time)
+{
+ if(abs_time == boost::posix_time::pos_infin){
+ this->wait();
+ return true;
+ }
+ return m_sem.timed_wait(abs_time);
+}
+/*
+inline int interprocess_semaphore::get_count() const
+{ return m_sem.get_count(); }
+*/
+} //namespace interprocess {
+
+} //namespace boost {
+
Added: sandbox/boost/interprocess/sync/posix/pthread_helpers.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/pthread_helpers.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,168 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_PTHREAD_HELPERS_HPP
+#define BOOST_INTERPROCESS_PTHREAD_HELPERS_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 <pthread.h>
+#include <errno.h>
+#include <boost/interprocess/exceptions.hpp>
+
+namespace boost {
+namespace interprocess {
+namespace detail{
+
+ #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
+
+ //!Makes pthread_mutexattr_t cleanup easy when using exceptions
+ struct mutexattr_wrapper
+ {
+ //!Constructor
+ mutexattr_wrapper(bool recursive = false)
+ {
+ if(pthread_mutexattr_init(&m_attr)!=0 ||
+ pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0 ||
+ (recursive &&
+ pthread_mutexattr_settype(&m_attr, PTHREAD_MUTEX_RECURSIVE)!= 0 ))
+ throw boost::interprocess::interprocess_exception();
+ }
+
+ //!Destructor
+ ~mutexattr_wrapper() { pthread_mutexattr_destroy(&m_attr); }
+
+ //!This allows using mutexattr_wrapper as pthread_mutexattr_t
+ operator pthread_mutexattr_t&() { return m_attr; }
+
+ pthread_mutexattr_t m_attr;
+ };
+
+ //!Makes pthread_condattr_t cleanup easy when using exceptions
+ struct condattr_wrapper
+ {
+ //!Constructor
+ condattr_wrapper()
+ {
+ if(pthread_condattr_init(&m_attr)!=0 ||
+ pthread_condattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0)
+ throw boost::interprocess::interprocess_exception();
+ }
+
+ //!Destructor
+ ~condattr_wrapper() { pthread_condattr_destroy(&m_attr); }
+
+ //!This allows using condattr_wrapper as pthread_condattr_t
+ operator pthread_condattr_t&(){ return m_attr; }
+
+ pthread_condattr_t m_attr;
+ };
+
+ //!Makes initialized pthread_mutex_t cleanup easy when using exceptions
+ class mutex_initializer
+ {
+ public:
+ //!Constructor. Takes interprocess_mutex attributes to initialize the interprocess_mutex
+ mutex_initializer(pthread_mutex_t &mut, pthread_mutexattr_t &mut_attr)
+ : mp_mut(&mut)
+ {
+ if(pthread_mutex_init(mp_mut, &mut_attr) != 0)
+ throw boost::interprocess::interprocess_exception();
+ }
+
+ ~mutex_initializer() { if(mp_mut) pthread_mutex_destroy(mp_mut); }
+
+ void release() {mp_mut = 0; }
+
+ private:
+ pthread_mutex_t *mp_mut;
+ };
+
+ //!Makes initialized pthread_cond_t cleanup easy when using exceptions
+ class condition_initializer
+ {
+ public:
+ condition_initializer(pthread_cond_t &cond, pthread_condattr_t &cond_attr)
+ : mp_cond(&cond)
+ {
+ if(pthread_cond_init(mp_cond, &cond_attr)!= 0)
+ throw boost::interprocess::interprocess_exception();
+ }
+
+ ~condition_initializer() { if(mp_cond) pthread_cond_destroy(mp_cond); }
+
+ void release() { mp_cond = 0; }
+
+ private:
+ pthread_cond_t *mp_cond;
+ };
+
+ #endif // #if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED
+
+ #if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+
+ //!Makes pthread_barrierattr_t cleanup easy when using exceptions
+ struct barrierattr_wrapper
+ {
+ //!Constructor
+ barrierattr_wrapper()
+ {
+ if(pthread_barrierattr_init(&m_attr)!=0 ||
+ pthread_barrierattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED)!= 0)
+ throw boost::interprocess::interprocess_exception();
+ }
+
+ //!Destructor
+ ~barrierattr_wrapper() { pthread_barrierattr_destroy(&m_attr); }
+
+ //!This allows using mutexattr_wrapper as pthread_barrierattr_t
+ operator pthread_barrierattr_t&() { return m_attr; }
+
+ pthread_barrierattr_t m_attr;
+ };
+
+ //!Makes initialized pthread_barrier_t cleanup easy when using exceptions
+ class barrier_initializer
+ {
+ public:
+ //!Constructor. Takes barrier attributes to initialize the barrier
+ barrier_initializer(pthread_barrier_t &mut,
+ pthread_barrierattr_t &mut_attr,
+ int count)
+ : mp_barrier(&mut)
+ {
+ if(pthread_barrier_init(mp_barrier, &mut_attr, count) != 0)
+ throw boost::interprocess::interprocess_exception();
+ }
+
+ ~barrier_initializer() { if(mp_barrier) pthread_barrier_destroy(mp_barrier); }
+
+ void release() {mp_barrier = 0; }
+
+ private:
+ pthread_barrier_t *mp_barrier;
+ };
+
+ #endif //#if defined(BOOST_INTERPROCESS_POSIX_BARRIERS) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+
+}//namespace detail
+
+}//namespace interprocess
+
+}//namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //ifdef BOOST_INTERPROCESS_PTHREAD_HELPERS_HPP
Added: sandbox/boost/interprocess/sync/posix/ptime_to_timespec.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/ptime_to_timespec.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,38 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_PTIME_TO_TIMESPEC_HPP
+#define BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
+
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+namespace boost {
+
+namespace interprocess {
+
+namespace detail {
+
+inline timespec ptime_to_timespec (const boost::posix_time::ptime &tm)
+{
+ const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
+ boost::posix_time::time_duration duration (tm - epoch);
+ timespec ts;
+ ts.tv_sec = duration.total_seconds();
+ ts.tv_nsec = duration.total_nanoseconds() % 1000000000;
+ return ts;
+}
+
+} //namespace detail {
+
+} //namespace interprocess {
+
+} //namespace boost {
+
+#endif //ifndef BOOST_INTERPROCESS_DETAIL_PTIME_TO_TIMESPEC_HPP
Added: sandbox/boost/interprocess/sync/posix/semaphore_wrapper.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/posix/semaphore_wrapper.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,274 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_SEMAPHORE_WRAPPER_HPP
+#define BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
+
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/detail/os_file_functions.hpp>
+#include <boost/interprocess/detail/tmp_dir_helpers.hpp>
+#include <string>
+#include <semaphore.h>
+
+#ifdef SEM_FAILED
+#define BOOST_INTERPROCESS_POSIX_SEM_FAILED SEM_FAILED
+#else
+#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast<sem_t*>(-1))
+#endif
+
+#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
+#else
+#include <boost/interprocess/detail/os_thread_functions.hpp>
+#endif
+
+namespace boost {
+namespace interprocess {
+
+/// @cond
+namespace detail{ class interprocess_tester; }
+/// @endcond
+
+namespace detail {
+
+inline bool semaphore_open
+ (sem_t *&handle, detail::create_enum_t type, const char *origname, mode_t mode,
+ unsigned int count)
+{
+ std::string name;
+ #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
+ detail::add_leading_slash(origname, name);
+ #else
+ detail::create_tmp_dir_and_get_filename(origname, name);
+ #endif
+
+ //Create new mapping
+ int oflag = 0;
+ if(mode == read_only){
+ oflag |= O_RDONLY;
+ }
+ else if(mode == read_write){
+ oflag |= O_RDWR;
+ }
+ else{
+ error_info err(mode_error);
+ throw interprocess_exception(err);
+ }
+
+ switch(type){
+ case detail::DoOpen:
+ //No addition
+ break;
+ case detail::DoCreate:
+ oflag |= (O_CREAT | O_EXCL);
+ break;
+ case detail::DoOpenOrCreate:
+ oflag |= O_CREAT;
+ break;
+ default:
+ {
+ error_info err = other_error;
+ throw interprocess_exception(err);
+ }
+ }
+
+ //Open file using POSIX API
+ if(oflag & O_CREAT)
+ handle = sem_open(name.c_str(), oflag, S_IRWXO | S_IRWXG | S_IRWXU, count);
+ else
+ handle = sem_open(name.c_str(), oflag);
+
+ //Check for error
+ if(handle == BOOST_INTERPROCESS_POSIX_SEM_FAILED){
+ throw interprocess_exception(error_info(errno));
+ }
+
+ return true;
+}
+
+inline void semaphore_close(sem_t *handle)
+{
+ int ret = sem_close(handle);
+ if(ret != 0){
+ assert(0);
+ }
+}
+
+inline bool semaphore_unlink(const char *semname)
+{
+ try{
+ std::string sem_str;
+ #ifndef BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES
+ detail::add_leading_slash(semname, sem_str);
+ #else
+ detail::tmp_filename(semname, sem_str);
+ #endif
+ return 0 != sem_unlink(sem_str.c_str());
+ }
+ catch(...){
+ return false;
+ }
+}
+
+inline void semaphore_init(sem_t *handle, int initialCount)
+{
+ int ret = sem_init(handle, 1, initialCount);
+ //According to SUSV3 version 2003 edition, the return value of a successful
+ //sem_init call is not defined, but -1 is returned on failure.
+ //In the future, a successful call might be required to return 0.
+ if(ret == -1){
+ throw interprocess_exception(system_error_code());
+ }
+}
+
+inline void semaphore_destroy(sem_t *handle)
+{
+ int ret = sem_destroy(handle);
+ if(ret != 0){
+ assert(0);
+ }
+}
+
+inline void semaphore_post(sem_t *handle)
+{
+ int ret = sem_post(handle);
+ if(ret != 0){
+ throw interprocess_exception(system_error_code());
+ }
+}
+
+inline void semaphore_wait(sem_t *handle)
+{
+ int ret = sem_wait(handle);
+ if(ret != 0){
+ throw interprocess_exception(system_error_code());
+ }
+}
+
+inline bool semaphore_try_wait(sem_t *handle)
+{
+ int res = sem_trywait(handle);
+ if(res == 0)
+ return true;
+ if(system_error_code() == EAGAIN){
+ return false;
+ }
+ throw interprocess_exception(system_error_code());
+ return false;
+}
+
+inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime &abs_time)
+{
+ #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+ timespec tspec = detail::ptime_to_timespec(abs_time);
+ for (;;){
+ int res = sem_timedwait(handle, &tspec);
+ if(res == 0)
+ return true;
+ if (res > 0){
+ //buggy glibc, copy the returned error code to errno
+ errno = res;
+ }
+ if(system_error_code() == ETIMEDOUT){
+ return false;
+ }
+ throw interprocess_exception(system_error_code());
+ }
+ return false;
+ #else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+ boost::posix_time::ptime now;
+ while((now = microsec_clock::universal_time()) < abs_time){
+ if(semaphore_try_wait(handle))
+ return true;
+ thread_yield();
+ }
+ return false;
+ #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
+}
+
+
+class named_semaphore_wrapper
+{
+ named_semaphore_wrapper();
+ named_semaphore_wrapper(const named_semaphore_wrapper&);
+ named_semaphore_wrapper &operator= (const named_semaphore_wrapper &);
+
+ public:
+ named_semaphore_wrapper
+ (detail::create_enum_t type, const char *name, mode_t mode, unsigned int count)
+ { semaphore_open(mp_sem, type, name, mode, count); }
+
+ ~named_semaphore_wrapper()
+ {
+ if(mp_sem != BOOST_INTERPROCESS_POSIX_SEM_FAILED)
+ semaphore_close(mp_sem);
+ }
+
+ void post()
+ { semaphore_post(mp_sem); }
+
+ void wait()
+ { semaphore_wait(mp_sem); }
+
+ bool try_wait()
+ { return semaphore_try_wait(mp_sem); }
+
+ bool timed_wait(const boost::posix_time::ptime &abs_time)
+ { return semaphore_timed_wait(mp_sem, abs_time); }
+
+ static bool remove(const char *name)
+ { return semaphore_unlink(name); }
+
+ private:
+ friend class detail::interprocess_tester;
+ void dont_close_on_destruction()
+ { mp_sem = BOOST_INTERPROCESS_POSIX_SEM_FAILED; }
+
+ sem_t *mp_sem;
+};
+
+class semaphore_wrapper
+{
+ semaphore_wrapper();
+ semaphore_wrapper(const semaphore_wrapper&);
+ semaphore_wrapper &operator= (const semaphore_wrapper &);
+
+ public:
+ semaphore_wrapper(int initialCount)
+ { semaphore_init(&m_sem, initialCount); }
+
+ ~semaphore_wrapper()
+ { semaphore_destroy(&m_sem); }
+
+ void post()
+ { semaphore_post(&m_sem); }
+
+ void wait()
+ { semaphore_wait(&m_sem); }
+
+ bool try_wait()
+ { return semaphore_try_wait(&m_sem); }
+
+ bool timed_wait(const boost::posix_time::ptime &abs_time)
+ { return semaphore_timed_wait(&m_sem, abs_time); }
+
+ private:
+ sem_t m_sem;
+};
+
+} //namespace detail {
+} //namespace interprocess {
+} //namespace boost {
+
+#undef BOOST_INTERPROCESS_POSIX_SEM_FAILED
+
+#endif //#ifndef BOOST_INTERPROCESS_POSIX_SEMAPHORE_WRAPPER_HPP
Added: sandbox/boost/interprocess/sync/scoped_lock.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/scoped_lock.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,461 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This interface is inspired by Howard Hinnant's lock proposal.
+// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_SCOPED_LOCK_HPP
+#define BOOST_INTERPROCESS_SCOPED_LOCK_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/sync/lock_options.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+//!\file
+//!Describes the scoped_lock class.
+
+namespace boost {
+namespace interprocess {
+
+
+//!scoped_lock is meant to carry out the tasks for locking, unlocking, try-locking
+//!and timed-locking (recursive or not) for the Mutex. The Mutex need not supply all
+//!of this functionality. If the client of scoped_lock<Mutex> does not use
+//!functionality which the Mutex does not supply, no harm is done. Mutex ownership
+//!transfer is supported through the syntax of move semantics. Ownership transfer
+//!is allowed both by construction and assignment. The scoped_lock does not support
+//!copy semantics. A compile time error results if copy construction or copy
+//!assignment is attempted. Mutex ownership can also be moved from an
+//!upgradable_lock and sharable_lock via constructor. In this role, scoped_lock
+//!shares the same functionality as a write_lock.
+template <class Mutex>
+class scoped_lock
+{
+ /// @cond
+ private:
+ typedef scoped_lock<Mutex> this_type;
+ scoped_lock(scoped_lock&);
+ scoped_lock& operator= (scoped_lock&);
+ typedef bool this_type::*unspecified_bool_type;
+ /// @endcond
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(scoped_lock)
+
+ typedef Mutex mutex_type;
+
+ //!Effects: Default constructs a scoped_lock.
+ //!Postconditions: owns() == false and mutex() == 0.
+ scoped_lock()
+ : mp_mutex(0), m_locked(false)
+ {}
+
+ //!Effects: m.lock().
+ //!Postconditions: owns() == true and mutex() == &m.
+ //!Notes: The constructor will take ownership of the mutex. If another thread
+ //! already owns the mutex, this thread will block until the mutex is released.
+ //! Whether or not this constructor handles recursive locking depends upon the mutex.
+ explicit scoped_lock(mutex_type& m)
+ : mp_mutex(&m), m_locked(false)
+ { mp_mutex->lock(); m_locked = true; }
+
+ //!Postconditions: owns() == false, and mutex() == &m.
+ //!Notes: The constructor will not take ownership of the mutex. There is no effect
+ //! required on the referenced mutex.
+ scoped_lock(mutex_type& m, defer_lock_type)
+ : mp_mutex(&m), m_locked(false)
+ {}
+
+ //!Postconditions: owns() == true, and mutex() == &m.
+ //!Notes: The constructor will suppose that the mutex is already locked. There
+ //! is no effect required on the referenced mutex.
+ scoped_lock(mutex_type& m, accept_ownership_type)
+ : mp_mutex(&m), m_locked(true)
+ {}
+
+ //!Effects: m.try_lock().
+ //!Postconditions: mutex() == &m. owns() == the return value of the
+ //! m.try_lock() executed within the constructor.
+ //!Notes: The constructor will take ownership of the mutex if it can do
+ //! so without waiting. Whether or not this constructor handles recursive
+ //! locking depends upon the mutex. If the mutex_type does not support try_lock,
+ //! this constructor will fail at compile time if instantiated, but otherwise
+ //! have no effect.
+ scoped_lock(mutex_type& m, try_to_lock_type)
+ : mp_mutex(&m), m_locked(mp_mutex->try_lock())
+ {}
+
+ //!Effects: m.timed_lock(abs_time).
+ //!Postconditions: mutex() == &m. owns() == the return value of the
+ //! m.timed_lock(abs_time) executed within the constructor.
+ //!Notes: The constructor will take ownership of the mutex if it can do
+ //! it until abs_time is reached. Whether or not this constructor
+ //! handles recursive locking depends upon the mutex. If the mutex_type
+ //! does not support try_lock, this constructor will fail at compile
+ //! time if instantiated, but otherwise have no effect.
+ scoped_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
+ : mp_mutex(&m), m_locked(mp_mutex->timed_lock(abs_time))
+ {}
+
+ //!Postconditions: mutex() == the value scop.mutex() had before the
+ //! constructor executes. s1.mutex() == 0. owns() == the value of
+ //! scop.owns() before the constructor executes. scop.owns().
+ //!Notes: If the scop scoped_lock owns the mutex, ownership is moved
+ //! to thisscoped_lock with no blocking. If the scop scoped_lock does not
+ //! own the mutex, then neither will this scoped_lock. Only a moved
+ //! scoped_lock's will match this signature. An non-moved scoped_lock
+ //! can be moved with the expression: "boost::move(lock);". This
+ //! constructor does not alter the state of the mutex, only potentially
+ //! who owns it.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ scoped_lock(boost::rv<scoped_lock> &scop)
+ : mp_mutex(0), m_locked(scop.get().owns())
+ { mp_mutex = scop.get().release(); }
+ #else
+ scoped_lock(scoped_lock &&scop)
+ : mp_mutex(0), m_locked(scop.owns())
+ { mp_mutex = scop.release(); }
+ #endif
+
+ //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock() on the
+ //! referenced mutex. upgr.release() is called.
+ //!Postconditions: mutex() == the value upgr.mutex() had before the construction.
+ //! upgr.mutex() == 0. owns() == upgr.owns() before the construction.
+ //! upgr.owns() == false after the construction.
+ //!Notes: If upgr is locked, this constructor will lock this scoped_lock while
+ //! unlocking upgr. If upgr is unlocked, then this scoped_lock will be
+ //! unlocked as well. Only a moved upgradable_lock's will match this
+ //! signature. An non-moved upgradable_lock can be moved with
+ //! the expression: "boost::move(lock);" This constructor may block if
+ //! other threads hold a sharable_lock on this mutex (sharable_lock's can
+ //! share ownership with an upgradable_lock).
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ explicit scoped_lock(boost::rv<upgradable_lock<T> > &upgr
+ , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr.get();
+ if(u_lock.owns()){
+ u_lock.mutex()->unlock_upgradable_and_lock();
+ m_locked = true;
+ }
+ mp_mutex = u_lock.release();
+ }
+ #else
+ scoped_lock(upgradable_lock<Mutex> &&upgr)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr;
+ if(u_lock.owns()){
+ u_lock.mutex()->unlock_upgradable_and_lock();
+ m_locked = true;
+ }
+ mp_mutex = u_lock.release();
+ }
+ #endif
+
+ //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the
+ //!referenced mutex:
+ //! a)if try_unlock_upgradable_and_lock() returns true then mutex() obtains
+ //! the value from upgr.release() and owns() is set to true.
+ //! b)if try_unlock_upgradable_and_lock() returns false then upgr is
+ //! unaffected and this scoped_lock construction as the same effects as
+ //! a default construction.
+ //! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
+ //! and owns() is set to false
+ //!Notes: This construction will not block. It will try to obtain mutex
+ //! ownership from upgr immediately, while changing the lock type from a
+ //! "read lock" to a "write lock". If the "read lock" isn't held in the
+ //! first place, the mutex merely changes type to an unlocked "write lock".
+ //! If the "read lock" is held, then mutex transfer occurs only if it can
+ //! do so in a non-blocking manner.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ scoped_lock(boost::rv<upgradable_lock<T> > &upgr, try_to_lock_type
+ , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr.get();
+ if(u_lock.owns()){
+ if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){
+ mp_mutex = u_lock.release();
+ }
+ }
+ else{
+ u_lock.release();
+ }
+ }
+ #else
+ scoped_lock(upgradable_lock<Mutex> &&upgr, try_to_lock_type)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr;
+ if(u_lock.owns()){
+ if((m_locked = u_lock.mutex()->try_unlock_upgradable_and_lock()) == true){
+ mp_mutex = u_lock.release();
+ }
+ }
+ else{
+ u_lock.release();
+ }
+ }
+ #endif
+
+ //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time)
+ //! on the referenced mutex:
+ //! a)if timed_unlock_upgradable_and_lock(abs_time) returns true then mutex()
+ //! obtains the value from upgr.release() and owns() is set to true.
+ //! b)if timed_unlock_upgradable_and_lock(abs_time) returns false then upgr
+ //! is unaffected and this scoped_lock construction as the same effects
+ //! as a default construction.
+ //! c)Else upgr.owns() is false. mutex() obtains the value from upgr.release()
+ //! and owns() is set to false
+ //!Notes: This construction will not block. It will try to obtain mutex ownership
+ //! from upgr immediately, while changing the lock type from a "read lock" to a
+ //! "write lock". If the "read lock" isn't held in the first place, the mutex
+ //! merely changes type to an unlocked "write lock". If the "read lock" is held,
+ //! then mutex transfer occurs only if it can do so in a non-blocking manner.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ scoped_lock(boost::rv<upgradable_lock<T> > &upgr, boost::posix_time::ptime &abs_time
+ , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr.get();
+ if(u_lock.owns()){
+ if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){
+ mp_mutex = u_lock.release();
+ }
+ }
+ else{
+ u_lock.release();
+ }
+ }
+ #else
+ scoped_lock(upgradable_lock<Mutex> &&upgr, boost::posix_time::ptime &abs_time)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr;
+ if(u_lock.owns()){
+ if((m_locked = u_lock.mutex()->timed_unlock_upgradable_and_lock(abs_time)) == true){
+ mp_mutex = u_lock.release();
+ }
+ }
+ else{
+ u_lock.release();
+ }
+ }
+ #endif
+
+ //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the
+ //!referenced mutex.
+ //! a)if try_unlock_sharable_and_lock() returns true then mutex() obtains
+ //! the value from shar.release() and owns() is set to true.
+ //! b)if try_unlock_sharable_and_lock() returns false then shar is
+ //! unaffected and this scoped_lock construction has the same
+ //! effects as a default construction.
+ //! c)Else shar.owns() is false. mutex() obtains the value from
+ //! shar.release() and owns() is set to false
+ //!Notes: This construction will not block. It will try to obtain mutex
+ //! ownership from shar immediately, while changing the lock type from a
+ //! "read lock" to a "write lock". If the "read lock" isn't held in the
+ //! first place, the mutex merely changes type to an unlocked "write lock".
+ //! If the "read lock" is held, then mutex transfer occurs only if it can
+ //! do so in a non-blocking manner.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ scoped_lock(boost::rv<sharable_lock<T> > &shar, try_to_lock_type
+ , typename detail::enable_if< detail::is_same<T, Mutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ sharable_lock<mutex_type> &s_lock = shar.get();
+ if(s_lock.owns()){
+ if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){
+ mp_mutex = s_lock.release();
+ }
+ }
+ else{
+ s_lock.release();
+ }
+ }
+ #else
+ template<class T>
+ scoped_lock(sharable_lock<T> &&shar, try_to_lock_type)
+ : mp_mutex(0), m_locked(false)
+ {
+ sharable_lock<mutex_type> &s_lock = shar;
+ if(s_lock.owns()){
+ if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock()) == true){
+ mp_mutex = s_lock.release();
+ }
+ }
+ else{
+ s_lock.release();
+ }
+ }
+ #endif
+
+ //!Effects: if (owns()) mp_mutex->unlock().
+ //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/
+ ~scoped_lock()
+ {
+ try{ if(m_locked && mp_mutex) mp_mutex->unlock(); }
+ catch(...){}
+ }
+
+ //!Effects: If owns() before the call, then unlock() is called on mutex().
+ //! *this gets the state of scop and scop gets set to a default constructed state.
+ //!Notes: With a recursive mutex it is possible that both this and scop own
+ //! the same mutex before the assignment. In this case, this will own the
+ //! mutex after the assignment (and scop will not), but the mutex's lock
+ //! count will be decremented by one.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ scoped_lock &operator=(boost::rv<scoped_lock> &scop)
+ {
+ if(this->owns())
+ this->unlock();
+ m_locked = scop.get().owns();
+ mp_mutex = scop.get().release();
+ return *this;
+ }
+ #else
+ scoped_lock &operator=(scoped_lock &&scop)
+ {
+ if(this->owns())
+ this->unlock();
+ m_locked = scop.owns();
+ mp_mutex = scop.release();
+ return *this;
+ }
+ #endif
+
+ //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
+ //! exception. Calls lock() on the referenced mutex.
+ //!Postconditions: owns() == true.
+ //!Notes: The scoped_lock changes from a state of not owning the mutex, to
+ //! owning the mutex, blocking if necessary.
+ void lock()
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ mp_mutex->lock();
+ m_locked = true;
+ }
+
+ //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
+ //! exception. Calls try_lock() on the referenced mutex.
+ //!Postconditions: owns() == the value returned from mutex()->try_lock().
+ //!Notes: The scoped_lock changes from a state of not owning the mutex, to
+ //! owning the mutex, but only if blocking was not required. If the
+ //! mutex_type does not support try_lock(), this function will fail at
+ //! compile time if instantiated, but otherwise have no effect.*/
+ bool try_lock()
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ m_locked = mp_mutex->try_lock();
+ return m_locked;
+ }
+
+ //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
+ //! exception. Calls timed_lock(abs_time) on the referenced mutex.
+ //!Postconditions: owns() == the value returned from mutex()-> timed_lock(abs_time).
+ //!Notes: The scoped_lock changes from a state of not owning the mutex, to
+ //! owning the mutex, but only if it can obtain ownership by the specified
+ //! time. If the mutex_type does not support timed_lock (), this function
+ //! will fail at compile time if instantiated, but otherwise have no effect.*/
+ bool timed_lock(const boost::posix_time::ptime& abs_time)
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ m_locked = mp_mutex->timed_lock(abs_time);
+ return m_locked;
+ }
+
+ //!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
+ //! exception. Calls unlock() on the referenced mutex.
+ //!Postconditions: owns() == false.
+ //!Notes: The scoped_lock changes from a state of owning the mutex, to not
+ //! owning the mutex.*/
+ void unlock()
+ {
+ if(!mp_mutex || !m_locked)
+ throw lock_exception();
+ mp_mutex->unlock();
+ m_locked = false;
+ }
+
+ //!Effects: Returns true if this scoped_lock has acquired
+ //!the referenced mutex.
+ bool owns() const
+ { return m_locked && mp_mutex; }
+
+ //!Conversion to bool.
+ //!Returns owns().
+ operator unspecified_bool_type() const
+ { return m_locked? &this_type::m_locked : 0; }
+
+ //!Effects: Returns a pointer to the referenced mutex, or 0 if
+ //!there is no mutex to reference.
+ mutex_type* mutex() const
+ { return mp_mutex; }
+
+ //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
+ //! mutex to reference.
+ //!Postconditions: mutex() == 0 and owns() == false.
+ mutex_type* release()
+ {
+ mutex_type *mut = mp_mutex;
+ mp_mutex = 0;
+ m_locked = false;
+ return mut;
+ }
+
+ //!Effects: Swaps state with moved lock.
+ //!Throws: Nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<scoped_lock<mutex_type> > &other)
+ {
+ std::swap(mp_mutex, other.get().mp_mutex);
+ std::swap(m_locked, other.get().m_locked);
+ }
+ #else
+ void swap(scoped_lock<mutex_type> &&other)
+ {
+ std::swap(mp_mutex, other.mp_mutex);
+ std::swap(m_locked, other.m_locked);
+ }
+ #endif
+
+ /// @cond
+ private:
+ mutex_type *mp_mutex;
+ bool m_locked;
+ /// @endcond
+};
+
+} // namespace interprocess
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_SCOPED_LOCK_HPP
Added: sandbox/boost/interprocess/sync/sharable_lock.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/sharable_lock.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,359 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This interface is inspired by Howard Hinnant's lock proposal.
+// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_SHARABLE_LOCK_HPP
+#define BOOST_INTERPROCESS_SHARABLE_LOCK_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/sync/lock_options.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+//!\file
+//!Describes the upgradable_lock class that serves to acquire the upgradable
+//!lock of a mutex.
+
+namespace boost {
+namespace interprocess {
+
+
+//!sharable_lock is meant to carry out the tasks for sharable-locking
+//!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking
+//!(recursive or not) for the Mutex. The Mutex need not supply all of this
+//!functionality. If the client of sharable_lock<Mutex> does not use functionality which
+//!the Mutex does not supply, no harm is done. Mutex ownership can be shared among
+//!sharable_locks, and a single upgradable_lock. sharable_lock does not support
+//!copy semantics. But sharable_lock supports ownership transfer from an sharable_lock,
+//!upgradable_lock and scoped_lock via transfer_lock syntax.*/
+template <class SharableMutex>
+class sharable_lock
+{
+ public:
+ typedef SharableMutex mutex_type;
+ /// @cond
+ private:
+ typedef sharable_lock<SharableMutex> this_type;
+ sharable_lock(sharable_lock&);
+ explicit sharable_lock(scoped_lock<mutex_type>&);
+ typedef bool this_type::*unspecified_bool_type;
+ sharable_lock& operator=(sharable_lock&);
+ sharable_lock& operator=(scoped_lock<mutex_type>&);
+ /// @endcond
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(sharable_lock)
+
+ //!Effects: Default constructs a sharable_lock.
+ //!Postconditions: owns() == false and mutex() == 0.
+ sharable_lock()
+ : mp_mutex(0), m_locked(false)
+ {}
+
+ //!Effects: m.lock_sharable().
+ //!Postconditions: owns() == true and mutex() == &m.
+ //!Notes: The constructor will take sharable-ownership of the mutex. If
+ //! another thread already owns the mutex with exclusive ownership
+ //! (scoped_lock), this thread will block until the mutex is released.
+ //! If another thread owns the mutex with sharable or upgradable ownership,
+ //! then no blocking will occur. Whether or not this constructor handles
+ //! recursive locking depends upon the mutex.
+ explicit sharable_lock(mutex_type& m)
+ : mp_mutex(&m), m_locked(false)
+ { mp_mutex->lock_sharable(); m_locked = true; }
+
+ //!Postconditions: owns() == false, and mutex() == &m.
+ //!Notes: The constructor will not take ownership of the mutex. There is no effect
+ //! required on the referenced mutex.
+ sharable_lock(mutex_type& m, defer_lock_type)
+ : mp_mutex(&m), m_locked(false)
+ {}
+
+ //!Postconditions: owns() == true, and mutex() == &m.
+ //!Notes: The constructor will suppose that the mutex is already sharable
+ //! locked. There is no effect required on the referenced mutex.
+ sharable_lock(mutex_type& m, accept_ownership_type)
+ : mp_mutex(&m), m_locked(true)
+ {}
+
+ //!Effects: m.try_lock_sharable()
+ //!Postconditions: mutex() == &m. owns() == the return value of the
+ //! m.try_lock_sharable() executed within the constructor.
+ //!Notes: The constructor will take sharable-ownership of the mutex if it
+ //! can do so without waiting. Whether or not this constructor handles
+ //! recursive locking depends upon the mutex. If the mutex_type does not
+ //! support try_lock_sharable, this constructor will fail at compile
+ //! time if instantiated, but otherwise have no effect.
+ sharable_lock(mutex_type& m, try_to_lock_type)
+ : mp_mutex(&m), m_locked(false)
+ { m_locked = mp_mutex->try_lock_sharable(); }
+
+ //!Effects: m.timed_lock_sharable(abs_time)
+ //!Postconditions: mutex() == &m. owns() == the return value of the
+ //! m.timed_lock_sharable() executed within the constructor.
+ //!Notes: The constructor will take sharable-ownership of the mutex if it
+ //! can do so within the time specified. Whether or not this constructor
+ //! handles recursive locking depends upon the mutex. If the mutex_type
+ //! does not support timed_lock_sharable, this constructor will fail at
+ //! compile time if instantiated, but otherwise have no effect.
+ sharable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
+ : mp_mutex(&m), m_locked(false)
+ { m_locked = mp_mutex->timed_lock_sharable(abs_time); }
+
+ //!Postconditions: mutex() == upgr.mutex(). owns() == the value of upgr.owns()
+ //! before the construction. upgr.owns() == false after the construction.
+ //!Notes: If the upgr sharable_lock owns the mutex, ownership is moved to this
+ //! sharable_lock with no blocking. If the upgr sharable_lock does not own the mutex, then
+ //! neither will this sharable_lock. Only a moved sharable_lock's will match this
+ //! signature. An non-moved sharable_lock can be moved with the expression:
+ //! "boost::move(lock);". This constructor does not alter the state of the mutex,
+ //! only potentially who owns it.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ sharable_lock(boost::rv<sharable_lock> &upgr)
+ : mp_mutex(0), m_locked(upgr.get().owns())
+ { mp_mutex = upgr.get().release(); }
+ #else
+ sharable_lock(sharable_lock<mutex_type> &&upgr)
+ : mp_mutex(0), m_locked(upgr.owns())
+ { mp_mutex = upgr.release(); }
+ #endif
+
+ //!Effects: If upgr.owns() then calls unlock_upgradable_and_lock_sharable() on the
+ //! referenced mutex.
+ //!Postconditions: mutex() == the value upgr.mutex() had before the construction.
+ //! upgr.mutex() == 0 owns() == the value of upgr.owns() before construction.
+ //! upgr.owns() == false after the construction.
+ //!Notes: If upgr is locked, this constructor will lock this sharable_lock while
+ //! unlocking upgr. Only a moved sharable_lock's will match this
+ //! signature. An non-moved upgradable_lock can be moved with the expression:
+ //! "boost::move(lock);".*/
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ sharable_lock(boost::rv<upgradable_lock<T> > &upgr
+ , typename detail::enable_if< detail::is_same<T, SharableMutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr.get();
+ if(u_lock.owns()){
+ u_lock.mutex()->unlock_upgradable_and_lock_sharable();
+ m_locked = true;
+ }
+ mp_mutex = u_lock.release();
+ }
+ #else
+ sharable_lock(upgradable_lock<mutex_type> &&upgr)
+ : mp_mutex(0), m_locked(false)
+ {
+ upgradable_lock<mutex_type> &u_lock = upgr;
+ if(u_lock.owns()){
+ u_lock.mutex()->unlock_upgradable_and_lock_sharable();
+ m_locked = true;
+ }
+ mp_mutex = u_lock.release();
+ }
+ #endif
+
+ //!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the
+ //! referenced mutex.
+ //!Postconditions: mutex() == the value scop.mutex() had before the construction.
+ //! scop.mutex() == 0 owns() == scop.owns() before the constructor. After the
+ //! construction, scop.owns() == false.
+ //!Notes: If scop is locked, this constructor will transfer the exclusive ownership
+ //! to a sharable-ownership of this sharable_lock.
+ //! Only a moved scoped_lock's will match this
+ //! signature. An non-moved scoped_lock can be moved with the expression:
+ //! "boost::move(lock);".
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ sharable_lock(boost::rv<scoped_lock<T> > &scop
+ , typename detail::enable_if< detail::is_same<T, SharableMutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ scoped_lock<mutex_type> &e_lock = scop.get();
+ if(e_lock.owns()){
+ e_lock.mutex()->unlock_and_lock_sharable();
+ m_locked = true;
+ }
+ mp_mutex = e_lock.release();
+ }
+ #else
+ sharable_lock(scoped_lock<mutex_type> &&scop)
+ : mp_mutex(0), m_locked(false)
+ {
+ scoped_lock<mutex_type> &e_lock = scop;
+ if(e_lock.owns()){
+ e_lock.mutex()->unlock_and_lock_sharable();
+ m_locked = true;
+ }
+ mp_mutex = e_lock.release();
+ }
+ #endif
+
+ //!Effects: if (owns()) mp_mutex->unlock_sharable().
+ //!Notes: The destructor behavior ensures that the mutex lock is not leaked.
+ ~sharable_lock()
+ {
+ try{
+ if(m_locked && mp_mutex) mp_mutex->unlock_sharable();
+ }
+ catch(...){}
+ }
+
+ //!Effects: If owns() before the call, then unlock_sharable() is called on mutex().
+ //! *this gets the state of upgr and upgr gets set to a default constructed state.
+ //!Notes: With a recursive mutex it is possible that both this and upgr own the mutex
+ //! before the assignment. In this case, this will own the mutex after the assignment
+ //! (and upgr will not), but the mutex's lock count will be decremented by one.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ sharable_lock &operator=(boost::rv<sharable_lock<mutex_type> > &upgr)
+ {
+ if(this->owns())
+ this->unlock();
+ m_locked = upgr.get().owns();
+ mp_mutex = upgr.get().release();
+ return *this;
+ }
+ #else
+ sharable_lock &operator=(sharable_lock<mutex_type> &&upgr)
+ {
+ if(this->owns())
+ this->unlock();
+ m_locked = upgr.owns();
+ mp_mutex = upgr.release();
+ return *this;
+ }
+ #endif
+
+ //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
+ //! exception. Calls lock_sharable() on the referenced mutex.
+ //!Postconditions: owns() == true.
+ //!Notes: The sharable_lock changes from a state of not owning the
+ //! mutex, to owning the mutex, blocking if necessary.
+ void lock()
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ mp_mutex->lock_sharable();
+ m_locked = true;
+ }
+
+ //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
+ //! exception. Calls try_lock_sharable() on the referenced mutex.
+ //!Postconditions: owns() == the value returned from
+ //! mutex()->try_lock_sharable().
+ //!Notes: The sharable_lock changes from a state of not owning the mutex,
+ //! to owning the mutex, but only if blocking was not required. If the
+ //! mutex_type does not support try_lock_sharable(), this function will
+ //! fail at compile time if instantiated, but otherwise have no effect.
+ bool try_lock()
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ m_locked = mp_mutex->try_lock_sharable();
+ return m_locked;
+ }
+
+ //!Effects: If mutex() == 0 or already locked, throws a lock_exception()
+ //! exception. Calls timed_lock_sharable(abs_time) on the referenced mutex.
+ //!Postconditions: owns() == the value returned from
+ //! mutex()->timed_lock_sharable(elps_time).
+ //!Notes: The sharable_lock changes from a state of not owning the mutex,
+ //! to owning the mutex, but only if it can obtain ownership within the
+ //! specified time interval. If the mutex_type does not support
+ //! timed_lock_sharable(), this function will fail at compile time if
+ //! instantiated, but otherwise have no effect.
+ bool timed_lock(const boost::posix_time::ptime& abs_time)
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ m_locked = mp_mutex->timed_lock_sharable(abs_time);
+ return m_locked;
+ }
+
+ //!Effects: If mutex() == 0 or not locked, throws a lock_exception() exception.
+ //! Calls unlock_sharable() on the referenced mutex.
+ //!Postconditions: owns() == false.
+ //!Notes: The sharable_lock changes from a state of owning the mutex, to
+ //! not owning the mutex.
+ void unlock()
+ {
+ if(!mp_mutex || !m_locked)
+ throw lock_exception();
+ mp_mutex->unlock_sharable();
+ m_locked = false;
+ }
+
+ //!Effects: Returns true if this scoped_lock has
+ //!acquired the referenced mutex.
+ bool owns() const
+ { return m_locked && mp_mutex; }
+
+ //!Conversion to bool.
+ //!Returns owns().
+ operator unspecified_bool_type() const
+ { return m_locked? &this_type::m_locked : 0; }
+
+ //!Effects: Returns a pointer to the referenced mutex, or 0 if
+ //!there is no mutex to reference.
+ mutex_type* mutex() const
+ { return mp_mutex; }
+
+ //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
+ //! mutex to reference.
+ //!Postconditions: mutex() == 0 and owns() == false.
+ mutex_type* release()
+ {
+ mutex_type *mut = mp_mutex;
+ mp_mutex = 0;
+ m_locked = false;
+ return mut;
+ }
+
+ //!Effects: Swaps state with moved lock.
+ //!Throws: Nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<sharable_lock<mutex_type> > &other)
+ {
+ std::swap(mp_mutex, other.get().mp_mutex);
+ std::swap(m_locked, other.get().m_locked);
+ }
+ #else
+ void swap(sharable_lock<mutex_type> &&other)
+ {
+ std::swap(mp_mutex, other.mp_mutex);
+ std::swap(m_locked, other.m_locked);
+ }
+ #endif
+
+ /// @cond
+ private:
+ mutex_type *mp_mutex;
+ bool m_locked;
+ /// @endcond
+};
+
+} // namespace interprocess
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_SHARABLE_LOCK_HPP
Added: sandbox/boost/interprocess/sync/upgradable_lock.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/sync/upgradable_lock.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,366 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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.
+//
+//////////////////////////////////////////////////////////////////////////////
+//
+// This interface is inspired by Howard Hinnant's lock proposal.
+// http://home.twcny.rr.com/hinnant/cpp_extensions/threads_move.html
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP
+#define BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP
+
+#if (defined _MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/sync/lock_options.hpp>
+#include <boost/interprocess/detail/mpl.hpp>
+#include <boost/interprocess/detail/type_traits.hpp>
+
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/move_semantics/move.hpp>
+#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
+
+//!\file
+//!Describes the upgradable_lock class that serves to acquire the upgradable
+//!lock of a mutex.
+
+namespace boost {
+namespace interprocess {
+
+//!upgradable_lock is meant to carry out the tasks for read-locking, unlocking,
+//!try-read-locking and timed-read-locking (recursive or not) for the Mutex.
+//!Additionally the upgradable_lock can transfer ownership to a scoped_lock
+//!using transfer_lock syntax. The Mutex need not supply all of the functionality.
+//!If the client of upgradable_lock<Mutex> does not use functionality which the
+//!Mutex does not supply, no harm is done. Mutex ownership can be shared among
+//!read_locks, and a single upgradable_lock. upgradable_lock does not support
+//!copy semantics. However upgradable_lock supports ownership transfer from
+//!a upgradable_locks or scoped_locks via transfer_lock syntax.
+template <class UpgradableMutex>
+class upgradable_lock
+{
+ public:
+ typedef UpgradableMutex mutex_type;
+ /// @cond
+ private:
+ typedef upgradable_lock<UpgradableMutex> this_type;
+ upgradable_lock(upgradable_lock&);
+ explicit upgradable_lock(scoped_lock<mutex_type>&);
+ typedef bool this_type::*unspecified_bool_type;
+ upgradable_lock& operator=(upgradable_lock&);
+ upgradable_lock& operator=(scoped_lock<mutex_type>&);
+ /// @endcond
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(upgradable_lock)
+
+ //!Effects: Default constructs a upgradable_lock.
+ //!Postconditions: owns() == false and mutex() == 0.
+ upgradable_lock()
+ : mp_mutex(0), m_locked(false)
+ {}
+
+ explicit upgradable_lock(mutex_type& m)
+ : mp_mutex(&m), m_locked(false)
+ { mp_mutex->lock_upgradable(); m_locked = true; }
+
+ //!Postconditions: owns() == false, and mutex() == &m.
+ //!Notes: The constructor will not take ownership of the mutex. There is no effect
+ //! required on the referenced mutex.
+ upgradable_lock(mutex_type& m, defer_lock_type)
+ : mp_mutex(&m), m_locked(false)
+ {}
+
+ //!Postconditions: owns() == true, and mutex() == &m.
+ //!Notes: The constructor will suppose that the mutex is already upgradable
+ //! locked. There is no effect required on the referenced mutex.
+ upgradable_lock(mutex_type& m, accept_ownership_type)
+ : mp_mutex(&m), m_locked(true)
+ {}
+
+ //!Effects: m.try_lock_upgradable().
+ //!Postconditions: mutex() == &m. owns() == the return value of the
+ //! m.try_lock_upgradable() executed within the constructor.
+ //!Notes: The constructor will take upgradable-ownership of the mutex
+ //! if it can do so without waiting. Whether or not this constructor
+ //! handles recursive locking depends upon the mutex. If the mutex_type
+ //! does not support try_lock_upgradable, this constructor will fail at
+ //! compile time if instantiated, but otherwise have no effect.
+ upgradable_lock(mutex_type& m, try_to_lock_type)
+ : mp_mutex(&m), m_locked(false)
+ { m_locked = mp_mutex->try_lock_upgradable(); }
+
+ //!Effects: m.timed_lock_upgradable(abs_time)
+ //!Postconditions: mutex() == &m. owns() == the return value of the
+ //! m.timed_lock_upgradable() executed within the constructor.
+ //!Notes: The constructor will take upgradable-ownership of the mutex if it
+ //! can do so within the time specified. Whether or not this constructor
+ //! handles recursive locking depends upon the mutex. If the mutex_type
+ //! does not support timed_lock_upgradable, this constructor will fail
+ //! at compile time if instantiated, but otherwise have no effect.
+ upgradable_lock(mutex_type& m, const boost::posix_time::ptime& abs_time)
+ : mp_mutex(&m), m_locked(false)
+ { m_locked = mp_mutex->timed_lock_upgradable(abs_time); }
+
+ //!Effects: No effects on the underlying mutex.
+ //!Postconditions: mutex() == the value upgr.mutex() had before the
+ //! construction. upgr.mutex() == 0. owns() == upgr.owns() before the
+ //! construction. upgr.owns() == false.
+ //!Notes: If upgr is locked, this constructor will lock this upgradable_lock
+ //! while unlocking upgr. If upgr is unlocked, then this upgradable_lock will
+ //! be unlocked as well. Only a moved upgradable_lock's will match this
+ //! signature. An non-moved upgradable_lock can be moved with the
+ //! expression: "boost::move(lock);". This constructor does not alter the
+ //! state of the mutex, only potentially who owns it.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ upgradable_lock(boost::rv<upgradable_lock<mutex_type> > &upgr)
+ : mp_mutex(0), m_locked(upgr.get().owns())
+ { mp_mutex = upgr.get().release(); }
+ #else
+ upgradable_lock(upgradable_lock<mutex_type> &&upgr)
+ : mp_mutex(0), m_locked(upgr.owns())
+ { mp_mutex = upgr.release(); }
+ #endif
+
+ //!Effects: If scop.owns(), m_.unlock_and_lock_upgradable().
+ //!Postconditions: mutex() == the value scop.mutex() had before the construction.
+ //! scop.mutex() == 0. owns() == scop.owns() before the constructor. After the
+ //! construction, scop.owns() == false.
+ //!Notes: If scop is locked, this constructor will transfer the exclusive-ownership
+ //! to an upgradable-ownership of this upgradable_lock.
+ //! Only a moved sharable_lock's will match this
+ //! signature. An non-moved sharable_lock can be moved with the
+ //! expression: "boost::move(lock);".
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ upgradable_lock(boost::rv<scoped_lock<T> > &scop
+ , typename detail::enable_if< detail::is_same<T, UpgradableMutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ scoped_lock<mutex_type> &u_lock = scop.get();
+ if(u_lock.owns()){
+ u_lock.mutex()->unlock_and_lock_upgradable();
+ m_locked = true;
+ }
+ mp_mutex = u_lock.release();
+ }
+ #else
+ upgradable_lock(scoped_lock<mutex_type> &&scop)
+ : mp_mutex(0), m_locked(false)
+ {
+ scoped_lock<mutex_type> &u_lock = scop;
+ if(u_lock.owns()){
+ u_lock.mutex()->unlock_and_lock_upgradable();
+ m_locked = true;
+ }
+ mp_mutex = u_lock.release();
+ }
+ #endif
+
+ //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock_upgradable()
+ //! on the referenced mutex.
+ //! a)if try_unlock_sharable_and_lock_upgradable() returns true then mutex()
+ //! obtains the value from shar.release() and owns() is set to true.
+ //! b)if try_unlock_sharable_and_lock_upgradable() returns false then shar is
+ //! unaffected and this upgradable_lock construction has the same
+ //! effects as a default construction.
+ //! c)Else shar.owns() is false. mutex() obtains the value from shar.release()
+ //! and owns() is set to false.
+ //!Notes: This construction will not block. It will try to obtain mutex
+ //! ownership from shar immediately, while changing the lock type from a
+ //! "read lock" to an "upgradable lock". If the "read lock" isn't held
+ //! in the first place, the mutex merely changes type to an unlocked
+ //! "upgradable lock". If the "read lock" is held, then mutex transfer
+ //! occurs only if it can do so in a non-blocking manner.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ template<class T>
+ upgradable_lock( boost::rv<sharable_lock<T> > &shar, try_to_lock_type
+ , typename detail::enable_if< detail::is_same<T, UpgradableMutex> >::type * = 0)
+ : mp_mutex(0), m_locked(false)
+ {
+ sharable_lock<mutex_type> &s_lock = shar.get();
+ if(s_lock.owns()){
+ if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock_upgradable()) == true){
+ mp_mutex = s_lock.release();
+ }
+ }
+ else{
+ s_lock.release();
+ }
+ }
+ #else
+ upgradable_lock( sharable_lock<mutex_type> &&shar, try_to_lock_type)
+ : mp_mutex(0), m_locked(false)
+ {
+ sharable_lock<mutex_type> &s_lock = shar;
+ if(s_lock.owns()){
+ if((m_locked = s_lock.mutex()->try_unlock_sharable_and_lock_upgradable()) == true){
+ mp_mutex = s_lock.release();
+ }
+ }
+ else{
+ s_lock.release();
+ }
+ }
+ #endif
+
+ //!Effects: if (owns()) m_->unlock_upgradable().
+ //!Notes: The destructor behavior ensures that the mutex lock is not leaked.
+ ~upgradable_lock()
+ {
+ try{
+ if(m_locked && mp_mutex) mp_mutex->unlock_upgradable();
+ }
+ catch(...){}
+ }
+
+ //!Effects: If owns(), then unlock_upgradable() is called on mutex().
+ //! *this gets the state of upgr and upgr gets set to a default constructed state.
+ //!Notes: With a recursive mutex it is possible that both this and upgr own the
+ //! mutex before the assignment. In this case, this will own the mutex
+ //! after the assignment (and upgr will not), but the mutex's upgradable lock
+ //! count will be decremented by one.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ upgradable_lock &operator=(boost::rv<upgradable_lock<mutex_type> > &upgr)
+ {
+ if(this->owns())
+ this->unlock();
+ m_locked = upgr.get().owns();
+ mp_mutex = upgr.get().release();
+ return *this;
+ }
+ #else
+ upgradable_lock &operator=(upgradable_lock<mutex_type> &&upgr)
+ {
+ if(this->owns())
+ this->unlock();
+ m_locked = upgr.owns();
+ mp_mutex = upgr.release();
+ return *this;
+ }
+ #endif
+
+ //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
+ //! exception. Calls lock_upgradable() on the referenced mutex.
+ //!Postconditions: owns() == true.
+ //!Notes: The sharable_lock changes from a state of not owning the mutex,
+ //! to owning the mutex, blocking if necessary.
+ void lock()
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ mp_mutex->lock_upgradable();
+ m_locked = true;
+ }
+
+ //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
+ //! exception. Calls try_lock_upgradable() on the referenced mutex.
+ //!Postconditions: owns() == the value returned from
+ //! mutex()->try_lock_upgradable().
+ //!Notes: The upgradable_lock changes from a state of not owning the mutex,
+ //! to owning the mutex, but only if blocking was not required. If the
+ //! mutex_type does not support try_lock_upgradable(), this function will
+ //! fail at compile time if instantiated, but otherwise have no effect.
+ bool try_lock()
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ m_locked = mp_mutex->try_lock_upgradable();
+ return m_locked;
+ }
+
+ //!Effects: If mutex() == 0 or if already locked, throws a lock_exception()
+ //! exception. Calls timed_lock_upgradable(abs_time) on the referenced mutex.
+ //!Postconditions: owns() == the value returned from
+ //! mutex()->timed_lock_upgradable(abs_time).
+ //!Notes: The upgradable_lock changes from a state of not owning the mutex,
+ //! to owning the mutex, but only if it can obtain ownership within the
+ //! specified time. If the mutex_type does not support
+ //! timed_lock_upgradable(abs_time), this function will fail at compile
+ //! time if instantiated, but otherwise have no effect.
+ bool timed_lock(const boost::posix_time::ptime& abs_time)
+ {
+ if(!mp_mutex || m_locked)
+ throw lock_exception();
+ m_locked = mp_mutex->timed_lock_upgradable(abs_time);
+ return m_locked;
+ }
+
+ //!Effects: If mutex() == 0 or if not locked, throws a lock_exception()
+ //! exception. Calls unlock_upgradable() on the referenced mutex.
+ //!Postconditions: owns() == false.
+ //!Notes: The upgradable_lock changes from a state of owning the mutex,
+ //! to not owning the mutex.
+ void unlock()
+ {
+ if(!mp_mutex || !m_locked)
+ throw lock_exception();
+ mp_mutex->unlock_upgradable();
+ m_locked = false;
+ }
+
+ //!Effects: Returns true if this scoped_lock has acquired the
+ //!referenced mutex.
+ bool owns() const
+ { return m_locked && mp_mutex; }
+
+ //!Conversion to bool.
+ //!Returns owns().
+ operator unspecified_bool_type() const
+ { return m_locked? &this_type::m_locked : 0; }
+
+ //!Effects: Returns a pointer to the referenced mutex, or 0 if
+ //!there is no mutex to reference.
+ mutex_type* mutex() const
+ { return mp_mutex; }
+
+ //!Effects: Returns a pointer to the referenced mutex, or 0 if there is no
+ //! mutex to reference.
+ //!Postconditions: mutex() == 0 and owns() == false.
+ mutex_type* release()
+ {
+ mutex_type *mut = mp_mutex;
+ mp_mutex = 0;
+ m_locked = false;
+ return mut;
+ }
+
+ //!Effects: Swaps state with moved lock.
+ //!Throws: Nothing.
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ void swap(boost::rv<upgradable_lock<mutex_type> > &other)
+ {
+ std::swap(mp_mutex, other.get().mp_mutex);
+ std::swap(m_locked, other.get().m_locked);
+ }
+ #else
+ void swap(upgradable_lock<mutex_type> &&other)
+ {
+ std::swap(mp_mutex, other.mp_mutex);
+ std::swap(m_locked, other.m_locked);
+ }
+ #endif
+
+ /// @cond
+ private:
+ mutex_type *mp_mutex;
+ bool m_locked;
+ /// @endcond
+};
+
+} // namespace interprocess
+} // namespace boost
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif // BOOST_INTERPROCESS_UPGRADABLE_LOCK_HPP
Added: sandbox/boost/interprocess/windows_shared_memory.hpp
==============================================================================
--- (empty file)
+++ sandbox/boost/interprocess/windows_shared_memory.hpp 2009-02-17 13:04:56 EST (Tue, 17 Feb 2009)
@@ -0,0 +1,241 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (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_WINDOWS_SHARED_MEMORY_HPP
+#define BOOST_INTERPROCESS_WINDOWS_SHARED_MEMORY_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/detail/workaround.hpp>
+
+#if !defined(BOOST_INTERPROCESS_WINDOWS)
+#error "This header can only be used in Windows operating systems"
+#endif
+
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/utilities.hpp>
+#include <boost/interprocess/detail/os_file_functions.hpp>
+#include <boost/interprocess/interprocess_fwd.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/detail/win32_api.hpp>
+#include <cstddef>
+#include <boost/cstdint.hpp>
+#include <string>
+
+//!\file
+//!Describes a class representing a native windows shared memory.
+
+namespace boost {
+namespace interprocess {
+
+//!A class that wraps the native Windows shared memory
+//!that is implemented as a file mapping of the paging file.
+//!Unlike shared_memory_object, windows_shared_memory has
+//!no kernel persistence and the shared memory is destroyed
+//!when all processes destroy all their windows_shared_memory
+//!objects and mapped regions for the same shared memory
+//!or the processes end/crash.
+//!
+//!Warning: Windows native shared memory and interprocess portable
+//!shared memory (boost::interprocess::shared_memory_object)
+//!can't communicate between them.
+class windows_shared_memory
+{
+ /// @cond
+ //Non-copyable and non-assignable
+ windows_shared_memory(windows_shared_memory &);
+ windows_shared_memory &operator=(windows_shared_memory &);
+ /// @endcond
+
+ public:
+ BOOST_ENABLE_MOVE_EMULATION(windows_shared_memory)
+
+ //!Default constructor.
+ //!Represents an empty windows_shared_memory.
+ windows_shared_memory();
+
+ //!Creates a new native shared memory with name "name" and mode "mode",
+ //!with the access mode "mode".
+ //!If the file previously exists, throws an error.
+ windows_shared_memory(create_only_t, const char *name, mode_t mode, std::size_t size)
+ { this->priv_open_or_create(detail::DoCreate, name, mode, size); }
+
+ //!Tries to create a shared memory object 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.
+ windows_shared_memory(open_or_create_t, const char *name, mode_t mode, std::size_t size)
+ { this->priv_open_or_create(detail::DoOpenOrCreate, name, mode, size); }
+
+ //!Tries to open a shared memory object with name "name", with the access mode "mode".
+ //!If the file does not previously exist, it throws an error.
+ windows_shared_memory(open_only_t, const char *name, mode_t mode)
+ { this->priv_open_or_create(detail::DoOpen, name, mode, 0); }
+
+ //!Moves the ownership of "moved"'s shared memory object to *this.
+ //!After the call, "moved" does not represent any shared memory object.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ windows_shared_memory(boost::rv<windows_shared_memory> &moved)
+ { this->swap(moved.get()); }
+ #else
+ windows_shared_memory(windows_shared_memory &&moved)
+ { this->swap(moved); }
+ #endif
+
+ //!Moves the ownership of "moved"'s shared memory to *this.
+ //!After the call, "moved" does not represent any shared memory.
+ //!Does not throw
+ #if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
+ windows_shared_memory &operator=(boost::rv<windows_shared_memory> &moved)
+ #else
+ windows_shared_memory &operator=(windows_shared_memory &&moved)
+ #endif
+ {
+ windows_shared_memory tmp(boost::move(moved));
+ this->swap(tmp);
+ return *this;
+ }
+
+ //!Swaps to shared_memory_objects. Does not throw
+ void swap(windows_shared_memory &other);
+
+ //!Destroys *this. All mapped regions are still valid after
+ //!destruction. When all mapped regions and windows_shared_memory
+ //!objects referring the shared memory are destroyed, the
+ //!operating system will destroy the shared memory.
+ ~windows_shared_memory();
+
+ //!Returns the name of the shared memory.
+ const char *get_name() const;
+
+ //!Returns access mode
+ mode_t get_mode() const;
+
+ //!Returns the mapping handle. Never throws
+ mapping_handle_t get_mapping_handle() const;
+
+ /// @cond
+ 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, std::size_t size);
+
+ void * m_handle;
+ mode_t m_mode;
+ std::string m_name;
+ /// @endcond
+};
+
+/// @cond
+
+inline windows_shared_memory::windows_shared_memory()
+ : m_handle(0)
+{}
+
+inline windows_shared_memory::~windows_shared_memory()
+{ this->priv_close(); }
+
+inline const char *windows_shared_memory::get_name() const
+{ return m_name.c_str(); }
+
+inline void windows_shared_memory::swap(windows_shared_memory &other)
+{
+ std::swap(m_handle, other.m_handle);
+ std::swap(m_mode, other.m_mode);
+ m_name.swap(other.m_name);
+}
+
+inline mapping_handle_t windows_shared_memory::get_mapping_handle() const
+{ mapping_handle_t mhnd = { m_handle, true}; return mhnd; }
+
+inline mode_t windows_shared_memory::get_mode() const
+{ return m_mode; }
+
+inline bool windows_shared_memory::priv_open_or_create
+ (detail::create_enum_t type, const char *filename, mode_t mode, std::size_t size)
+{
+ m_name = filename ? filename : "";
+
+ unsigned long file_map_access = 0;
+ unsigned long map_access = 0;
+
+ switch(mode)
+ {
+ case read_only:
+ file_map_access |= winapi::page_readonly;
+ map_access |= winapi::file_map_read;
+ break;
+ case read_write:
+ file_map_access |= winapi::page_readwrite;
+ map_access |= winapi::file_map_write;
+ break;
+ case copy_on_write:
+ file_map_access |= winapi::page_writecopy;
+ map_access |= winapi::file_map_copy;
+ break;
+ default:
+ {
+ error_info err(mode_error);
+ throw interprocess_exception(err);
+ }
+ break;
+ }
+
+ switch(type){
+ case detail::DoOpen:
+ m_handle = winapi::open_file_mapping
+ (map_access, filename);
+ break;
+ case detail::DoCreate:
+ case detail::DoOpenOrCreate:
+ {
+ __int64 s = size;
+ unsigned long high_size(s >> 32), low_size((boost::uint32_t)s);
+ m_handle = winapi::create_file_mapping
+ (winapi::invalid_handle_value, file_map_access, high_size, low_size, filename);
+ }
+ break;
+ default:
+ {
+ error_info err = other_error;
+ throw interprocess_exception(err);
+ }
+ }
+
+ if(!m_handle || (type == detail::DoCreate && winapi::get_last_error() == winapi::error_already_exists)){
+ error_info err = system_error_code();
+ this->priv_close();
+ throw interprocess_exception(err);
+ }
+
+ m_mode = mode;
+ return true;
+}
+
+inline void windows_shared_memory::priv_close()
+{
+ if(m_handle){
+ winapi::close_handle(m_handle);
+ m_handle = 0;
+ }
+}
+
+///@endcond
+
+} //namespace interprocess {
+} //namespace boost {
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_WINDOWS_SHARED_MEMORY_HPP
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk