From 385370873058113c0d73feeaa46bcc32a3dc594e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 26 Nov 2007 16:34:13 +0000 Subject: [PATCH 01/77] Added missing #include [SVN r41400] --- test/named_creation_template.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/named_creation_template.hpp b/test/named_creation_template.hpp index ef6815f..2e28eb9 100644 --- a/test/named_creation_template.hpp +++ b/test/named_creation_template.hpp @@ -15,6 +15,7 @@ #include #include "boost_interprocess_check.hpp" #include +#include #include namespace boost { namespace interprocess { namespace test { From e8134c980c2ebbc13ffc1c45bc1dabca27270b6d Mon Sep 17 00:00:00 2001 From: Boris Gubenko Date: Wed, 28 Nov 2007 19:04:53 +0000 Subject: [PATCH 02/77] add "-lrt" for acc* toolsets [SVN r41439] --- test/Jamfile.v2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ab83520..8b3e8ec 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,8 @@ rule test_all : # additional args : # test-files : # requirements + acc:-lrt + acc-pa_risc:-lrt ] ; } From 9104031ec04678aed685981b81cd57285aa3f380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 1 Dec 2007 18:01:15 +0000 Subject: [PATCH 03/77] Simplified mutexes for systems with no _POSIX_TIMEOUTS. [SVN r41540] --- doc/html/reference.css | 8 + .../boost/interprocess/detail/workaround.hpp | 8 +- .../sync/emulation/interprocess_mutex.hpp | 4 +- .../interprocess/sync/interprocess_mutex.hpp | 8 +- .../sync/interprocess_recursive_mutex.hpp | 12 +- .../sync/posix/interprocess_mutex.hpp | 150 +++----------- .../posix/interprocess_recursive_mutex.hpp | 193 ++++-------------- proj/to-do.txt | 73 ------- proj/vc7ide/interprocesslib.vcproj | 4 - test/condition_test_template.hpp | 6 +- test/expand_bwd_test_template.hpp | 4 +- test/mutex_test_template.hpp | 28 +-- test/named_creation_template.hpp | 9 +- test/semaphore_test_template.hpp | 4 +- test/shared_memory_mapping_test.cpp | 2 +- 15 files changed, 113 insertions(+), 400 deletions(-) delete mode 100644 proj/to-do.txt diff --git a/doc/html/reference.css b/doc/html/reference.css index be4e64c..956d7da 100644 --- a/doc/html/reference.css +++ b/doc/html/reference.css @@ -1,3 +1,11 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + 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) +=============================================================================*/ PRE.synopsis { background-color: #e0ffff; border: thin solid blue; diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index a606231..cd31c8f 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -15,6 +15,8 @@ #if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) + #include + #if defined(_POSIX_THREAD_PROCESS_SHARED) # if !((_XOPEN_VERSION >= 600) && (_POSIX_THREAD_PROCESS_SHARED - 0 <= 0)) # if !defined(__CYGWIN__) @@ -88,6 +90,10 @@ #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) @@ -102,7 +108,7 @@ # endif #endif -#if defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || defined(BOOST_INTERPROCESS_VARIADIC_TEMPLATES) +#if defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && defined(BOOST_INTERPROCESS_VARIADIC_TEMPLATES) #define BOOST_INTERPROCESS_PERFECT_FORWARDING #endif diff --git a/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp index a7693d1..036cd04 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp @@ -54,9 +54,7 @@ inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_t if(now >= abs_time) return false; do{ - boost::uint32_t prev_s = detail::atomic_cas32((boost::uint32_t*)&m_s, 1, 0); - - if (m_s == 1 && prev_s == 0){ + if(this->try_lock()){ break; } now = microsec_clock::universal_time(); diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index cb6551c..ee375a8 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -109,13 +109,7 @@ class interprocess_mutex #if defined(BOOST_INTERPROCESS_USE_GENERIC_EMULATION) volatile boost::uint32_t m_s; #elif defined(BOOST_INTERPROCESS_USE_POSIX) - #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS - pthread_mutex_t m_mut; - #else - pthread_mutex_t m_mut; - pthread_cond_t m_cond; - bool m_locked; - #endif + pthread_mutex_t m_mut; #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index 060ec19..0c902b3 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -36,7 +36,7 @@ #include #include -#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED +#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED && defined BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES #include #include #include @@ -107,15 +107,7 @@ class interprocess_recursive_mutex unsigned int m_nLockCount; detail::OS_thread_id_t m_nOwner; #else //#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) - #if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined BOOST_INTERPROCESS_POSIX_TIMEOUTS - pthread_mutex_t m_mut; - #else //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined BOOST_INTERPROCESS_POSIX_TIMEOUTS - pthread_mutex_t m_mut; - pthread_cond_t m_unlocked; - pthread_t m_thread_id; - bool m_valid_id; - unsigned int m_count; - #endif //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined BOOST_INTERPROCESS_POSIX_TIMEOUTS + pthread_mutex_t m_mut; #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) /// @endcond }; diff --git a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp index b68f336..06b36b2 100644 --- a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp @@ -27,13 +27,13 @@ #include #include #include +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS +# include +#endif namespace boost { - namespace interprocess { -#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS - inline interprocess_mutex::interprocess_mutex() { detail::mutexattr_wrapper mut_attr; @@ -56,139 +56,51 @@ inline void interprocess_mutex::lock() inline bool interprocess_mutex::try_lock() { int res = pthread_mutex_trylock(&m_mut); - if (res == EDEADLK) throw lock_exception(); - assert(res == 0 || res == EBUSY); + if (!(res == 0 || res == EBUSY)) + throw lock_exception(); return res == 0; } inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) { + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + timespec ts = detail::ptime_to_timespec(abs_time); int res = pthread_mutex_timedlock(&m_mut, &ts); - if (res == EDEADLK || (res != 0 && res != ETIMEDOUT)) + 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); -// if (res == EPERM) throw lock_exception(); assert(res == 0); } -#else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS - -inline interprocess_mutex::interprocess_mutex() - : m_locked(false) -{ - //Mutex init - detail::mutexattr_wrapper mut_attr; - detail::mutex_initializer mut(m_mut, mut_attr); - - //Condition init - detail::condattr_wrapper cond_attr; - detail::condition_initializer cond(m_cond, cond_attr); - - mut.release(); - cond.release(); -} - -inline interprocess_mutex::~interprocess_mutex() -{ - assert(!m_locked); - int res = 0; - res = pthread_mutex_destroy(&m_mut); - assert(res == 0); - - res = pthread_cond_destroy(&m_cond); - assert(res == 0); -} - -inline void interprocess_mutex::lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - while (m_locked){ - res = pthread_cond_wait(&m_cond, &m_mut); - assert(res == 0); - } - - assert(!m_locked); - m_locked = true; - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); -} - -inline bool interprocess_mutex::try_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - bool ret = false; - if (!m_locked) - { - m_locked = true; - ret = true; - } - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); - return ret; -} - -inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_time) -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - timespec ts = detail::ptime_to_timespec(abs_time); - - while (m_locked) - { - res = pthread_cond_timedwait(&m_cond, &m_mut, &ts); - assert(res == 0 || res == ETIMEDOUT); - - if (res == ETIMEDOUT) - break; - } - - bool ret = false; - if (!m_locked) - { - m_locked = true; - ret = true; - } - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); - return ret; -} - -inline void interprocess_mutex::unlock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - assert(m_locked); - m_locked = false; - - res = pthread_cond_signal(&m_cond); - assert(res == 0); - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); -} - -#endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS - } //namespace interprocess { - } //namespace boost { diff --git a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp index 345ec63..be92550 100644 --- a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp @@ -27,12 +27,14 @@ #include #include #include +#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS +# include +#endif namespace boost { namespace interprocess { -#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined BOOST_INTERPROCESS_POSIX_TIMEOUTS inline interprocess_recursive_mutex::interprocess_recursive_mutex() { detail::mutexattr_wrapper mut_attr(true); @@ -48,179 +50,58 @@ inline interprocess_recursive_mutex::~interprocess_recursive_mutex() inline void interprocess_recursive_mutex::lock() { - int res = 0; - res = pthread_mutex_lock(&m_mut); - if (res == EDEADLK) throw lock_exception(); - assert(res == 0); + if (pthread_mutex_lock(&m_mut) != 0) + throw lock_exception(); } inline bool interprocess_recursive_mutex::try_lock() { - int res = 0; - res = pthread_mutex_trylock(&m_mut); - if (res == EDEADLK) throw lock_exception(); - assert(res == 0 || res == EBUSY); + 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) { + #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS + timespec ts = detail::ptime_to_timespec(abs_time); int res = pthread_mutex_timedlock(&m_mut, &ts); - if (res == EDEADLK) throw lock_exception(); - assert(res == 0 || res == EBUSY); - return res == 0; -} - -inline void interprocess_recursive_mutex::unlock() -{ - int res = 0; - res = pthread_mutex_unlock(&m_mut); - if (res == EPERM) throw lock_exception(); - assert(res == 0); -} - -#else //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined BOOST_INTERPROCESS_POSIX_TIMEOUTS - -inline interprocess_recursive_mutex::interprocess_recursive_mutex() - : m_valid_id(false), m_count(0) -{ - //Mutex init - detail::mutexattr_wrapper mut_attr; - detail::mutex_initializer mut(m_mut, mut_attr); - - //Condition init - detail::condattr_wrapper cond_attr; - detail::condition_initializer cond(m_unlocked, cond_attr); - - mut.release(); - cond.release(); -} - -inline interprocess_recursive_mutex::~interprocess_recursive_mutex() -{ - int res = 0; - res = pthread_mutex_destroy(&m_mut); - assert(res == 0); - - res = pthread_cond_destroy(&m_unlocked); - assert(res == 0); -} - -inline void interprocess_recursive_mutex::lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - if(res != 0){ - throw interprocess_exception(system_error_code()); - } - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)){ - ++m_count; - } - else{ - while (m_valid_id) - { - res = pthread_cond_wait(&m_unlocked, &m_mut); - assert(res == 0); - } - - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - } - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); -} - -inline bool interprocess_recursive_mutex::try_lock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)){ - ++m_count; - ret = true; - } - else if (!m_valid_id){ - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); - return ret; -} - -inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - bool ret = false; - pthread_t tid = pthread_self(); - if (m_valid_id && pthread_equal(m_thread_id, tid)){ - ++m_count; - ret = true; - } - else{ - timespec ts = detail::ptime_to_timespec(abs_time); - - while (m_valid_id){ - res = pthread_cond_timedwait(&m_unlocked, &m_mut, &ts); - if (res == ETIMEDOUT) - break; - assert(res == 0); - } - - if (!m_valid_id){ - m_thread_id = tid; - m_valid_id = true; - m_count = 1; - ret = true; - } - } - - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); - return ret; -} - -inline void interprocess_recursive_mutex::unlock() -{ - int res = 0; - res = pthread_mutex_lock(&m_mut); - assert(res == 0); - - pthread_t tid = pthread_self(); - if (m_valid_id && !pthread_equal(m_thread_id, tid)){ - res = pthread_mutex_unlock(&m_mut); - assert(res == 0); + if (res != 0 && res != ETIMEDOUT) throw lock_exception(); - } + return res == 0; - if (--m_count == 0){ - assert(m_valid_id); - m_valid_id = false; + #else //BOOST_INTERPROCESS_POSIX_TIMEOUTS - res = pthread_cond_signal(&m_unlocked); - assert(res == 0); - } + //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); } -#endif //#if (_POSIX_VERSION >= 200112L || _XOPEN_VERSION >= 500) && defined BOOST_INTERPROCESS_POSIX_TIMEOUTS - } //namespace interprocess { } //namespace boost { diff --git a/proj/to-do.txt b/proj/to-do.txt deleted file mode 100644 index c5ccc4e..0000000 --- a/proj/to-do.txt +++ /dev/null @@ -1,73 +0,0 @@ --> Implement zero_memory flag for allocation_command - --> Add explanations about system libraries (-lrt) or options (-pthread) to be added - to the command line. - --> The general allocation funtion can be improved with some fixed size allocation bins. - --> Update the documentation about memory algorithms with explanations about new functions. - --> Adapt error reporting to TR1 system exceptions - --> Improve exception messages - --> Movability of containers should depend on the no-throw guarantee of allocators copy constructor - --> Check self-assignment for vectors - --> Detect POD data in vector/deque to use memcpy and minimize code. - --> Update writing a new memory allocator explaining new functions (like alignment) - --> private node allocators could take the number of nodes as a runtime parameter. - --> Explain how to build intrusive indexes. - --> Add intrusive index types as available indexes. - --> Add maximum alignment allocation limit in PageSize bytes. Otherwise, we can't - guarantee alignment for process-shared allocations. - --> Add default algorithm and index types. The user does not need to know how are - they implemented. - --> Add private mapping to managed classes. - --> Add unique_ptr documentation. - --> Pass max size check in allocation to node pools - --> Add atomic_func explanation in docs - --> Once shrink to fit indexes is implemented test all memory has been deallocated - in tests to detect leaks/implementation failures. - --> Improve allocate_many functions to allocate all the nodes forming a singly - linked list of nodes. - --> rbtree_algorithms can be improved wrt the balanced tree. When erasing the old - node and inserting the new (expanded or shrunk) check if the position should - be the same. If so, avoid erase() + insert() and just update the size. - --> Use in-place expansion capabilities to shrink_to_fit and reserve functions - from iunordered_index. - --> Refactor pool allocators to extract common operations - --> Shrink in place interface is not adequate for with objects that don't have - a trivial destructor: how many destructors can we call before deallocating - the memory? Options: - 1. Call destructors in the low-level shrink function (but this might lead to - deadlock) - 2. Offer a function to know how much can we shrink (but destructor + shrinking - would not be atomic so we must guarantee that shrinking will succeed). - --> Optimize copy_n with std::copy in vector. Revise other functions to improve optimizations - --> Keep an eye on container iterator constness issue to bring Interprocess containers up-to-date. - --> change unique_ptr to avoid using compressed_pair - --> Improve unique_ptr test to test move assignment and other goodies like assigment from null - --> barrier_test fails on MacOS X on PowerPC. \ No newline at end of file diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 55937f0..8c0bd92 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -237,10 +237,6 @@ - - diff --git a/test/condition_test_template.hpp b/test/condition_test_template.hpp index 478e612..1ceb0cf 100644 --- a/test/condition_test_template.hpp +++ b/test/condition_test_template.hpp @@ -139,7 +139,7 @@ void condition_test_waits(condition_test_data* data) // Test timed_wait. while (data->notified != 3) - data->condition.timed_wait(lock, ptime_delay(10)); + data->condition.timed_wait(lock, ptime_delay(5)); assert(lock ? true : false); assert(data->notified == 3); data->awoken++; @@ -147,7 +147,7 @@ void condition_test_waits(condition_test_data* data) // Test predicate timed_wait. cond_predicate pred(data->notified, 4); - bool ret = data->condition.timed_wait(lock, ptime_delay(10), pred); + bool ret = data->condition.timed_wait(lock, ptime_delay(5), pred); assert(ret);(void)ret; assert(lock ? true : false); assert(pred()); @@ -177,7 +177,7 @@ void do_test_condition_notify_one() template void do_test_condition_notify_all() { - const int NUMTHREADS = 5; + const int NUMTHREADS = 3; boost::thread_group threads; condition_test_data data; diff --git a/test/expand_bwd_test_template.hpp b/test/expand_bwd_test_template.hpp index ff1dba0..4ccf0ca 100644 --- a/test/expand_bwd_test_template.hpp +++ b/test/expand_bwd_test_template.hpp @@ -76,7 +76,7 @@ typedef triple_value_holder triple_int_holder; //Function to check if both sets are equal template -static bool CheckEqualVector(const Vector1 &vector1, const Vector2 &vector2) +bool CheckEqualVector(const Vector1 &vector1, const Vector2 &vector2) { if(vector1.size() != vector2.size()) return false; @@ -84,7 +84,7 @@ static bool CheckEqualVector(const Vector1 &vector1, const Vector2 &vector2) } template -static bool CheckUninitializedIsZero(const Vector & v) +bool CheckUninitializedIsZero(const Vector & v) { typedef typename Vector::value_type value_type; typename Vector::size_type sz = v.size(); diff --git a/test/mutex_test_template.hpp b/test/mutex_test_template.hpp index 5c6d995..54c57d4 100644 --- a/test/mutex_test_template.hpp +++ b/test/mutex_test_template.hpp @@ -123,7 +123,7 @@ struct test_timedlock BOOST_INTERPROCES_CHECK(lock ? true : false); lock.unlock(); BOOST_INTERPROCES_CHECK(!lock); - boost::posix_time::ptime pt = delay(10*BaseSeconds, 0); + boost::posix_time::ptime pt = delay(3*BaseSeconds, 0); BOOST_INTERPROCES_CHECK(lock.timed_lock(pt)); BOOST_INTERPROCES_CHECK(lock ? true : false); } @@ -152,7 +152,7 @@ struct test_recursive_lock } { //This should always lock - boost::posix_time::ptime pt = delay(3*BaseSeconds); + boost::posix_time::ptime pt = delay(2*BaseSeconds); lock_type lock1(mx, pt); lock_type lock2(mx, pt); } @@ -171,7 +171,7 @@ void lock_and_sleep(void *arg, M &sm) boost::thread::sleep(xsecs(pdata->m_secs)); } else{ - boost::thread::sleep(xsecs(3*BaseSeconds)); + boost::thread::sleep(xsecs(2*BaseSeconds)); } ++shared_val; @@ -184,7 +184,7 @@ void try_lock_and_sleep(void *arg, M &sm) data *pdata = (data *) arg; boost::interprocess::scoped_lock l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ - boost::thread::sleep(xsecs(3*BaseSeconds)); + boost::thread::sleep(xsecs(2*BaseSeconds)); ++shared_val; pdata->m_value = shared_val; } @@ -198,7 +198,7 @@ void timed_lock_and_sleep(void *arg, M &sm) boost::interprocess::scoped_lock l (sm, boost::interprocess::defer_lock); if (l.timed_lock(pt)){ - boost::thread::sleep(xsecs(3*BaseSeconds)); + boost::thread::sleep(xsecs(2*BaseSeconds)); ++shared_val; pdata->m_value = shared_val; } @@ -223,13 +223,13 @@ void test_mutex_lock() data d1(1); data d2(2); - // Locker one launches, holds the lock for 3*BaseSeconds seconds. + // Locker one launches, holds the lock for 2*BaseSeconds seconds. boost::thread tm1(thread_adapter(&lock_and_sleep, &d1, *pm1)); //Wait 1*BaseSeconds boost::thread::sleep(xsecs(1*BaseSeconds)); - // Locker two launches, but it won't hold the lock for 3*BaseSeconds seconds. + // Locker two launches, but it won't hold the lock for 2*BaseSeconds seconds. boost::thread tm2(thread_adapter(&lock_and_sleep, &d2, *pm2)); //Wait completion @@ -259,7 +259,7 @@ void test_mutex_try_lock() data d1(1); data d2(2); - // Locker one launches, holds the lock for 3*BaseSeconds seconds. + // Locker one launches, holds the lock for 2*BaseSeconds seconds. boost::thread tm1(thread_adapter(&try_lock_and_sleep, &d1, *pm1)); //Wait 1*BaseSeconds @@ -293,16 +293,16 @@ void test_mutex_timed_lock() pm2 = &m2; } - data d1(1, 3*BaseSeconds); - data d2(2, 3*BaseSeconds); + data d1(1, 2*BaseSeconds); + data d2(2, 2*BaseSeconds); - // Locker one launches, holds the lock for 3*BaseSeconds seconds. + // Locker one launches, holds the lock for 2*BaseSeconds seconds. boost::thread tm1(thread_adapter(&timed_lock_and_sleep, &d1, *pm1)); //Wait 1*BaseSeconds boost::thread::sleep(xsecs(1*BaseSeconds)); - // Locker two launches, holds the lock for 3*BaseSeconds seconds. + // Locker two launches, holds the lock for 2*BaseSeconds seconds. boost::thread tm2(thread_adapter(&timed_lock_and_sleep, &d2, *pm2)); //Wait completion @@ -315,7 +315,7 @@ void test_mutex_timed_lock() } template -static inline void test_all_lock() +inline void test_all_lock() { //Now generic interprocess_mutex tests std::cout << "test_lock<" << typeid(M).name() << ">" << std::endl; @@ -327,7 +327,7 @@ static inline void test_all_lock() } template -static inline void test_all_recursive_lock() +inline void test_all_recursive_lock() { //Now generic interprocess_mutex tests std::cout << "test_recursive_lock<" << typeid(M).name() << ">" << std::endl; diff --git a/test/named_creation_template.hpp b/test/named_creation_template.hpp index 2e28eb9..4dd7637 100644 --- a/test/named_creation_template.hpp +++ b/test/named_creation_template.hpp @@ -15,13 +15,12 @@ #include #include "boost_interprocess_check.hpp" #include -#include #include namespace boost { namespace interprocess { namespace test { template -static inline void create_then_open_then_open_or_create() +inline void create_then_open_then_open_or_create() { try{ //Create it and open it twice @@ -36,7 +35,7 @@ static inline void create_then_open_then_open_or_create() } template -static inline void open_or_create_then_create() +inline void open_or_create_then_create() { //Create it with open_or_create and try to create it twice NamedResource nresource1(open_or_create); @@ -49,7 +48,7 @@ static inline void open_or_create_then_create() } template -static inline void dont_create_and_open() +inline void dont_create_and_open() { //Try to open it without creating try{ @@ -64,7 +63,7 @@ static inline void dont_create_and_open() } template -static inline void test_named_creation() +inline void test_named_creation() { std::cout << "create_then_open_then_open_or_create<" << typeid(NamedResource).name() << ">" << std::endl; diff --git a/test/semaphore_test_template.hpp b/test/semaphore_test_template.hpp index ee83a1a..23c235f 100644 --- a/test/semaphore_test_template.hpp +++ b/test/semaphore_test_template.hpp @@ -282,7 +282,7 @@ void test_mutex_timed_lock(P &sm) } template -static inline void test_all_lock() +inline void test_all_lock() { //Now generic interprocess_mutex tests std::cout << "test_wait<" << typeid(P).name() << ">" << std::endl; @@ -294,7 +294,7 @@ static inline void test_all_lock() } template -static inline void test_all_recursive_lock() +inline void test_all_recursive_lock() { //Now generic interprocess_mutex tests std::cout << "test_recursive_lock<" << typeid(P).name() << ">" << std::endl; diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 47ece77..723659c 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -69,7 +69,7 @@ int main () //Create a file mapping shared_memory_object mapping(open_only, test::get_process_id_name(), read_write); mapped_region region(mapping, read_write, 0, FileSize/2, 0); - mapped_region region2(mapping, read_write, FileSize/2, 0/*FileSize - FileSize/2*/, 0); + mapped_region region2(mapping, read_write, FileSize/2, FileSize - FileSize/2, 0); unsigned char *checker = (unsigned char*)region.get_address(); //Check pattern From 77dd13811f32c61bcaa3e3cd94a2af1337ff66c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 2 Dec 2007 09:25:53 +0000 Subject: [PATCH 04/77] Added missing #include overwritten by previous commit [SVN r41571] --- test/named_creation_template.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/named_creation_template.hpp b/test/named_creation_template.hpp index 4dd7637..0d5db18 100644 --- a/test/named_creation_template.hpp +++ b/test/named_creation_template.hpp @@ -15,6 +15,7 @@ #include #include "boost_interprocess_check.hpp" #include +#include #include namespace boost { namespace interprocess { namespace test { From dab43973e36dff2726fba28e083520d43c9e00b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 4 Dec 2007 22:05:28 +0000 Subject: [PATCH 05/77] Added Leopard workaround. _POSIX_THREAD_PROCESS_SHARED is defined but does not seem to work. For the moment, Mac OS will use emulation code [SVN r41704] --- include/boost/interprocess/detail/workaround.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index cd31c8f..6265d8d 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -19,7 +19,9 @@ #if defined(_POSIX_THREAD_PROCESS_SHARED) # if !((_XOPEN_VERSION >= 600) && (_POSIX_THREAD_PROCESS_SHARED - 0 <= 0)) - # if !defined(__CYGWIN__) + // Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not support it. + // Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but it does not seem to work + # if !defined(__CYGWIN__) && !defined(__APPLE__) # define BOOST_INTERPROCESS_POSIX_PROCESS_SHARED # endif # endif From 4bc132e96d8d7d3f2e1d9fe013600ac6a4d6278e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 28 Dec 2007 09:08:00 +0000 Subject: [PATCH 06/77] Ticket #1543: [interprocess] 'streamoff' : is not a member of 'std' http://svn.boost.org/trac/boost/ticket/1543 [SVN r42322] --- test/file_mapping_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index b9851c9..53182d1 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include From 715769871fc7b527a0a26a1227cee1cdbc8b2f82 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 7 Jan 2008 20:07:12 +0000 Subject: [PATCH 07/77] Use the default location for the reference documentation. [SVN r42581] --- doc/Jamfile.v2 | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9c864e4..c935497 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -27,7 +27,6 @@ doxygen autodoc EXTRACT_PRIVATE=NO EXPAND_ONLY_PREDEF=YES "boost.doxygen.reftitle=Boost.Interprocess Reference" - "boost.doxygen.refid=reference" ; xml interprocess : interprocess.qbk ; From 1a240759d3bb985ac111d006049dbb3a96ca26de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 20 Jan 2008 11:54:47 +0000 Subject: [PATCH 08/77] Updated Interprocess and Intrusive: -> Added linear slist to intrusive -> Updated all allocators to version 2 allocators in Interprocess -> Optimized rbtree_best_fit size overhead to 1 std:size_t. [SVN r42878] --- doc/Jamfile.v2 | 1 + doc/interprocess.qbk | 2 +- .../interprocess/allocators/adaptive_pool.hpp | 504 ++++++++---- .../allocators/allocation_type.hpp | 2 +- .../interprocess/allocators/allocator.hpp | 101 ++- .../allocators/cached_adaptive_pool.hpp | 515 ++++++------ .../allocators/cached_node_allocator.hpp | 470 +++++------ .../allocators/detail/adaptive_node_pool.hpp | 689 ++++++++-------- .../allocators/detail/allocator_common.hpp | 760 ++++++++++++++++++ .../allocators/detail/node_pool.hpp | 344 ++++---- .../allocators/detail/node_tools.hpp | 5 +- .../allocators/node_allocator.hpp | 513 +++++++----- .../allocators/private_adaptive_pool.hpp | 433 +++++++--- .../allocators/private_node_allocator.hpp | 456 ++++++++++- .../containers/detail/flat_tree.hpp | 2 +- .../containers/detail/node_alloc_holder.hpp | 46 +- .../interprocess/containers/detail/tree.hpp | 8 +- .../interprocess/containers/flat_map.hpp | 2 +- .../interprocess/containers/flat_set.hpp | 2 +- .../boost/interprocess/containers/list.hpp | 9 +- include/boost/interprocess/containers/map.hpp | 2 +- include/boost/interprocess/containers/set.hpp | 2 +- .../boost/interprocess/containers/slist.hpp | 4 +- .../boost/interprocess/containers/string.hpp | 4 +- .../boost/interprocess/containers/vector.hpp | 29 +- include/boost/interprocess/creation_tags.hpp | 2 +- .../boost/interprocess/detail/algorithms.hpp | 2 +- include/boost/interprocess/detail/atomic.hpp | 2 +- .../boost/interprocess/detail/cast_tags.hpp | 2 +- .../interprocess/detail/config_begin.hpp | 1 + .../detail/in_place_interface.hpp | 2 +- .../detail/interprocess_tester.hpp | 2 +- .../boost/interprocess/detail/iterators.hpp | 8 +- .../detail/managed_memory_impl.hpp | 2 +- .../interprocess/detail/math_functions.hpp | 2 +- include/boost/interprocess/detail/min_max.hpp | 2 +- include/boost/interprocess/detail/mpl.hpp | 2 +- .../boost/interprocess/detail/named_proxy.hpp | 2 +- .../interprocess/detail/os_file_functions.hpp | 2 +- .../detail/os_thread_functions.hpp | 2 +- .../interprocess/detail/pointer_type.hpp | 2 +- .../detail/posix_time_types_wrk.hpp | 2 +- .../detail/segment_manager_helper.hpp | 2 +- .../interprocess/detail/tmp_dir_helpers.hpp | 2 +- .../boost/interprocess/detail/type_traits.hpp | 2 +- .../boost/interprocess/detail/utilities.hpp | 147 +++- .../interprocess/detail/version_type.hpp | 2 +- .../boost/interprocess/detail/win32_api.hpp | 2 +- .../boost/interprocess/detail/workaround.hpp | 6 +- include/boost/interprocess/errors.hpp | 2 +- include/boost/interprocess/exceptions.hpp | 2 +- include/boost/interprocess/file_mapping.hpp | 2 +- .../interprocess/indexes/flat_map_index.hpp | 2 +- .../boost/interprocess/indexes/iset_index.hpp | 2 +- .../indexes/iunordered_set_index.hpp | 2 +- .../boost/interprocess/indexes/map_index.hpp | 2 +- .../boost/interprocess/indexes/null_index.hpp | 2 +- .../indexes/unordered_map_index.hpp | 2 +- .../boost/interprocess/interprocess_fwd.hpp | 18 +- .../boost/interprocess/ipc/message_queue.hpp | 2 +- .../interprocess/managed_external_buffer.hpp | 7 +- .../interprocess/managed_heap_memory.hpp | 2 +- .../interprocess/managed_mapped_file.hpp | 2 +- .../interprocess/managed_shared_memory.hpp | 2 +- .../managed_windows_shared_memory.hpp | 2 +- include/boost/interprocess/mapped_region.hpp | 2 +- .../mem_algo/detail/mem_algo_common.hpp | 214 ++++- .../mem_algo/detail/simple_seq_fit_impl.hpp | 60 +- .../interprocess/mem_algo/rbtree_best_fit.hpp | 609 ++++++++------ .../interprocess/mem_algo/simple_seq_fit.hpp | 2 +- include/boost/interprocess/offset_ptr.hpp | 6 +- .../boost/interprocess/segment_manager.hpp | 27 +- .../interprocess/shared_memory_object.hpp | 2 +- .../boost/interprocess/smart_ptr/deleter.hpp | 2 +- .../smart_ptr/detail/shared_count.hpp | 2 +- .../detail/sp_counted_base_atomic.hpp | 2 +- .../interprocess/smart_ptr/shared_ptr.hpp | 2 +- .../boost/interprocess/smart_ptr/weak_ptr.hpp | 2 +- .../interprocess/streams/bufferstream.hpp | 2 +- .../interprocess/streams/vectorstream.hpp | 2 +- .../sync/emulation/interprocess_condition.hpp | 2 +- .../sync/emulation/interprocess_mutex.hpp | 2 +- .../interprocess_recursive_mutex.hpp | 2 +- .../sync/emulation/interprocess_semaphore.hpp | 2 +- .../sync/emulation/named_creation_functor.hpp | 2 +- include/boost/interprocess/sync/file_lock.hpp | 2 +- .../sync/interprocess_barrier.hpp | 2 +- .../sync/interprocess_condition.hpp | 2 +- .../interprocess/sync/interprocess_mutex.hpp | 2 +- .../sync/interprocess_recursive_mutex.hpp | 2 +- .../sync/interprocess_semaphore.hpp | 2 +- .../sync/interprocess_upgradable_mutex.hpp | 2 +- .../boost/interprocess/sync/lock_options.hpp | 2 +- .../boost/interprocess/sync/mutex_family.hpp | 2 +- .../interprocess/sync/named_condition.hpp | 2 +- .../boost/interprocess/sync/named_mutex.hpp | 2 +- .../sync/named_recursive_mutex.hpp | 2 +- .../interprocess/sync/named_semaphore.hpp | 2 +- .../sync/named_upgradable_mutex.hpp | 2 +- .../boost/interprocess/sync/null_mutex.hpp | 2 +- .../sync/posix/interprocess_condition.hpp | 2 +- .../sync/posix/interprocess_mutex.hpp | 2 +- .../posix/interprocess_recursive_mutex.hpp | 2 +- .../sync/posix/interprocess_semaphore.hpp | 2 +- .../sync/posix/pthread_helpers.hpp | 2 +- .../sync/posix/ptime_to_timespec.hpp | 2 +- .../sync/posix/semaphore_wrapper.hpp | 2 +- .../boost/interprocess/sync/scoped_lock.hpp | 2 +- .../boost/interprocess/sync/sharable_lock.hpp | 2 +- .../interprocess/sync/upgradable_lock.hpp | 2 +- .../interprocess/windows_shared_memory.hpp | 2 +- proj/vc7ide/interprocesslib.vcproj | 6 + test/adaptive_node_pool_test.cpp | 2 +- test/adaptive_pool_test.cpp | 24 + test/cached_adaptive_pool_test.cpp | 24 + test/cached_node_allocator_test.cpp | 23 +- test/file_mapping_test.cpp | 1 - test/map_test.hpp | 2 + test/memory_algorithm_test.cpp | 94 ++- test/memory_algorithm_test_template.hpp | 110 ++- test/node_allocator_test.cpp | 19 +- test/node_pool_test.hpp | 8 +- test/private_adaptive_pool_test.cpp | 19 +- test/private_node_allocator_test.cpp | 21 +- test/set_test.hpp | 2 + test/vector_test.cpp | 237 +----- test/vector_test.hpp | 219 +++++ 127 files changed, 4675 insertions(+), 2294 deletions(-) create mode 100644 include/boost/interprocess/allocators/detail/allocator_common.hpp create mode 100644 test/vector_test.hpp diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index c935497..9cb17de 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -26,6 +26,7 @@ doxygen autodoc HIDE_UNDOC_MEMBERS=YES EXTRACT_PRIVATE=NO EXPAND_ONLY_PREDEF=YES + PREDEFINED=BOOST_INTERPROCESS_DOXYGEN_INVOKED "boost.doxygen.reftitle=Boost.Interprocess Reference" ; diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index e444b72..a05d77a 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -6418,7 +6418,7 @@ warranty. [classref boost::interprocess::named_mutex named_mutex]. * Reduced template bloat for node and adaptive allocators extracting node - implementation to a class taht only depends on the memory algorithm, instead of + implementation to a class that only depends on the memory algorithm, instead of the segment manager + node size + node number... * Fixed bug in `mapped_region` in UNIX when mapping address was provided but diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index f480651..0c00006 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,35 +36,38 @@ namespace boost { namespace interprocess { -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This node allocator shares a segregated storage between all instances -//!of adaptive_pool with equal sizeof(T) placed in the same segment -//!group. NodesPerChunk is the number of nodes allocated at once when the allocator -//!needs runs out of nodes. MaxFreeChunks is the number of free nodes -//!in the adaptive node pool that will trigger the deallocation of -template -class adaptive_pool +/// @cond + +namespace detail{ + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > +class adaptive_pool_base + : public node_pool_allocation_impl + < adaptive_pool_base + < Version, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> + , Version + , T + , SegmentManager + > { public: typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; typedef SegmentManager segment_manager; - typedef typename detail:: - pointer_to_other::type char_pointer; - typedef typename SegmentManager:: - mutex_family::mutex_type mutex_type; - typedef adaptive_pool - self_t; + typedef adaptive_pool_base + self_t; typedef detail::shared_adaptive_node_pool - < SegmentManager, mutex_type - , sizeof(T), NodesPerChunk, MaxFreeChunks> node_pool_t; + < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; typedef typename detail:: pointer_to_other::type node_pool_ptr; + BOOST_STATIC_ASSERT((Version <=2)); + public: //------- typedef typename detail:: @@ -78,52 +82,60 @@ class adaptive_pool typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - //!Obtains adaptive_pool from - //!adaptive_pool + typedef detail::version_type version; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; + + //!Obtains adaptive_pool_base from + //!adaptive_pool_base template struct rebind { - typedef adaptive_pool other; + typedef adaptive_pool_base other; }; /// @cond private: - //!Not assignable from related adaptive_pool - template - adaptive_pool& operator= - (const adaptive_pool&); + //!Not assignable from related adaptive_pool_base + template + adaptive_pool_base& operator= + (const adaptive_pool_base&); - //!Not assignable from other adaptive_pool - adaptive_pool& operator=(const adaptive_pool&); + //!Not assignable from other adaptive_pool_base + adaptive_pool_base& operator=(const adaptive_pool_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 - adaptive_pool(segment_manager *segment_mngr) - : mp_node_pool(priv_get_or_create(segment_mngr)) { } + adaptive_pool_base(segment_manager *segment_mngr) + : mp_node_pool(detail::get_or_create_node_pool(segment_mngr)) { } - //!Copy constructor from other adaptive_pool. Increments the reference + //!Copy constructor from other adaptive_pool_base. Increments the reference //!count of the associated node pool. Never throws - adaptive_pool(const adaptive_pool &other) + adaptive_pool_base(const adaptive_pool_base &other) : mp_node_pool(other.get_node_pool()) { mp_node_pool->inc_ref_count(); } - //!Copy constructor from related adaptive_pool. If not present, constructs + //!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 - adaptive_pool - (const adaptive_pool &other) - : mp_node_pool(priv_get_or_create(other.get_segment_manager())) { } + adaptive_pool_base + (const adaptive_pool_base &other) + : mp_node_pool(detail::get_or_create_node_pool(other.get_segment_manager())) { } //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws - ~adaptive_pool() - { priv_destroy_if_last_link(); } + ~adaptive_pool_base() + { detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool)); } //!Returns a pointer to the node pool. //!Never throws @@ -135,156 +147,300 @@ class adaptive_pool segment_manager* get_segment_manager()const { return mp_node_pool->get_segment_manager(); } - //!Returns the number of elements that could be allocated. - //!Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } - - //!Allocate memory for an array of count elements. - //!Throws boost::interprocess::bad_alloc if there is no enough memory*/ - pointer allocate(size_type count, cvoid_pointer = 0) - { - if(count > ((size_type)-1)/sizeof(value_type)) - throw bad_alloc(); - return pointer(static_cast(mp_node_pool->allocate(count))); - } - - //!Deallocate allocated memory. - //!Never throws - void deallocate(const pointer &ptr, size_type count) - { mp_node_pool->deallocate(detail::get_pointer(ptr), count); } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { mp_node_pool->deallocate_free_chunks(); } - //!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); } - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... - - //!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(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(); } - /// @cond - private: - //!Object function that creates the node allocator if it is not created and - //!increments reference count if it is already created - struct get_or_create_func - { - typedef detail::shared_adaptive_node_pool - node_pool_t; - - //!This connects or constructs the unique instance of node_pool_t - //!Can throw boost::interprocess::bad_alloc - void operator()() - { - //Find or create the node_pool_t - mp_node_pool = mp_named_alloc->template find_or_construct - (unique_instance)(mp_named_alloc); - //If valid, increment link count - if(mp_node_pool != 0) - mp_node_pool->inc_ref_count(); - } - - //!Constructor. Initializes function - //!object parameters - get_or_create_func(segment_manager *hdr) : mp_named_alloc(hdr){} - - node_pool_t *mp_node_pool; - segment_manager *mp_named_alloc; - }; - - //!Initialization function, creates an executes atomically the - //!initialization object functions. Can throw boost::interprocess::bad_alloc - node_pool_t *priv_get_or_create(segment_manager *named_alloc) - { - get_or_create_func func(named_alloc); - named_alloc->atomic_func(func); - return func.mp_node_pool; - } - - //!Object function that decrements the reference count. If the count - //!reaches to zero destroys the node allocator from memory. - //!Never throws - struct destroy_if_last_link_func - { - typedef detail::shared_adaptive_node_pool - node_pool_t; - - //!Decrements reference count and destroys the object if there is no - //!more attached allocators. Never throws - void operator()() - { - //If not the last link return - if(mp_node_pool->dec_ref_count() != 0) return; - - //Last link, let's destroy the segment_manager - mp_named_alloc->template destroy(unique_instance); - } - - //!Constructor. Initializes function - //!object parameters - destroy_if_last_link_func(segment_manager *nhdr, - node_pool_t *phdr) - : mp_named_alloc(nhdr), mp_node_pool(phdr){} - - segment_manager *mp_named_alloc; - node_pool_t *mp_node_pool; - }; - - //!Destruction function, initializes and executes destruction function - //!object. Never throws - void priv_destroy_if_last_link() - { - typedef detail::shared_adaptive_node_pool - node_pool_t; - //Get segment manager - segment_manager *named_segment_mngr = this->get_segment_manager(); - //Execute destruction functor atomically - destroy_if_last_link_func func(named_segment_mngr, detail::get_pointer(mp_node_pool)); - named_segment_mngr->atomic_func(func); - } - private: node_pool_ptr mp_node_pool; /// @endcond }; //!Equality test for same type -//!of adaptive_pool -template inline -bool operator==(const adaptive_pool &alloc1, - const adaptive_pool &alloc2) +//!of adaptive_pool_base +template inline +bool operator==(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type -//!of adaptive_pool -template inline -bool operator!=(const adaptive_pool &alloc1, - const adaptive_pool &alloc2) +//!of adaptive_pool_base +template inline +bool operator!=(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } +template < class T + , class SegmentManager + , std::size_t NodesPerChunk = 64 + , std::size_t MaxFreeChunks = 2 + , unsigned char OverheadPercent = 5 + > +class adaptive_pool_v1 + : public adaptive_pool_base + < 1 + , T + , SegmentManager + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > +{ + public: + typedef detail::adaptive_pool_base + < 1, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + + template + struct rebind + { + typedef adaptive_pool_v1 other; + }; + + adaptive_pool_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + adaptive_pool_v1 + (const adaptive_pool_v1 &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. NodesPerChunk is the number of nodes allocated at once when the allocator +//!needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks +//!that the adaptive node pool will hold. The rest of the totally free chunks 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 NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > +class adaptive_pool + /// @cond + : public detail::adaptive_pool_base + < 2 + , T + , SegmentManager + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef detail::adaptive_pool_base + < 2, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + public: + typedef detail::version_type version; + + template + struct rebind + { + typedef adaptive_pool other; + }; + + adaptive_pool(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + adaptive_pool + (const adaptive_pool &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 + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + //!Obtains adaptive_pool from + //!adaptive_pool + template + struct rebind + { + typedef adaptive_pool other; + }; + + private: + //!Not assignable from + //!related adaptive_pool + template + adaptive_pool& operator= + (const adaptive_pool&); + + //!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 + adaptive_pool + (const adaptive_pool &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 + 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 chunks + //!of the pool + void deallocate_free_chunks(); + + //!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); + + //!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 + 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 chunk + //!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_iterator 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 chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it); + + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator it); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of adaptive_pool +template inline +bool operator==(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); + +//!Inequality test for same type +//!of adaptive_pool +template inline +bool operator!=(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); + +#endif } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/allocators/allocation_type.hpp b/include/boost/interprocess/allocators/allocation_type.hpp index a24d789..1894d11 100644 --- a/include/boost/interprocess/allocators/allocation_type.hpp +++ b/include/boost/interprocess/allocators/allocation_type.hpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index e87b557..9d7ce2d 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -51,13 +51,6 @@ class allocator /// @cond private: - struct cast_functor - { - typedef typename detail::add_reference::type result_type; - result_type operator()(char &ptr) const - { return *static_cast(static_cast(&ptr)); } - }; - //Self type typedef allocator self_t; @@ -108,7 +101,9 @@ class allocator typedef transform_iterator < typename SegmentManager:: multiallocation_iterator - , cast_functor> multiallocation_iterator; + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; /// @endcond @@ -146,7 +141,7 @@ class allocator pointer allocate(size_type count, cvoid_ptr hint = 0) { (void)hint; - if(count > ((size_type)-1)/sizeof(T)) + if(count > this->max_size()) throw bad_alloc(); return pointer((value_type*)mp_mngr->allocate(count*sizeof(T))); } @@ -166,7 +161,13 @@ class allocator friend void swap(self_t &alloc1, self_t &alloc2) { detail::do_swap(alloc1.mp_mngr, alloc2.mp_mngr); } - //Experimental version 2 allocator functions + //!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 allocation_command(allocation_type command, @@ -178,42 +179,6 @@ class allocator (command, limit_size, preferred_size, received_size, detail::get_pointer(reuse)); } - //!Returns maximum the number of objects the previously allocated memory - //!pointed by p can hold. - size_type size(const pointer &p) const - { - return (size_type)mp_mngr->size(detail::get_pointer(p))/sizeof(T); - } - - //!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); } - - /// @cond - - //Experimental. Don't use. - - //!Allocates many elements of size == 1 in a contiguous chunk - //!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_iterator allocate_individual(std::size_t num_elements) - { return this->allocate_many(1, num_elements); } - - /// @endcond - - //!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); } - - /// @cond - //!Allocates many elements of size elem_size in a contiguous chunk //!of memory. The minimum number to be allocated is min_elements, //!the preferred and maximum number is @@ -235,10 +200,44 @@ class allocator (mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); } - /// @endcond + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it) + { return mp_mngr->deallocate_many(it.base()); } - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator it) + { return this->deallocate_many(it); } //!Returns address of mutable object. //!Never throws @@ -251,7 +250,7 @@ class allocator { return const_pointer(boost::addressof(value)); } //!Default construct an object. - //!Throws if T's default constructor throws*/ + //!Throws if T's default constructor throws void construct(const pointer &ptr) { new(detail::get_pointer(ptr)) value_type; } diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index 9930209..ec75948 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -19,56 +19,155 @@ #include #include -#include -#include -#include #include +#include #include -#include +#include #include -#include -#include #include //!\file -//!Describes cached_cached_node_allocator pooled shared memory STL compatible allocator +//!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 NodesPerChunk = 64 + , std::size_t MaxFreeChunks = 2 + , unsigned char OverheadPercent = 5 + > +class cached_adaptive_pool_v1 + : public detail::cached_allocator_impl + < T + , detail::shared_adaptive_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > + , 1> +{ + public: + typedef detail::cached_allocator_impl + < T + , detail::shared_adaptive_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > + , 1> base_t; + + template + struct rebind + { + typedef cached_adaptive_pool_v1 + 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 + cached_adaptive_pool_v1 + (const cached_adaptive_pool_v1 + &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 fixed size +//!cached_adaptive_pool with equal sizeof(T) placed in the same //!memory segment. But also caches some nodes privately to //!avoid some synchronization overhead. -template +//! +//!NodesPerChunk is the minimum number of nodes of nodes allocated at once when +//!the allocator needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks +//!that the adaptive node pool will hold. The rest of the totally free chunks 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 NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > class cached_adaptive_pool -{ /// @cond - typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; - typedef SegmentManager segment_manager; - typedef typename detail:: - pointer_to_other::type char_pointer; - typedef typename SegmentManager::mutex_family::mutex_type mutex_type; - typedef cached_adaptive_pool - self_t; - enum { DEFAULT_MAX_CACHED_NODES = 64 }; - - typedef typename detail::node_slist::node_t node_t; - typedef typename detail::node_slist::node_slist_t cached_list_t; + : public detail::cached_allocator_impl + < T + , detail::shared_adaptive_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > + , 2> /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef detail::cached_allocator_impl + < T + , detail::shared_adaptive_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > + , 2> base_t; public: - //------- - typedef typename detail:: - pointer_to_other::type pointer; - typedef typename detail:: - pointer_to_other::type const_pointer; + typedef detail::version_type version; + + template + struct rebind + { + typedef cached_adaptive_pool + 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 + cached_adaptive_pool + (const cached_adaptive_pool &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 ::type reference; @@ -76,312 +175,178 @@ class cached_adaptive_pool ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::shared_adaptive_node_pool - < SegmentManager, mutex_type - , sizeof(T), NodesPerChunk, MaxFreeChunks> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; - //!Obtains cached_adaptive_pool from other + //!Obtains cached_adaptive_pool from //!cached_adaptive_pool template struct rebind { - typedef cached_adaptive_pool other; + typedef cached_adaptive_pool other; }; - /// @cond private: - - //!Not assignable from related cached_adaptive_pool - template + //!Not assignable from + //!related cached_adaptive_pool + template cached_adaptive_pool& operator= - (const cached_adaptive_pool&); + (const cached_adaptive_pool&); - //!Not assignable from other cached_adaptive_pool + //!Not assignable from + //!other cached_adaptive_pool cached_adaptive_pool& operator=(const cached_adaptive_pool&); - /// @endcond - - public: - //!Constructor from a segment manager. If not present, constructs - //!a node pool. Increments the reference count of the node pool. - //!Can throw boost::interprocess::bad_alloc - cached_adaptive_pool(segment_manager *segment_mngr, - std::size_t max_cached_nodes = DEFAULT_MAX_CACHED_NODES) - : mp_node_pool(priv_get_or_create(segment_mngr)), - m_max_cached_nodes(max_cached_nodes) - {} - //!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) - : mp_node_pool(other.get_node_pool()), - m_max_cached_nodes(other.get_max_cached_nodes()) - { mp_node_pool->inc_ref_count(); } + 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 cached_adaptive_pool - (const cached_adaptive_pool &other) - : mp_node_pool(priv_get_or_create(other.get_segment_manager())), - m_max_cached_nodes(other.get_max_cached_nodes()) - { } + (const cached_adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws - ~cached_adaptive_pool() - { - priv_deallocate_all_cached_nodes(); - priv_destroy_if_last_link(); - } + ~cached_adaptive_pool(); //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const - { return detail::get_pointer(mp_node_pool); } + node_pool_t* get_node_pool() const; //!Returns the segment manager. //!Never throws - segment_manager* get_segment_manager()const - { return mp_node_pool->get_segment_manager(); } + segment_manager* get_segment_manager()const; - //!Sets the new max cached nodes value. This can provoke deallocations - //!if "newmax" is less than current cached nodes. Never throws - void set_max_cached_nodes(std::size_t newmax) - { - m_max_cached_nodes = newmax; - priv_deallocate_remaining_nodes(); - } - - //!Returns the max cached nodes parameter. + //!Returns the number of elements that could be allocated. //!Never throws - std::size_t get_max_cached_nodes() const - { return m_max_cached_nodes; } - - //!Returns the number of elements that could be - //!allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } + 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) - { - (void)hint; - if(count > ((size_type)-1)/sizeof(value_type)) - throw bad_alloc(); - typedef detail::shared_adaptive_node_pool - node_pool_t; - - void * ret; - - if(count == 1){ - //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()){ - mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes); - } - ret = &m_cached_nodes.front(); - m_cached_nodes.pop_front(); - } - else{ - ret = mp_node_pool->allocate(count); - } - return pointer(static_cast(ret)); - } + pointer allocate(size_type count, cvoid_pointer hint = 0); - //!Deallocate allocated memory. Never throws - void deallocate(const pointer &ptr, size_type count) - { - typedef detail::shared_adaptive_node_pool - node_pool_t; + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count); - if(count == 1){ - //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. - priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); - } - m_cached_nodes.push_front(*(node_t*)detail::char_ptr_cast(detail::get_pointer(ptr))); - } - else{ - mp_node_pool->deallocate(detail::get_pointer(ptr), count); - } - } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { mp_node_pool->deallocate_free_chunks(); } + //!Deallocates all free chunks + //!of the pool + void deallocate_free_chunks(); //!Swaps allocators. Does not throw. If each allocator is placed in a - //!different shared memory segments, the result is undefined. - friend void swap(self_t &alloc1, self_t &alloc2) - { - detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); - 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() - { this->priv_deallocate_all_cached_nodes(); } - - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... + //!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 - { return pointer(boost::addressof(value)); } + pointer address(reference value) const; //!Returns address of non mutable object. //!Never throws - const_pointer address(const_reference value) const - { return const_pointer(boost::addressof(value)); } + const_pointer address(const_reference value) const; //!Default construct an object. - //!Throws if T's default constructor throws*/ - void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + //!Throws if T's default constructor throws + void construct(const pointer &ptr); //!Destroys object. Throws if object's //!destructor throws - void destroy(const pointer &ptr) - { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + void destroy(const pointer &ptr); - /// @cond - private: + //!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; - //!Object function that creates the node allocator if it is not created and - //!increments reference count if it is already created - struct get_or_create_func - { - typedef detail::shared_adaptive_node_pool - node_pool_t; + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0); - //!This connects or constructs the unique instance of node_pool_t - //!Can throw boost::interprocess::bad_alloc - void operator()() - { - //Find or create the node_pool_t - mp_node_pool = mp_named_alloc->template find_or_construct - (unique_instance)(mp_named_alloc); - //If valid, increment link count - if(mp_node_pool != 0) - mp_node_pool->inc_ref_count(); - } + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator allocate_many(size_type elem_size, std::size_t num_elements); - //!Constructor. Initializes function - //!object parameters - get_or_create_func(segment_manager *hdr) : mp_named_alloc(hdr){} - - node_pool_t *mp_node_pool; - segment_manager *mp_named_alloc; - }; + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Frees all cached nodes. + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it); + + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator 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 - void priv_deallocate_all_cached_nodes() - { - if(m_cached_nodes.empty()) return; - mp_node_pool->deallocate_nodes(m_cached_nodes); - } - - //!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); - } - - //!Initialization function, creates an executes atomically the - //!initialization object functions. Can throw boost::interprocess::bad_alloc - node_pool_t *priv_get_or_create(segment_manager *named_alloc) - { - get_or_create_func func(named_alloc); - named_alloc->atomic_func(func); - return func.mp_node_pool; - } - - //!Object function that decrements the reference count. If the count - //!reaches to zero destroys the node allocator from memory. - //!Never throws - struct destroy_if_last_link_func - { - typedef detail::shared_adaptive_node_pool - node_pool_t; - - //!Decrements reference count and destroys the object if there is no - //!more attached allocators. Never throws - void operator()() - { - //If not the last link return - if(mp_node_pool->dec_ref_count() != 0) return; - - //Last link, let's destroy the segment_manager - mp_named_alloc->template destroy(unique_instance); - } - - //!Constructor. Initializes function - //!object parameters - destroy_if_last_link_func(segment_manager *nhdr, - node_pool_t *phdr) - : mp_named_alloc(nhdr), mp_node_pool(phdr){} - - segment_manager *mp_named_alloc; - node_pool_t *mp_node_pool; - }; - - //!Destruction function, initializes and executes destruction function - //!object. Never throws - void priv_destroy_if_last_link() - { - typedef detail::shared_adaptive_node_pool - node_pool_t; - //Get segment manager - segment_manager *segment_mngr = this->get_segment_manager(); - //Execute destruction functor atomically - destroy_if_last_link_func func(segment_mngr, detail::get_pointer(mp_node_pool)); - segment_mngr->atomic_func(func); - } - - private: - node_pool_ptr mp_node_pool; - cached_list_t m_cached_nodes; - std::size_t m_max_cached_nodes; - /// @endcond + std::size_t get_max_cached_nodes() const; + #endif }; -//!Equality test for same type of -//!cached_adaptive_pool -template inline -bool operator==(const cached_adaptive_pool &alloc1, - const cached_adaptive_pool &alloc2) - { return alloc1.get_node_pool() == alloc2.get_node_pool(); } +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED -//!Inequality test for same type of -//!cached_adaptive_pool -template inline -bool operator!=(const cached_adaptive_pool &alloc1, - const cached_adaptive_pool &alloc2) - { return alloc1.get_node_pool() != alloc2.get_node_pool(); } +//!Equality test for same type +//!of cached_adaptive_pool +template inline +bool operator==(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); + +//!Inequality test for same type +//!of cached_adaptive_pool +template inline +bool operator!=(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); + +#endif } //namespace interprocess { - } //namespace boost { + #include #endif //#ifndef BOOST_INTERPROCESS_CACHED_ADAPTIVE_POOL_HPP diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 2f7d1f4..4ee4767 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -19,14 +19,11 @@ #include #include -#include -#include -#include #include +#include #include -#include -#include -#include +#include +#include #include //!\file @@ -35,37 +32,113 @@ namespace boost { namespace interprocess { -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This node allocator shares a segregated storage between all instances of -//!cached_node_allocator with equal sizeof(T) placed in the same fixed size -//!memory segment. But also caches some nodes privately to -//!avoid some synchronization overhead. -template -class cached_node_allocator + +/// @cond + +namespace detail { + +template < class T + , class SegmentManager + , std::size_t NodesPerChunk = 64 + > +class cached_node_allocator_v1 + : public detail::cached_allocator_impl + < T + , detail::shared_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + > + , 1> { + public: + typedef detail::cached_allocator_impl + < T + , detail::shared_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + > + , 1> base_t; + + template + struct rebind + { + typedef cached_node_allocator_v1 + 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 + cached_node_allocator_v1 + (const cached_node_allocator_v1 + &other) + : base_t(other) + {} +}; + +} //namespace detail{ + +/// @endcond + +template < class T + , class SegmentManager + , std::size_t NodesPerChunk + > +class cached_node_allocator /// @cond - typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; - typedef SegmentManager segment_manager; - typedef typename detail:: - pointer_to_other::type char_pointer; - typedef typename SegmentManager::mutex_family::mutex_type mutex_type; - typedef cached_node_allocator self_t; - enum { DEFAULT_MAX_CACHED_NODES = 64 }; - typedef typename detail::node_slist::node_t node_t; - typedef typename detail::node_slist::node_slist_t cached_list_t; + : public detail::cached_allocator_impl + < T + , detail::shared_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + > + , 2> /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + public: + typedef detail::cached_allocator_impl + < T + , detail::shared_node_pool + < SegmentManager + , sizeof(T) + , NodesPerChunk + > + , 2> base_t; public: - //------- - typedef typename detail:: - pointer_to_other::type pointer; - typedef typename detail:: - pointer_to_other::type const_pointer; + typedef detail::version_type version; + + template + struct rebind + { + typedef cached_node_allocator 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 + cached_node_allocator + (const cached_node_allocator &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 ::type reference; @@ -73,302 +146,173 @@ class cached_node_allocator ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::shared_node_pool - < SegmentManager, mutex_type - , sizeof(T), NodesPerChunk> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; - //!Obtains cached_node_allocator from other cached_node_allocator + //!Obtains cached_node_allocator from + //!cached_node_allocator template struct rebind { - typedef cached_node_allocator other; + typedef cached_node_allocator other; }; - /// @cond private: - - //!Not assignable from related cached_node_allocator + //!Not assignable from + //!related cached_node_allocator template cached_node_allocator& operator= (const cached_node_allocator&); - //!Not assignable from other cached_node_allocator + //!Not assignable from + //!other cached_node_allocator cached_node_allocator& operator=(const cached_node_allocator&); - /// @endcond public: - //!Constructor from a segment manager. If not present, constructs - //!a node pool. Increments the reference count of the node pool. + //!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, - std::size_t max_cached_nodes = DEFAULT_MAX_CACHED_NODES) - : mp_node_pool(priv_get_or_create(segment_mngr)), - m_max_cached_nodes(max_cached_nodes) - {} + 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) - : mp_node_pool(other.get_node_pool()), - m_max_cached_nodes(other.get_max_cached_nodes()) - { mp_node_pool->inc_ref_count(); } + //!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 cached_node_allocator - (const cached_node_allocator &other) - : mp_node_pool(priv_get_or_create(other.get_segment_manager())), - m_max_cached_nodes(other.get_max_cached_nodes()) - { } + (const cached_node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws - ~cached_node_allocator() - { - priv_deallocate_all_cached_nodes(); - priv_destroy_if_last_link(); - } + ~cached_node_allocator(); //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const - { return detail::get_pointer(mp_node_pool); } + node_pool_t* get_node_pool() const; //!Returns the segment manager. //!Never throws - segment_manager* get_segment_manager()const - { return mp_node_pool->get_segment_manager(); } + segment_manager* get_segment_manager()const; - //!Sets the new max cached nodes value. This can provoke deallocations - //!if "newmax" is less than current cached nodes. Never throws - void set_max_cached_nodes(std::size_t newmax) - { - m_max_cached_nodes = newmax; - priv_deallocate_remaining_nodes(); - } - - //!Returns the max cached nodes parameter. + //!Returns the number of elements that could be allocated. //!Never throws - std::size_t get_max_cached_nodes() const - { return m_max_cached_nodes; } - - //!Returns the number of elements that could be allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } + 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) - { - (void)hint; - if(count > ((size_type)-1)/sizeof(value_type)) - throw bad_alloc(); - typedef detail::shared_node_pool - node_pool_t; - - void * ret; - - if(count == 1){ - //If don't have any cached node, we have to get a new list of free nodes from the pool - if(m_cached_nodes.empty()){ - mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes); - } - ret = &m_cached_nodes.front(); - m_cached_nodes.pop_front(); - } - else{ - ret = mp_node_pool->allocate(count); - } - return pointer(static_cast(ret)); - } + pointer allocate(size_type count, cvoid_pointer hint = 0); //!Deallocate allocated memory. //!Never throws - void deallocate(const pointer &ptr, size_type count) - { - typedef detail::shared_node_pool - node_pool_t; + void deallocate(const pointer &ptr, size_type count); - if(count == 1){ - //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. - priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2); - } - m_cached_nodes.push_front(*(node_t*)detail::char_ptr_cast(detail::get_pointer(ptr))); - } - else{ - mp_node_pool->deallocate(detail::get_pointer(ptr), count); - } - } + //!Deallocates all free chunks + //!of the pool + void deallocate_free_chunks(); //!Swaps allocators. Does not throw. If each allocator is placed in a - //!different shared memory segments, the result is undefined. - friend void swap(self_t &alloc1, self_t &alloc2) - { - detail::do_swap(alloc1.mp_node_pool, alloc2.mp_node_pool); - alloc1.m_cached_nodes.swap(alloc2.m_cached_nodes); - detail::do_swap(alloc1.m_max_cached_nodes, alloc2.m_max_cached_nodes); - } - - //!Returns the cached nodes to the shared pool - void deallocate_cache() - { this->priv_deallocate_all_cached_nodes(); } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { mp_node_pool->deallocate_free_chunks(); } - - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... + //!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 - { return pointer(boost::addressof(value)); } + pointer address(reference value) const; //!Returns address of non mutable object. //!Never throws - const_pointer address(const_reference value) const - { return const_pointer(boost::addressof(value)); } + const_pointer address(const_reference value) const; //!Default construct an object. - //!Throws if T's default constructor throws*/ - void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + //!Throws if T's default constructor throws + void construct(const pointer &ptr); //!Destroys object. Throws if object's //!destructor throws - void destroy(const pointer &ptr) - { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + void destroy(const pointer &ptr); - /// @cond - private: + //!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; - //!Object function that creates the node allocator if it is not created and - //!increments reference count if it is already created - struct get_or_create_func - { - typedef detail::shared_node_pool - node_pool_t; + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0); - //!This connects or constructs the unique instance of node_pool_t - //!Can throw boost::interprocess::bad_alloc - void operator()() - { - //Find or create the node_pool_t - mp_node_pool = mp_named_alloc->template find_or_construct - (unique_instance)(mp_named_alloc); - //If valid, increment link count - if(mp_node_pool != 0) - mp_node_pool->inc_ref_count(); - } + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator allocate_many(size_type elem_size, std::size_t num_elements); - //!Constructor. Initializes function - //!object parameters - get_or_create_func(segment_manager *hdr) : mp_named_alloc(hdr){} - - node_pool_t *mp_node_pool; - segment_manager *mp_named_alloc; - }; + //!Allocates n_elements elements, each one of size elem_sizes[i]in a + //!contiguous chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Frees all cached nodes. + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it); + + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator 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 - void priv_deallocate_all_cached_nodes() - { mp_node_pool->deallocate_nodes(m_cached_nodes); } - - //!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) - { mp_node_pool->deallocate_nodes(m_cached_nodes, n); } - - //!Initialization function, creates an executes atomically the - //!initialization object functions. Can throw boost::interprocess::bad_alloc - node_pool_t *priv_get_or_create(segment_manager *named_alloc) - { - get_or_create_func func(named_alloc); - named_alloc->atomic_func(func); - return func.mp_node_pool; - } - - //!Object function that decrements the reference count. If the count - //!reaches to zero destroys the node allocator from memory. - //!Never throws - struct destroy_if_last_link_func - { - typedef detail::shared_node_pool - node_pool_t; - - //!Decrements reference count and destroys the object if there is no - //!more attached allocators. Never throws - void operator()() - { - //If not the last link return - if(mp_node_pool->dec_ref_count() != 0) return; - - //Last link, let's destroy the segment_manager - mp_named_alloc->template destroy(unique_instance); - } - - //!Constructor. Initializes function object - //!parameters - destroy_if_last_link_func(segment_manager *nhdr, - node_pool_t *phdr) - : mp_named_alloc(nhdr), mp_node_pool(phdr){} - - segment_manager *mp_named_alloc; - node_pool_t *mp_node_pool; - }; - - //!Destruction function, initializes and executes destruction function - //!object. Never throws - void priv_destroy_if_last_link() - { - typedef detail::shared_node_pool - node_pool_t; - //Get segment manager - segment_manager *segment_mngr = this->get_segment_manager(); - //Execute destruction functor atomically - destroy_if_last_link_func func(segment_mngr, detail::get_pointer(mp_node_pool)); - segment_mngr->atomic_func(func); - } - - private: - node_pool_ptr mp_node_pool; - cached_list_t m_cached_nodes; - std::size_t m_max_cached_nodes; - /// @endcond + std::size_t get_max_cached_nodes() const; + #endif }; -//!Equality test for same type of -//!cached_node_allocator +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of cached_node_allocator template inline bool operator==(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2) - { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + const cached_node_allocator &alloc2); -//!Inequality test for same type of -//!cached_node_allocator +//!Inequality test for same type +//!of cached_node_allocator template inline bool operator!=(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2) - { return alloc1.get_node_pool() != alloc2.get_node_pool(); } + const cached_node_allocator &alloc2); + +#endif } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index b9280f3..02dca7a 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -17,20 +17,21 @@ #include #include +#include #include #include #include #include #include -#include +#include #include #include #include #include +#include #include #include #include -#include //!\file //!Describes the real adaptive pool shared by many Interprocess pool allocators @@ -39,10 +40,6 @@ namespace boost { namespace interprocess { namespace detail { -//!Pooled shared memory allocator using an smart 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 chunk (NodesPerChunk) are known at compile time. template class private_adaptive_node_pool_impl { @@ -56,19 +53,85 @@ class private_adaptive_node_pool_impl public: typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; + typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; + typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: - //This hook will be used to chain the memory chunks - typedef typename bi::make_list_base_hook - , bi::link_mode >::type list_hook_t; + typedef typename bi::make_set_base_hook + < bi::void_pointer + , bi::optimize_size + , bi::constant_time_size + , bi::link_mode >::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 chunk_info_t - : public list_hook_t + : + public hdr_offset_holder, + public multiset_hook_t { //An intrusive list of free node from this chunk free_nodes_t free_nodes; + friend bool operator <(const chunk_info_t &l, const chunk_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 chunks 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_list >::type chunk_list_t; + typedef typename bi::make_multiset + >::type chunk_multiset_t; + typedef typename chunk_multiset_t::iterator chunk_iterator; + + static const std::size_t MaxAlign = alignment_of::value; + static const std::size_t HdrSize = ((sizeof(chunk_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_subchunk = (dividend - 1)/divisor + 1; + std::size_t candidate_power_of_2 = + upper_power_of_2(elements_per_subchunk*real_node_size + HdrOffsetSize); + bool overhead_satisfied = false; + while(!overhead_satisfied){ + elements_per_subchunk = (candidate_power_of_2 - HdrOffsetSize)/real_node_size; + std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*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_subchunks + (std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_chunk + ,std::size_t &num_subchunks, std::size_t &real_num_node) + { + std::size_t elements_per_subchunk = (alignment - HdrOffsetSize)/real_node_size; + std::size_t possible_num_subchunk = (elements_per_chunk - 1)/elements_per_subchunk + 1; + std::size_t hdr_subchunk_elements = (alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/real_node_size; + while(((possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements) < elements_per_chunk){ + ++possible_num_subchunk; + } + num_subchunks = possible_num_subchunk; + real_num_node = (possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements; + } public: //!Segment manager typedef @@ -77,26 +140,25 @@ class private_adaptive_node_pool_impl //!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_chunk, std::size_t max_free_chunks) - : m_node_size(node_size) - , m_max_free_chunks(max_free_chunks) - , m_real_node_size(lcm(m_node_size, sizeof(node_t))) - , m_header_size(min_value(get_rounded_size(sizeof(chunk_info_t), alignment_of::value) - ,get_rounded_size(sizeof(chunk_info_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 - , m_real_chunk_alignment(upper_power_of_2(m_header_size + m_real_node_size*nodes_per_chunk)) + , std::size_t nodes_per_chunk, std::size_t max_free_chunks + , unsigned char overhead_percent + ) + : m_max_free_chunks(max_free_chunks) + , m_real_node_size(lcm(node_size, std::size_t(alignment_of::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_chunk_alignment(calculate_alignment(overhead_percent, m_real_node_size)) //This is the real number of nodes per chunk - , m_real_num_node((m_real_chunk_alignment - SegmentManagerBase::PayloadPerAllocation - m_header_size)/m_real_node_size) + , m_num_subchunks(0) + , m_real_num_node(0) //General purpose allocator , mp_segment_mngr_base(segment_mngr_base) - , m_chunklist() - , m_first_free_chunk(m_chunklist.end()) - //Debug node count - , m_allocated(0) - , m_free_chunks(0) - {} + , m_chunk_multiset() + , m_totally_free_chunks(0) + { + calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node); + } //!Destructor. Deallocates all allocated chunks. Never throws ~private_adaptive_node_pool_impl() @@ -110,60 +172,118 @@ class private_adaptive_node_pool_impl { return detail::get_pointer(mp_segment_mngr_base); } //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc - void *allocate(std::size_t count) + void *allocate_node() { - std::size_t bytes = count*m_node_size; - if(bytes > m_real_node_size){//Normal allocation, no pooling used - void *addr = mp_segment_mngr_base->allocate(bytes); - if(!addr) throw bad_alloc(); - return addr; + priv_invariants(); + //If there are no free nodes we allocate a new block + if (m_chunk_multiset.empty()){ + priv_alloc_chunk(1); } - else //Node allocation, pooling used - return priv_alloc_node(); + //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(void *ptr, std::size_t count) + void deallocate_node(void *pElem) { - std::size_t bytes = count*m_node_size; - if(bytes > m_real_node_size)//Normal allocation was used - mp_segment_mngr_base->deallocate(ptr); - else //Node allocation was used - priv_dealloc_node(ptr); + priv_invariants(); + chunk_info_t *chunk_info = priv_chunk_from_node(pElem); + assert(chunk_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(pElem); + chunk_info->free_nodes.push_front(*to_deallocate); + + chunk_iterator this_chunk(chunk_multiset_t::s_iterator_to(*chunk_info)); + chunk_iterator next_chunk(this_chunk); + ++next_chunk; + + //Cache the free nodes from the chunk + std::size_t this_chunk_free_nodes = this_chunk->free_nodes.size(); + + if(this_chunk_free_nodes == 1){ + m_chunk_multiset.insert(m_chunk_multiset.begin(), *chunk_info); + } + else{ + chunk_iterator next_chunk(this_chunk); + ++next_chunk; + if(next_chunk != m_chunk_multiset.end()){ + std::size_t next_free_nodes = next_chunk->free_nodes.size(); + if(this_chunk_free_nodes > next_free_nodes){ + //Now move the chunk to the new position + m_chunk_multiset.erase(this_chunk); + m_chunk_multiset.insert(*chunk_info); + } + } + } + //Update free chunk count + if(this_chunk_free_nodes == m_real_num_node){ + ++m_totally_free_chunks; + priv_deallocate_free_chunks(m_max_free_chunks); + } + priv_invariants(); } //!Allocates a singly linked list of n nodes ending in null pointer. //!can throw boost::interprocess::bad_alloc - void allocate_nodes(const std::size_t n, free_nodes_t &nodes) + void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) { - std::size_t i = 0; + std::size_t old_node_count = nodes.size(); try{ - for(; i < n; ++i){ - nodes.push_front(*priv_alloc_node()); + priv_invariants(); + for(std::size_t i = 0; i != n; ++i){ + //If there are no free nodes we allocate all needed chunks + if (m_chunk_multiset.empty()){ + priv_alloc_chunk(((n - i) - 1)/m_real_num_node + 1); + } + nodes.push_front(priv_take_first_node()); } } catch(...){ - priv_deallocate_nodes(nodes, i); + priv_deallocate_nodes(nodes, nodes.size()); + priv_deallocate_free_chunks(m_max_free_chunks); throw; } + //remove me + assert((n+old_node_count) == (std::size_t)std::distance(nodes.get_it(), multiallocation_iterator())); + priv_invariants(); + } + + //!Allocates n nodes, pointed by the multiallocation_iterator. + //!Can throw boost::interprocess::bad_alloc + multiallocation_iterator allocate_nodes(const std::size_t n) + { + multiallocation_chain chain; + this->allocate_nodes(chain, n); + return chain.get_it(); } //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(free_nodes_t &nodes) + void deallocate_nodes(multiallocation_chain &nodes) { priv_deallocate_nodes(nodes, nodes.size()); } //!Deallocates the first n nodes of a linked list of nodes. Never throws - void deallocate_nodes(free_nodes_t &nodes, std::size_t n) + void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) { priv_deallocate_nodes(nodes, n); } + //!Deallocates the nodes pointed by the multiallocation iterator. Never throws + void deallocate_nodes(multiallocation_iterator it) + { + multiallocation_iterator itend; + while(it != itend){ + void *addr = &*it; + ++it; + deallocate_node(addr); + } + } + void deallocate_free_chunks() { priv_deallocate_free_chunks(0); } std::size_t num_free_nodes() { - typedef typename chunk_list_t::const_iterator citerator; + typedef typename chunk_multiset_t::const_iterator citerator; std::size_t count = 0; - citerator it (m_first_free_chunk), itend(m_chunklist.end()); + citerator it (m_chunk_multiset.begin()), itend(m_chunk_multiset.end()); for(; it != itend; ++it){ count += it->free_nodes.size(); } @@ -172,22 +292,40 @@ class private_adaptive_node_pool_impl void swap(private_adaptive_node_pool_impl &other) { + assert(m_max_free_chunks == other.m_max_free_chunks); + assert(m_real_node_size == other.m_real_node_size); + assert(m_real_chunk_alignment == other.m_real_chunk_alignment); + assert(m_real_num_node == other.m_real_num_node); std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); - m_chunklist.swap(other.m_chunklist); - std::swap(m_first_free_chunk, other.m_first_free_chunk); - std::swap(m_allocated, other.m_allocated); - std::swap(m_free_chunks, other.m_allocated); + std::swap(m_totally_free_chunks, other.m_totally_free_chunks); + m_chunk_multiset.swap(other.m_chunk_multiset); } private: + node_t *priv_take_first_node() + { + assert(m_chunk_multiset.begin() != m_chunk_multiset.end()); + //We take the first free node the multiset can't be empty + free_nodes_t &free_nodes = m_chunk_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_chunk_multiset.erase(m_chunk_multiset.begin()); + } + else if(free_nodes_count == m_real_num_node){ + --m_totally_free_chunks; + } + priv_invariants(); + return first_node; + } - void priv_deallocate_nodes(free_nodes_t &nodes, const std::size_t num) + void priv_deallocate_nodes(multiallocation_chain &nodes, const std::size_t num) { assert(nodes.size() >= num); for(std::size_t i = 0; i < num; ++i){ - node_t *to_deallocate = &nodes.front(); - nodes.pop_front(); - deallocate(to_deallocate, 1); + deallocate_node(nodes.pop_front()); } } @@ -197,71 +335,75 @@ class private_adaptive_node_pool_impl class chunk_destroyer { public: - chunk_destroyer(segment_manager_base_type *mngr, std::size_t real_num_node) - : mngr_(mngr), m_real_num_node(real_num_node) + chunk_destroyer(const private_adaptive_node_pool_impl *impl) + : mp_impl(impl) {} - void operator()(typename chunk_list_t::pointer to_deallocate) + void operator()(typename chunk_multiset_t::pointer to_deallocate) { std::size_t free_nodes = to_deallocate->free_nodes.size(); (void)free_nodes; - assert(free_nodes == m_real_num_node); - mngr_->deallocate(detail::get_pointer(to_deallocate)); + 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_subchunk_from_chunk((chunk_info_t*)detail::get_pointer(to_deallocate)); + mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder); } - segment_manager_base_type *mngr_; - const std::size_t m_real_num_node; + 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 + #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 { - typedef typename chunk_list_t::iterator chunk_iterator; - //We iterate though the chunk list to free the memory - chunk_iterator it(m_chunklist.begin()), - itend(m_chunklist.end()), to_deallocate; - for(++it; it != itend; ++it){ - chunk_iterator prev(it); - --prev; - std::size_t sp = prev->free_nodes.size(), - si = it->free_nodes.size(); - assert(sp <= si); - (void)sp; (void)si; + //We iterate through the chunk list to free the memory + chunk_iterator it(m_chunk_multiset.begin()), + itend(m_chunk_multiset.end()), to_deallocate; + if(it != itend){ + for(++it; it != itend; ++it){ + chunk_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_chunklist.begin(); - itend = m_chunklist.end(); - std::size_t total_free = 0; - for(; it != itend; ++it){ - total_free += it->free_nodes.size(); - } - assert(total_free >= m_free_chunks*m_real_num_node); - - //Check that the total totally free chunks are correct - it = m_chunklist.begin(); - itend = m_chunklist.end(); - total_free = 0; - for(; it != itend; ++it){ - total_free += it->free_nodes.size() == m_real_num_node; - } - assert(total_free >= m_free_chunks); - - //The chunk pointed by m_first_free_chunk should point - //to end or to a non-empty chunk - if(m_first_free_chunk != m_chunklist.end()){ - std::size_t s = m_first_free_chunk->free_nodes.size(); - assert(s != 0); + { + //Check that the total free nodes are correct + it = m_chunk_multiset.begin(); + itend = m_chunk_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_chunks*m_real_num_node); } - //All previous nodes of m_first_free_chunk should be 0 - it = m_chunklist.begin(); - itend = m_first_free_chunk; + { + //Check that the total totally free chunks are correct + it = m_chunk_multiset.begin(); + itend = m_chunk_multiset.end(); + std::size_t total_free_chunks = 0; + for(; it != itend; ++it){ + total_free_chunks += (it->free_nodes.size() == m_real_num_node); + } + assert(total_free_chunks == m_totally_free_chunks); + } + { + //Check that header offsets are correct + it = m_chunk_multiset.begin(); for(; it != itend; ++it){ - std::size_t s = it->free_nodes.size(); - assert(s == 0); + hdr_offset_holder *hdr_off_holder = priv_first_subchunk_from_chunk(&*it); + for(std::size_t i = 0, max = m_num_subchunks; i < max; ++i){ + assert(hdr_off_holder->hdr_offset == std::size_t((char*)&*it- (char*)hdr_off_holder)); + assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); + assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); + hdr_off_holder = (hdr_offset_holder *)((char*)hdr_off_holder + m_real_chunk_alignment); + } + } } } #else @@ -271,165 +413,136 @@ class private_adaptive_node_pool_impl //!Deallocates all used memory. Never throws void priv_clear() { - //Check for memory leaks - assert(m_allocated==0); + #ifndef NDEBUG + chunk_iterator it = m_chunk_multiset.begin(); + chunk_iterator itend = m_chunk_multiset.end(); + std::size_t num_free_nodes = 0; + for(; it != itend; ++it){ + //Check for memory leak + assert(it->free_nodes.size() == m_real_num_node); + ++num_free_nodes; + } + assert(num_free_nodes == m_totally_free_chunks); + #endif priv_invariants(); - m_first_free_chunk = m_chunklist.end(); - m_chunklist.clear_and_dispose - (chunk_destroyer(detail::get_pointer(mp_segment_mngr_base), m_real_num_node)); - m_free_chunks = 0; + m_chunk_multiset.clear_and_dispose + (chunk_destroyer(this)); + m_totally_free_chunks = 0; } - chunk_info_t *priv_chunk_from_node(void *node) + chunk_info_t *priv_chunk_from_node(void *node) const { - return (chunk_info_t *)((std::size_t)node & std::size_t(~(m_real_chunk_alignment - 1))); + hdr_offset_holder *hdr_off_holder = + (hdr_offset_holder*)((std::size_t)node & std::size_t(~(m_real_chunk_alignment - 1))); + assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); + assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); + chunk_info_t *chunk = (chunk_info_t *)(((char*)hdr_off_holder) + hdr_off_holder->hdr_offset); + assert(chunk->hdr_offset == 0); + return chunk; } - //!Allocates one node, using the adaptive pool algorithm. - //!Never throws - node_t *priv_alloc_node() + hdr_offset_holder *priv_first_subchunk_from_chunk(chunk_info_t *chunk) const { - priv_invariants(); - //If there are no free nodes we allocate a new block - if (m_first_free_chunk == m_chunklist.end()){ - priv_alloc_chunk(); - --m_first_free_chunk; - } - //We take the first free node since m_first_free_chunk can't be end() - chunk_info_t &chunk_info = *m_first_free_chunk; - assert(!chunk_info.free_nodes.empty()); - node_t *first_node = &chunk_info.free_nodes.front(); - if(chunk_info.free_nodes.size() == 1){ - ++m_first_free_chunk; - } - else if(chunk_info.free_nodes.size() == m_real_num_node){ - --m_free_chunks; - } - chunk_info.free_nodes.pop_front(); - ++m_allocated; - priv_invariants(); - return detail::get_pointer(first_node); - } - - //!Deallocates one node, using the adaptive pool algorithm. - //!Never throws - void priv_dealloc_node(void *pElem) - { - typedef typename chunk_list_t::iterator chunk_iterator; - priv_invariants(); - chunk_info_t *chunk_info = priv_chunk_from_node(pElem); - assert(chunk_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(pElem); - chunk_info->free_nodes.push_front(*to_deallocate); - chunk_iterator this_chunk(chunk_list_t::s_iterator_to(*chunk_info)); - chunk_iterator next_chunk(this_chunk); - ++next_chunk; - - //If this chunk has more free nodes than the next ones, - //we have to move the chunk in the list to maintain it ordered. - //Check if we have to move it - while(next_chunk != m_chunklist.end() && - this_chunk->free_nodes.size() > next_chunk->free_nodes.size()){ - ++next_chunk; - } - //Check if the chunk must be moved - if(++chunk_iterator(this_chunk) != next_chunk){ - //Update m_first_free_chunk iterator if it was pointing to this_chunk - if(m_first_free_chunk == this_chunk){ - ++m_first_free_chunk; - } - //Update m_first_free_chunk if the moved chunk crosses the empty boundary - else if(this_chunk->free_nodes.size() == 1){ - m_first_free_chunk = chunk_list_t::s_iterator_to(*chunk_info); - } - //Now move the chunk to the new position - m_chunklist.erase(this_chunk); - m_chunklist.insert(next_chunk, *chunk_info); - } - //Update m_first_free_chunk if the chunk crosses the empty boundary - else if(this_chunk->free_nodes.size() == 1){ - --m_first_free_chunk; - } - - if(this_chunk->free_nodes.size() == m_real_num_node){ - ++m_free_chunks; - } - - assert(m_allocated>0); - --m_allocated; - priv_invariants(); - priv_deallocate_free_chunks(m_max_free_chunks); - priv_invariants(); + hdr_offset_holder *hdr_off_holder = (hdr_offset_holder*) + (((char*)chunk) - (m_num_subchunks-1)*m_real_chunk_alignment); + assert(hdr_off_holder->hdr_offset == std::size_t((char*)chunk - (char*)hdr_off_holder)); + assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); + assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); + return hdr_off_holder; } void priv_deallocate_free_chunks(std::size_t max_free_chunks) { - typedef typename chunk_list_t::iterator chunk_iterator; + priv_invariants(); //Now check if we've reached the free nodes limit //and check if we have free chunks. If so, deallocate as much //as we can to stay below the limit - while(m_free_chunks > max_free_chunks && - m_chunklist.back().free_nodes.size() == m_real_num_node){ - chunk_iterator it(--m_chunklist.end()); - if(it == m_first_free_chunk) - ++m_first_free_chunk; //m_first_free_chunk is now equal to end() - m_chunklist.erase_and_dispose(it, chunk_destroyer(detail::get_pointer(mp_segment_mngr_base),m_real_num_node)); - --m_free_chunks; + for( chunk_iterator itend = m_chunk_multiset.end() + ; m_totally_free_chunks > max_free_chunks + ; --m_totally_free_chunks + ){ + assert(!m_chunk_multiset.empty()); + chunk_iterator it = itend; + --it; + std::size_t num_nodes = it->free_nodes.size(); + assert(num_nodes == m_real_num_node); + (void)num_nodes; + m_chunk_multiset.erase_and_dispose + (it, chunk_destroyer(this)); } } - //!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc - void priv_alloc_chunk() + //!Allocates a several chunks of nodes. Can throw boost::interprocess::bad_alloc + void priv_alloc_chunk(std::size_t n) { - //We allocate a new NodeBlock and put it as first - //element in the free Node list - std::size_t real_chunk_size = m_real_chunk_alignment - SegmentManagerBase::PayloadPerAllocation; - char *pNode = detail::char_ptr_cast - (mp_segment_mngr_base->allocate_aligned(real_chunk_size, m_real_chunk_alignment)); - if(!pNode) throw bad_alloc(); - chunk_info_t *c_info = new(pNode)chunk_info_t; - m_chunklist.push_back(*c_info); - - pNode += m_header_size; - //We initialize all Nodes in Node Block to insert - //them in the free Node list - for(std::size_t i = 0; i < m_real_num_node; ++i){ - c_info->free_nodes.push_front(*new (pNode) node_t); - pNode += m_real_node_size; + std::size_t real_chunk_size = m_real_chunk_alignment*m_num_subchunks - SegmentManagerBase::PayloadPerAllocation; + std::size_t elements_per_subchunk = (m_real_chunk_alignment - HdrOffsetSize)/m_real_node_size; + std::size_t hdr_subchunk_elements = (m_real_chunk_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 = detail::char_ptr_cast + (mp_segment_mngr_base->allocate_aligned(real_chunk_size, m_real_chunk_alignment)); + if(!mem_address) throw std::bad_alloc(); + ++m_totally_free_chunks; + + //First initialize header information on the last subchunk + char *hdr_addr = mem_address + m_real_chunk_alignment*(m_num_subchunks-1); + chunk_info_t *c_info = new(hdr_addr)chunk_info_t; + //Some structural checks + assert(static_cast(&static_cast(c_info)->hdr_offset) == + static_cast(c_info)); + typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin(); + for( std::size_t subchunk = 0, maxsubchunk = m_num_subchunks - 1 + ; subchunk < maxsubchunk + ; ++subchunk, mem_address += m_real_chunk_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_subchunk; ++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_subchunk_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 chunk after the free node list is full + m_chunk_multiset.insert(m_chunk_multiset.end(), *c_info); } - ++m_free_chunks; } private: typedef typename pointer_to_other ::type segment_mngr_base_ptr_t; - const std::size_t m_node_size; const std::size_t m_max_free_chunks; const std::size_t m_real_node_size; - const std::size_t m_header_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_chunk_alignment; + std::size_t m_num_subchunks; //This is the real number of nodes per chunk - const std::size_t m_real_num_node; + //const + std::size_t m_real_num_node; segment_mngr_base_ptr_t mp_segment_mngr_base;//Segment manager - chunk_list_t m_chunklist; //Intrusive chunk list - typename chunk_list_t::iterator m_first_free_chunk; //Iterator to the active chunk - std::size_t m_allocated; //Used nodes for debugging - std::size_t m_free_chunks; //Free chunks + chunk_multiset_t m_chunk_multiset; //Intrusive chunk list + std::size_t m_totally_free_chunks; //Free chunks }; -//!Pooled shared memory allocator using an smart 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 chunk (NodesPerChunk) are known at compile time. template< class SegmentManager , std::size_t NodeSize , std::size_t NodesPerChunk , std::size_t MaxFreeChunks + , unsigned char OverheadPercent > class private_adaptive_node_pool : public private_adaptive_node_pool_impl @@ -448,8 +561,8 @@ class private_adaptive_node_pool static const std::size_t nodes_per_chunk = NodesPerChunk; //!Constructor from a segment manager. Never throws - private_adaptive_node_pool(segment_manager *segmeng_mngr) - : base_t(segmeng_mngr, NodeSize, NodesPerChunk, MaxFreeChunks) + private_adaptive_node_pool(segment_manager *segment_mngr) + : base_t(segment_mngr, NodeSize, NodesPerChunk, MaxFreeChunks, OverheadPercent) {} //!Returns the segment manager. Never throws @@ -462,117 +575,25 @@ class private_adaptive_node_pool //!responsibility of user classes. Node size (NodeSize) and the number of //!nodes allocated per chunk (NodesPerChunk) are known at compile time template< class SegmentManager - , class Mutex , std::size_t NodeSize , std::size_t NodesPerChunk , std::size_t MaxFreeChunks + , unsigned char OverheadPercent > class shared_adaptive_node_pool - : public private_adaptive_node_pool - + : public detail::shared_pool_impl + < private_adaptive_node_pool + + > { - private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef private_adaptive_node_pool - private_node_allocator_t; - public: - //!Segment manager typedef - typedef SegmentManager segment_manager; - typedef typename private_node_allocator_t::free_nodes_t free_nodes_t; - - //!Constructor from a segment manager. Never throws - shared_adaptive_node_pool(segment_manager *segment_mgnr) - : private_node_allocator_t(segment_mgnr){} - - //!Destructor. Deallocates all allocated chunks. Never throws - ~shared_adaptive_node_pool() + typedef detail::shared_pool_impl + < private_adaptive_node_pool + + > base_t; + public: + shared_adaptive_node_pool(SegmentManager *segment_mgnr) + : base_t(segment_mgnr) {} - - //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc - void *allocate(std::size_t count) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return private_node_allocator_t::allocate(count); - } - - //!Deallocates an array pointed by ptr. Never throws - void deallocate(void *ptr, std::size_t count) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate(ptr, count); - } - - //!Allocates a singly linked list of n nodes ending in null pointer. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(std::size_t n, free_nodes_t &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return private_node_allocator_t::allocate_nodes(n, nodes); - } - - //!Deallocates a linked list of nodes ending in null pointer. Never throws - void deallocate_nodes(free_nodes_t &nodes, std::size_t num) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes, num); - } - - //!Deallocates a linked list of nodes ending in null pointer. Never throws - void deallocate_nodes(free_nodes_t &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes); - } - - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_free_chunks(); - } - - //!Increments internal reference count and returns new count. Never throws - std::size_t inc_ref_count() - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return ++m_header.m_usecount; - } - - //!Decrements internal reference count and returns new count. Never throws - std::size_t dec_ref_count() - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - assert(m_header.m_usecount > 0); - return --m_header.m_usecount; - } - - private: - //!This struct includes needed data and derives from - //!interprocess_mutex to allow EBO when using null_mutex - struct header_t : Mutex - { - std::size_t m_usecount; //Number of attached allocators - - header_t() - : m_usecount(0) {} - } m_header; }; } //namespace detail { diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp new file mode 100644 index 0000000..7c5bbcc --- /dev/null +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -0,0 +1,760 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include +#include +#include +#include //pointer_to_other, get_pointer +#include //std::pair +#include //boost::addressof +#include //BOOST_ASSERT +#include //bad_alloc +#include //scoped_lock +#include //allocation_type +#include //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 +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 + (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 +inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr) +{ + detail::get_or_create_node_pool_func 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 +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(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 +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_funcfunc(pool); + mngr->atomic_func(func); +} + +template +class cache_impl +{ + typedef typename NodePool::segment_manager:: + void_pointer void_pointer; + typedef typename pointer_to_other + ::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::multiallocation_iterator multiallocation_iterator; + 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(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()){ + mp_node_pool->allocate_nodes(m_cached_nodes, m_max_cached_nodes/2); + } + return m_cached_nodes.pop_front(); + } + + multiallocation_iterator cached_allocation(std::size_t n) + { + multiallocation_chain chain; + std::size_t count = n; + 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 = m_cached_nodes.pop_front(); + chain.push_back(ret); + } + + if(chain.size() != n){ + mp_node_pool->allocate_nodes(chain, n - chain.size()); + } + assert(chain.size() == n); + chain.splice_back(m_cached_nodes); + return multiallocation_iterator(chain.get_it()); + } + BOOST_CATCH(...){ + this->cached_deallocation(multiallocation_iterator(chain.get_it())); + throw; + } + 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_iterator it) + { + multiallocation_iterator itend; + + while(it != itend){ + void *addr = &*it; + ++it; + m_cached_nodes.push_front(addr); + } + + //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(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 array_allocation_impl +{ + const Derived *derived() const + { return static_cast(this); } + Derived *derived() + { return static_cast(this); } + + typedef typename SegmentManager::void_pointer void_pointer; + + public: + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename detail::add_reference + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain 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 + 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 chunk + //!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_iterator allocate_many(size_type elem_size, std::size_t num_elements) + { + return multiallocation_iterator + (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 chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + { + return multiallocation_iterator + (this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T))); + } + + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it) + { return this->derived()->get_segment_manager()->deallocate_many(it.base()); } + + //!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(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(); } +}; + + +template +class node_pool_allocation_impl + : public array_allocation_impl + < Derived + , T + , SegmentManager> +{ + const Derived *derived() const + { return static_cast(this); } + Derived *derived() + { return static_cast(this); } + + typedef typename SegmentManager::void_pointer void_pointer; + typedef typename detail:: + pointer_to_other::type cvoid_pointer; + + public: + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename detail::add_reference + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; + + 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; + if(count > this->max_size()) + throw bad_alloc(); + else if(Version == 1 && count == 1) + return pointer(static_cast(this->derived()->get_node_pool()->allocate_node())); + else + return pointer(static_cast + (this->derived()->get_node_pool()->get_segment_manager()->allocate(sizeof(T)*count))); + } + + //!Deallocate allocated memory. Never throws + void deallocate(const pointer &ptr, size_type count) + { + (void)count; + if(Version == 1 && count == 1) + this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(ptr)); + else + this->derived()->get_node_pool()->get_segment_manager()->deallocate(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(this->derived()->get_node_pool()->allocate_node())); } + + //!Allocates many elements of size == 1 in a contiguous chunk + //!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_iterator allocate_individual(std::size_t num_elements) + { return multiallocation_iterator(this->derived()->get_node_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) + { this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(p)); } + + //!Allocates many elements of size == 1 in a contiguous chunk + //!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_iterator it) + { this->derived()->get_node_pool()->deallocate_nodes(it.base()); } + + //!Deallocates all free chunks of the pool + void deallocate_free_chunks() + { this->derived()->get_node_pool()->deallocate_free_chunks(); } +}; + +template +class cached_allocator_impl + : public array_allocation_impl + , T, typename NodePool::segment_manager> +{ + cached_allocator_impl & operator=(const cached_allocator_impl& other); + typedef array_allocation_impl + < cached_allocator_impl + + , 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::type cvoid_pointer; + typedef typename base_t::pointer pointer; + typedef typename base_t::size_type size_type; + typedef typename base_t::multiallocation_iterator multiallocation_iterator; + 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 + cached_allocator_impl + (const cached_allocator_impl + &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(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(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(this->m_cache.cached_allocation())); } + + //!Allocates many elements of size == 1 in a contiguous chunk + //!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_iterator allocate_individual(std::size_t num_elements) + { return multiallocation_iterator(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 chunk + //!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_iterator it) + { m_cache.cached_deallocation(it.base()); } + + //!Deallocates all free chunks of the pool + void deallocate_free_chunks() + { m_cache.get_node_pool()->deallocate_free_chunks(); } + + //!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(); } + + /// @cond + private: + cache_impl m_cache; +}; + +//!Equality test for same type of +//!cached_allocator_impl +template inline +bool operator==(const cached_allocator_impl &alloc1, + const cached_allocator_impl &alloc2) + { return alloc1.get_node_pool() == alloc2.get_node_pool(); } + +//!Inequality test for same type of +//!cached_allocator_impl +template inline +bool operator!=(const cached_allocator_impl &alloc1, + const cached_allocator_impl &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 chunk (NodesPerChunk) are known at compile time +template +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_iterator multiallocation_iterator; + 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 chunks. Never throws + ~shared_pool_impl() + {} + + //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc + void *allocate_node() + { + //----------------------- + boost::interprocess::scoped_lock 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 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 guard(m_header); + //----------------------- + return private_node_allocator_t::allocate_nodes(nodes, n); + } + + //!Allocates n nodes, pointed by the multiallocation_iterator. + //!Can throw boost::interprocess::bad_alloc + multiallocation_iterator allocate_nodes(const std::size_t n) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return private_node_allocator_t::allocate_nodes(n); + } + + //!Deallocates a linked list of nodes ending in null pointer. Never throws + void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(nodes, num); + } + + //!Deallocates a linked list of nodes ending in null pointer. Never throws + void deallocate_nodes(multiallocation_chain &nodes) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(nodes); + } + + //!Deallocates the nodes pointed by the multiallocation iterator. Never throws + void deallocate_nodes(multiallocation_iterator it) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_nodes(it); + } + + //!Deallocates all the free chunks of memory. Never throws + void deallocate_free_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_chunks(); + } + + //!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_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::purge_chunks(); + } + + //!Increments internal reference count and returns new count. Never throws + std::size_t inc_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return ++m_header.m_usecount; + } + + //!Decrements internal reference count and returns new count. Never throws + std::size_t dec_ref_count() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + assert(m_header.m_usecount > 0); + return --m_header.m_usecount; + } + + private: + //!This struct includes needed data and derives from + //!interprocess_mutex to allow EBO when using null_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 + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index 726b99f..ce2c74b 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -51,10 +53,14 @@ class private_node_pool_impl typedef typename node_slist::slist_hook_t slist_hook_t; typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; + typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; + typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: - typedef typename bi::make_slist < node_t, bi::base_hook - , bi::constant_time_size >::type chunkslist_t; + typedef typename bi::make_slist + < node_t, bi::base_hook + , bi::linear + , bi::constant_time_size >::type chunkslist_t; public: //!Segment manager typedef @@ -62,10 +68,8 @@ class private_node_pool_impl //!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_chunk) - : m_node_size(node_size) - , m_nodes_per_chunk(nodes_per_chunk) - , m_real_node_size(detail::lcm(node_size, sizeof(node_t))) - , m_block_size(detail::get_rounded_size(m_real_node_size*m_nodes_per_chunk, sizeof(node_t))) + : m_nodes_per_chunk(nodes_per_chunk) + , m_real_node_size(detail::lcm(node_size, std::size_t(alignment_of::value))) //General purpose allocator , mp_segment_mngr_base(segment_mngr_base) , m_chunklist() @@ -76,7 +80,7 @@ class private_node_pool_impl //!Destructor. Deallocates all allocated chunks. Never throws ~private_node_pool_impl() - { priv_clear(); } + { this->purge_chunks(); } std::size_t get_real_num_node() const { return m_nodes_per_chunk; } @@ -86,116 +90,73 @@ class private_node_pool_impl { return detail::get_pointer(mp_segment_mngr_base); } //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc - void *allocate(std::size_t count) - { - std::size_t bytes = count*m_node_size; - if(bytes > m_real_node_size){//Normal allocation, no pooling used - void *addr = mp_segment_mngr_base->allocate(bytes); - if(!addr) throw bad_alloc(); - return addr; - } - else //Node allocation, pooling used - return priv_alloc_node(); - } + void *allocate_node() + { return priv_alloc_node(); } //!Deallocates an array pointed by ptr. Never throws - void deallocate(void *ptr, std::size_t count) - { - std::size_t bytes = count*m_node_size; - if(bytes > m_real_node_size)//Normal allocation was used - mp_segment_mngr_base->deallocate(ptr); - else //Node allocation was used - priv_dealloc_node(ptr); - } + void deallocate_node(void *ptr) + { priv_dealloc_node(ptr); } - //!Allocates a singly linked list of n nodes ending in null pointer. + //!Allocates a singly linked list of n nodes ending in null pointer and pushes them in the chain. //!can throw boost::interprocess::bad_alloc - void allocate_nodes(const std::size_t n, free_nodes_t &nodes) + void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) { std::size_t i = 0; try{ for(; i < n; ++i){ - nodes.push_front(*priv_alloc_node()); + nodes.push_front(priv_alloc_node()); } } catch(...){ - priv_deallocate_nodes(nodes, i); + this->deallocate_nodes(nodes, i); throw; } } - //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(free_nodes_t &nodes) - { priv_deallocate_nodes(nodes, nodes.size()); } - - //!Deallocates the first n nodes of a linked list of nodes. Never throws - void deallocate_nodes(free_nodes_t &nodes, std::size_t n) - { priv_deallocate_nodes(nodes, n); } - - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() - { priv_deallocate_free_chunks(); } - - std::size_t num_free_nodes() - { return m_freelist.size(); } - - void swap(private_node_pool_impl &other) + //!Allocates a singly linked list of n nodes ending in null pointer + //!can throw boost::interprocess::bad_alloc + multiallocation_iterator allocate_nodes(const std::size_t n) { - std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); - m_chunklist.swap(other.m_chunklist); - m_freelist.swap(other.m_freelist); - std::swap(m_allocated, other.m_allocated); + multiallocation_chain nodes; + std::size_t i = 0; + try{ + for(; i < n; ++i){ + nodes.push_front(priv_alloc_node()); + } + } + catch(...){ + this->deallocate_nodes(nodes, i); + throw; + } + return nodes.get_it(); } - private: + //!Deallocates a linked list of nodes. Never throws + void deallocate_nodes(multiallocation_chain &nodes) + { this->deallocate_nodes(nodes.get_it()); } - void priv_deallocate_nodes(free_nodes_t &nodes, const std::size_t num) + //!Deallocates the first n nodes of a linked list of nodes. Never throws + void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) { assert(nodes.size() >= num); for(std::size_t i = 0; i < num; ++i){ - node_t *to_deallocate = &nodes.front(); - nodes.pop_front(); - deallocate(to_deallocate, 1); + deallocate_node(nodes.pop_front()); } } - struct push_in_list + //!Deallocates the nodes pointed by the multiallocation iterator. Never throws + void deallocate_nodes(multiallocation_iterator it) { - 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(); - } + multiallocation_iterator itend; + while(it != itend){ + void *addr = &*it; + ++it; + deallocate_node(addr); } + } - private: - free_nodes_t &slist_; - typename free_nodes_t::iterator &last_it_; - }; - - struct is_between - : std::unary_function - { - is_between(const void *addr, std::size_t size) - : beg_((const char *)addr), end_(beg_+size) - {} - - bool operator()(typename free_nodes_t::const_reference v) const - { - return (beg_ <= (const char *)&v && - end_ > (const char *)&v); - } - private: - const char * beg_; - const char * end_; - }; - - void priv_deallocate_free_chunks() + //!Deallocates all the free chunks of memory. Never throws + void deallocate_free_chunks() { typedef typename free_nodes_t::iterator nodelist_iterator; typename chunkslist_t::iterator bit(m_chunklist.before_begin()), @@ -204,16 +165,19 @@ class private_node_pool_impl 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_chunk, alignment_of::value); + while(it != itend){ //Collect all the nodes from the chunk 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_chunk_from_hook(&*it); + const void *addr = get_chunk_from_hook(&*it, blocksize); - //Execute the algorithm and get an iterator to the last value m_freelist.remove_and_dispose_if - (is_between(addr, m_block_size), push_in_list(free_nodes, last_it)); + (is_between(addr, blocksize), push_in_list(free_nodes, last_it)); //If the number of nodes is equal to m_nodes_per_chunk //this means that the block can be deallocated @@ -253,23 +217,76 @@ class private_node_pool_impl , backup_list.size()); } - //!Deallocates all used memory. Never throws - void priv_clear() + 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_chunks() { //check for memory leaks assert(m_allocated==0); - + std::size_t blocksize = detail::get_rounded_size + (m_real_node_size*m_nodes_per_chunk, alignment_of::value); typename chunkslist_t::iterator it(m_chunklist.begin()), itend(m_chunklist.end()), aux; //We iterate though the NodeBlock list to free the memory while(!m_chunklist.empty()){ - void *addr = get_chunk_from_hook(&m_chunklist.front()); + void *addr = get_chunk_from_hook(&m_chunklist.front(), blocksize); m_chunklist.pop_front(); mp_segment_mngr_base->deallocate(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_chunklist.swap(other.m_chunklist); + 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 + { + is_between(const void *addr, std::size_t size) + : beg_((const char *)addr), end_(beg_+size) + {} + + bool operator()(typename free_nodes_t::const_reference v) const + { + return (beg_ <= (const char *)&v && + end_ > (const char *)&v); + } + private: + const char * beg_; + const char * end_; + }; + //!Allocates one node, using single segregated storage algorithm. //!Never throws node_t *priv_alloc_node() @@ -300,10 +317,13 @@ class private_node_pool_impl { //We allocate a new NodeBlock and put it as first //element in the free Node list - char *pNode = detail::char_ptr_cast(mp_segment_mngr_base->allocate(m_block_size + sizeof(node_t))); + std::size_t blocksize = + detail::get_rounded_size(m_real_node_size*m_nodes_per_chunk, alignment_of::value); + char *pNode = detail::char_ptr_cast + (mp_segment_mngr_base->allocate(blocksize + sizeof(node_t))); if(!pNode) throw bad_alloc(); char *pBlock = pNode; - m_chunklist.push_front(get_chunk_hook(pBlock)); + m_chunklist.push_front(get_chunk_hook(pBlock, blocksize)); //We initialize all Nodes in Node Block to insert //them in the free Node list @@ -314,26 +334,24 @@ class private_node_pool_impl private: //!Returns a reference to the chunk hook placed in the end of the chunk - inline node_t & get_chunk_hook (void *chunk) + static inline node_t & get_chunk_hook (void *chunk, std::size_t blocksize) { return *static_cast( - static_cast((detail::char_ptr_cast(chunk)+m_block_size))); + static_cast((detail::char_ptr_cast(chunk) + blocksize))); } //!Returns the starting address of the chunk reference to the chunk hook placed in the end of the chunk - inline void *get_chunk_from_hook (node_t *hook) + inline void *get_chunk_from_hook (node_t *hook, std::size_t blocksize) { - return static_cast((detail::char_ptr_cast(hook) - m_block_size)); + return static_cast((detail::char_ptr_cast(hook) - blocksize)); } private: typedef typename pointer_to_other ::type segment_mngr_base_ptr_t; - const std::size_t m_node_size; const std::size_t m_nodes_per_chunk; const std::size_t m_real_node_size; - const std::size_t m_block_size; segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager chunkslist_t m_chunklist; //Intrusive container of chunks free_nodes_t m_freelist; //Intrusive container of free nods @@ -376,114 +394,28 @@ class private_node_pool //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of //!nodes allocated per chunk (NodesPerChunk) 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 chunk (NodesPerChunk) are known at compile time template< class SegmentManager - , class Mutex , std::size_t NodeSize , std::size_t NodesPerChunk > class shared_node_pool - : public private_node_pool + : public detail::shared_pool_impl + < private_node_pool + + > { - private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef private_node_pool - private_node_allocator_t; - + typedef detail::shared_pool_impl + < private_node_pool + + > base_t; public: - typedef SegmentManager segment_manager; - typedef typename private_node_allocator_t::free_nodes_t free_nodes_t; - - //!Constructor from a segment manager. Never throws - shared_node_pool(segment_manager *segment_mngr) - : private_node_allocator_t(segment_mngr){} - - //!Destructor. Deallocates all allocated chunks. Never throws - ~shared_node_pool() + shared_node_pool(SegmentManager *segment_mgnr) + : base_t(segment_mgnr) {} - - //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc - void *allocate(std::size_t count) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return private_node_allocator_t::allocate(count); - } - - //!Deallocates an array pointed by ptr. Never throws - void deallocate(void *ptr, std::size_t count) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate(ptr, count); - } - - //!Allocates a singly linked list of n nodes ending in null pointer. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(const std::size_t n, free_nodes_t &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::allocate_nodes(n, nodes); - } - - //!Deallocates a linked list of nodes ending in null pointer. Never throws - void deallocate_nodes(free_nodes_t &nodes, std::size_t n) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes, n); - } - - void deallocate_nodes(free_nodes_t &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes); - } - - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_free_chunks(); - } - - //!Increments internal reference count and returns new count. Never throws - std::size_t inc_ref_count() - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return ++m_header.m_usecount; - } - - //!Decrements internal reference count and returns new count. Never throws - std::size_t dec_ref_count() - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - assert(m_header.m_usecount > 0); - return --m_header.m_usecount; - } - - private: - //!This struct includes needed data and derives from - //!interprocess_mutex to allow EBO when using null_mutex - struct header_t : Mutex - { - std::size_t m_usecount; //Number of attached allocators - - header_t() - : m_usecount(0) {} - } m_header; }; } //namespace detail { diff --git a/include/boost/interprocess/allocators/detail/node_tools.hpp b/include/boost/interprocess/allocators/detail/node_tools.hpp index bf6860a..048eb7c 100644 --- a/include/boost/interprocess/allocators/detail/node_tools.hpp +++ b/include/boost/interprocess/allocators/detail/node_tools.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007. Distributed under the Boost +// (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) // @@ -37,7 +37,8 @@ struct node_slist : public slist_hook_t {}; - typedef typename bi::make_slist >::type node_slist_t; + typedef typename bi::make_slist + , bi::base_hook >::type node_slist_t; }; } //namespace detail { diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index f6a0aa5..eed6e9e 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_POOLED_NODE_ALLOCATOR_HPP -#define BOOST_INTERPROCESS_POOLED_NODE_ALLOCATOR_HPP +#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP +#define BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -22,9 +22,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include @@ -35,26 +36,35 @@ namespace boost { namespace interprocess { -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This node allocator shares a segregated storage between all instances -//!of node_allocator with equal sizeof(T) placed in the same segment -//!group. NodesPerChunk is the number of nodes allocated at once when the allocator -//!needs runs out of nodes -template -class node_allocator +/// @cond + +namespace detail{ + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerChunk + > +class node_allocator_base + : public node_pool_allocation_impl + < node_allocator_base + < Version, T, SegmentManager, NodesPerChunk> + , Version + , T + , SegmentManager + > { public: typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; typedef SegmentManager segment_manager; - typedef typename SegmentManager:: - mutex_family::mutex_type mutex_type; - typedef node_allocator - self_t; + typedef node_allocator_base + self_t; + typedef detail::shared_node_pool + < SegmentManager, sizeof(T), NodesPerChunk> node_pool_t; + typedef typename detail:: + pointer_to_other::type node_pool_ptr; + + BOOST_STATIC_ASSERT((Version <=2)); public: //------- @@ -69,61 +79,61 @@ class node_allocator ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::shared_node_pool - < SegmentManager, mutex_type - , sizeof(T), NodesPerChunk> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; - //!Obtains node_allocator from other - //!node_allocator + typedef detail::version_type version; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; + + //!Obtains node_allocator_base from + //!node_allocator_base template struct rebind { - typedef node_allocator other; + typedef node_allocator_base other; }; /// @cond private: - //!Not assignable from related - //!node_allocator - template - node_allocator& operator= - (const node_allocator&); + //!Not assignable from related node_allocator_base + template + node_allocator_base& operator= + (const node_allocator_base&); - //!Not assignable from other - //!node_allocator - node_allocator& operator=(const node_allocator&); + //!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(segment_manager *segment_mngr) - : mp_node_pool(priv_get_or_create(segment_mngr)) - {} + node_allocator_base(segment_manager *segment_mngr) + : mp_node_pool(detail::get_or_create_node_pool(segment_mngr)) { } - //!Copy constructor from other node_allocator. Increments the reference + //!Copy constructor from other node_allocator_base. Increments the reference //!count of the associated node pool. Never throws - node_allocator(const node_allocator &other) + node_allocator_base(const node_allocator_base &other) : mp_node_pool(other.get_node_pool()) - { mp_node_pool->inc_ref_count(); } + { + mp_node_pool->inc_ref_count(); + } - //!Copy constructor from related node_allocator. If not present, constructs + //!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 - node_allocator - (const node_allocator &other) - : mp_node_pool(priv_get_or_create(other.get_segment_manager())) - {} + node_allocator_base + (const node_allocator_base &other) + : mp_node_pool(detail::get_or_create_node_pool(other.get_segment_manager())) { } //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws - ~node_allocator() - { priv_destroy_if_last_link(); } + ~node_allocator_base() + { detail::destroy_node_pool_if_last_link(detail::get_pointer(mp_node_pool)); } //!Returns a pointer to the node pool. //!Never throws @@ -135,159 +145,290 @@ class node_allocator segment_manager* get_segment_manager()const { return mp_node_pool->get_segment_manager(); } - //!Returns the number of elements that could be allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } - - //!Allocate memory for an array of count elements. - //!Throws boost::interprocess::bad_alloc if there is no enough memory - pointer allocate(size_type count, cvoid_pointer = 0) - { - if(count > ((size_type)-1)/sizeof(value_type)) - throw bad_alloc(); - return pointer(static_cast(mp_node_pool->allocate(count))); - } - - //!Deallocate allocated memory. - //!Never throws - void deallocate(const pointer &ptr, size_type count) - { mp_node_pool->deallocate(detail::get_pointer(ptr), count); } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { mp_node_pool->deallocate_free_chunks(); } - //!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); } - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... - - //!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(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(); } - /// @cond - private: - //!Object function that creates the node allocator if it is not created and - //!increments reference count if it is already created - struct get_or_create_func - { - typedef detail::shared_node_pool - node_pool_t; - - //!This connects or constructs the unique instance of node_pool_t - //!Can throw boost::interprocess::bad_alloc - void operator()() - { - //Find or create the node_pool_t - mp_node_pool = mp_named_alloc->template find_or_construct - (unique_instance)(mp_named_alloc); - //If valid, increment link count - if(mp_node_pool != 0) - mp_node_pool->inc_ref_count(); - } - - //!Constructor. Initializes function - //!object parameters - get_or_create_func(segment_manager *hdr) : mp_named_alloc(hdr){} - - node_pool_t *mp_node_pool; - segment_manager *mp_named_alloc; - }; - - //!Initialization function, creates an executes atomically the - //!initialization object functions. Can throw boost::interprocess::bad_alloc - node_pool_t *priv_get_or_create(segment_manager *named_alloc) - { - get_or_create_func func(named_alloc); - named_alloc->atomic_func(func); - return func.mp_node_pool; - } - - //!Object function that decrements the reference count. If the count - //!reaches to zero destroys the node allocator from memory. - //!Never throws - struct destroy_if_last_link_func - { - typedef detail::shared_node_pool - node_pool_t; - - //!Decrements reference count and destroys the object if there is no - //!more attached allocators. Never throws - void operator()() - { - //If not the last link return - if(mp_node_pool->dec_ref_count() != 0) return; - - //Last link, let's destroy the segment_manager - mp_named_alloc->template destroy(unique_instance); - } - - //!Constructor. Initializes function - //!object parameters - destroy_if_last_link_func(segment_manager *nhdr, - node_pool_t *phdr) - : mp_named_alloc(nhdr), mp_node_pool(phdr) - {} - - segment_manager *mp_named_alloc; - node_pool_t *mp_node_pool; - }; - - //!Destruction function, initializes and executes destruction function - //!object. Never throws - void priv_destroy_if_last_link() - { - typedef detail::shared_node_pool - node_pool_t; - //Get segment manager - segment_manager *named_segment_mngr = this->get_segment_manager(); - //Execute destruction functor atomically - destroy_if_last_link_func func(named_segment_mngr, detail::get_pointer(mp_node_pool)); - named_segment_mngr->atomic_func(func); - } - private: node_pool_ptr mp_node_pool; /// @endcond }; -//!Equality test for same type of -//!node_allocator -template inline -bool operator==(const node_allocator &alloc1, - const node_allocator &alloc2) +//!Equality test for same type +//!of node_allocator_base +template inline +bool operator==(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } -//!Inequality test for same type of -//!node_allocator -template inline -bool operator!=(const node_allocator &alloc1, - const node_allocator &alloc2) +//!Inequality test for same type +//!of node_allocator_base +template inline +bool operator!=(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } +template < class T + , class SegmentManager + , std::size_t NodesPerChunk = 64 + > +class node_allocator_v1 + : public node_allocator_base + < 1 + , T + , SegmentManager + , NodesPerChunk + > +{ + public: + typedef detail::node_allocator_base + < 1, T, SegmentManager, NodesPerChunk> base_t; + + template + struct rebind + { + typedef node_allocator_v1 other; + }; + + node_allocator_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + node_allocator_v1 + (const node_allocator_v1 &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. NodesPerChunk is the number of nodes allocated at once when the allocator +//!needs runs out of nodes +template < class T + , class SegmentManager + , std::size_t NodesPerChunk + > +class node_allocator + /// @cond + : public detail::node_allocator_base + < 2 + , T + , SegmentManager + , NodesPerChunk + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef detail::node_allocator_base + < 2, T, SegmentManager, NodesPerChunk> base_t; + public: + typedef detail::version_type version; + + template + struct rebind + { + typedef node_allocator other; + }; + + node_allocator(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + node_allocator + (const node_allocator &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 + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + //!Obtains node_allocator from + //!node_allocator + template + struct rebind + { + typedef node_allocator other; + }; + + private: + //!Not assignable from + //!related node_allocator + template + node_allocator& operator= + (const node_allocator&); + + //!Not assignable from + //!other node_allocator + node_allocator& operator=(const node_allocator&); + + public: + //!Constructor from a segment manager. If not present, constructs a node + //!pool. Increments the reference count of the associated node pool. + //!Can throw boost::interprocess::bad_alloc + node_allocator(segment_manager *segment_mngr); + + //!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 + node_allocator + (const node_allocator &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 + 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 chunks + //!of the pool + void deallocate_free_chunks(); + + //!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); + + //!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 + 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 chunk + //!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_iterator 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 chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it); + + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator it); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of node_allocator +template inline +bool operator==(const node_allocator &alloc1, + const node_allocator &alloc2); + +//!Inequality test for same type +//!of node_allocator +template inline +bool operator!=(const node_allocator &alloc1, + const node_allocator &alloc2); + +#endif + } //namespace interprocess { } //namespace boost { #include -#endif //#ifndef BOOST_INTERPROCESS_POOLED_NODE_ALLOCATOR_HPP +#endif //#ifndef BOOST_INTERPROCESS_NODE_ALLOCATOR_HPP diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index 1c743ce..5552348 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -30,38 +30,47 @@ #include //!\file -//!Describes private_adaptive_pool pooled shared memory STL compatible allocator +//!Describes private_adaptive_pool_base pooled shared memory STL compatible allocator namespace boost { namespace interprocess { -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This allocator has its own node pool. NodesPerChunk is the minimum number of nodes -//!allocated at once when the allocator needs runs out of nodes. -template -class private_adaptive_pool +/// @cond + +namespace detail { + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > +class private_adaptive_pool_base + : public node_pool_allocation_impl + < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerChunk + , MaxFreeChunks, OverheadPercent> + , Version + , T + , SegmentManager + > { /// @cond private: typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; typedef SegmentManager segment_manager; - typedef typename detail:: - pointer_to_other::type char_pointer; - typedef typename detail::pointer_to_other - ::type segment_mngr_ptr_t; - typedef typename SegmentManager:: - mutex_family::mutex_type mutex_type; - typedef private_adaptive_pool - self_t; + typedef private_adaptive_pool_base + < Version, T, SegmentManager, NodesPerChunk + , MaxFreeChunks, OverheadPercent> self_t; typedef detail::private_adaptive_node_pool - priv_node_pool_t; + node_pool_t; + BOOST_STATIC_ASSERT((Version <=2)); /// @endcond @@ -77,120 +86,358 @@ class private_adaptive_pool ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; + typedef detail::version_type + version; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; //!Obtains node_allocator from other node_allocator template struct rebind { - typedef private_adaptive_pool other; + typedef private_adaptive_pool_base + other; }; /// @cond private: - //!Not assignable from related private_adaptive_pool - template - private_adaptive_pool& operator= - (const private_adaptive_pool&); + //!Not assignable from related private_adaptive_pool_base + template + private_adaptive_pool_base& operator= + (const private_adaptive_pool_base&); - //!Not assignable from other private_adaptive_pool - private_adaptive_pool& operator=(const private_adaptive_pool&); + //!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(segment_manager *segment_mngr) + private_adaptive_pool_base(segment_manager *segment_mngr) : m_node_pool(segment_mngr) {} - //!Copy constructor from other private_adaptive_pool. Never throws - private_adaptive_pool(const private_adaptive_pool &other) + //!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. Never throws. + //!Copy constructor from related private_adaptive_pool_base. Never throws. template - private_adaptive_pool - (const private_adaptive_pool &other) + private_adaptive_pool_base + (const private_adaptive_pool_base + &other) : m_node_pool(other.get_segment_manager()) {} //!Destructor, frees all used memory. Never throws - ~private_adaptive_pool() + ~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 number of elements that could be allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()/sizeof(value_type); } - - //!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; - if(count > ((size_type)-1)/sizeof(value_type)) - throw bad_alloc(); - return pointer(static_cast(m_node_pool.allocate(count))); - } - - //!Deallocate allocated memory. Never throws - void deallocate(const pointer &ptr, size_type count) - { m_node_pool.deallocate(detail::get_pointer(ptr), count); } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { m_node_pool.deallocate_free_chunks(); } + //!Returns the internal node pool. Never throws + node_pool_t* get_node_pool() const + { return const_cast(&m_node_pool); } //!Swaps allocators. Does not throw. If each allocator is placed in a - //!different shared memory segments, the result is undefined.*/ + //!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); } - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... - - //!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(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(); } - /// @cond private: - priv_node_pool_t m_node_pool; + node_pool_t m_node_pool; /// @endcond }; -//!Equality test for same type of private_adaptive_pool -template inline -bool operator==(const private_adaptive_pool &alloc1, - const private_adaptive_pool &alloc2) +//!Equality test for same type of private_adaptive_pool_base +template inline +bool operator==(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) { return &alloc1 == &alloc2; } -//!Inequality test for same type of private_adaptive_pool -template inline -bool operator!=(const private_adaptive_pool &alloc1, - const private_adaptive_pool &alloc2) -{ - return &alloc1 != &alloc2; -} +//!Inequality test for same type of private_adaptive_pool_base +template inline +bool operator!=(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) +{ return &alloc1 != &alloc2; } + +template < class T + , class SegmentManager + , std::size_t NodesPerChunk = 64 + , std::size_t MaxFreeChunks = 2 + , unsigned char OverheadPercent = 5 + > +class private_adaptive_pool_v1 + : public private_adaptive_pool_base + < 1 + , T + , SegmentManager + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > +{ + public: + typedef detail::private_adaptive_pool_base + < 1, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + + template + struct rebind + { + typedef private_adaptive_pool_v1 other; + }; + + private_adaptive_pool_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_adaptive_pool_v1 + (const private_adaptive_pool_v1 &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. +//! +//!NodesPerChunk is the minimum number of nodes of nodes allocated at once when +//!the allocator needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks +//!that the adaptive node pool will hold. The rest of the totally free chunks 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 NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > +class private_adaptive_pool + /// @cond + : public detail::private_adaptive_pool_base + < 2 + , T + , SegmentManager + , NodesPerChunk + , MaxFreeChunks + , OverheadPercent + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef detail::private_adaptive_pool_base + < 2, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + public: + typedef detail::version_type version; + + template + struct rebind + { + typedef private_adaptive_pool + other; + }; + + private_adaptive_pool(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_adaptive_pool + (const private_adaptive_pool &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 + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + //!Obtains private_adaptive_pool from + //!private_adaptive_pool + template + struct rebind + { + typedef private_adaptive_pool + other; + }; + + private: + //!Not assignable from + //!related private_adaptive_pool + template + private_adaptive_pool& operator= + (const private_adaptive_pool&); + + //!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 + private_adaptive_pool + (const private_adaptive_pool &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 chunks + //!of the pool + void deallocate_free_chunks(); + + //!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); + + //!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 + 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 chunk + //!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_iterator 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 chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it); + + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator it); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of private_adaptive_pool +template inline +bool operator==(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); + +//!Inequality test for same type +//!of private_adaptive_pool +template inline +bool operator!=(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); + +#endif } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index be7d491..608bacc 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -1,13 +1,13 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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 @@ -50,12 +50,8 @@ class private_node_allocator typedef typename detail:: pointer_to_other::type cvoid_pointer; typedef SegmentManager segment_manager; - typedef typename detail:: - pointer_to_other::type char_pointer; typedef typename detail::pointer_to_other ::type segment_mngr_ptr_t; - typedef typename SegmentManager:: - mutex_family::mutex_type mutex_type; typedef private_node_allocator self_t; typedef detail::private_node_pool @@ -128,21 +124,30 @@ class private_node_allocator pointer allocate(size_type count, cvoid_pointer hint = 0) { (void)hint; - if(count > ((size_type)-1)/sizeof(value_type)) + if(count > this->max_size()) throw bad_alloc(); - return pointer(static_cast(m_node_pool.allocate(count))); + else if(count == 1) + return pointer(static_cast(m_node_pool.allocate_node())); + else + return pointer(static_cast + (m_node_pool.get_segment_manager()->allocate(sizeof(T)*count))); } //!Deallocate allocated memory. Never throws void deallocate(const pointer &ptr, size_type count) - { m_node_pool.deallocate(detail::get_pointer(ptr), count); } + { + if(count == 1) + m_node_pool.deallocate_node(detail::get_pointer(ptr)); + else + m_node_pool.get_segment_manager()->deallocate(detail::get_pointer(ptr)); + } //!Deallocates all free chunks of the pool void deallocate_free_chunks() { m_node_pool.deallocate_free_chunks(); } //!Swaps allocators. Does not throw. If each allocator is placed in a - //!different shared memory segments, the result is undefined.*/ + //!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); } @@ -160,7 +165,7 @@ class private_node_allocator { return const_pointer(boost::addressof(value)); } //!Default construct an object. - //!Throws if T's default constructor throws*/ + //!Throws if T's default constructor throws void construct(const pointer &ptr) { new(detail::get_pointer(ptr)) value_type; } @@ -196,3 +201,432 @@ bool operator!=(const private_node_allocator &alloc1, #endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP +*/ + +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\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 NodesPerChunk + > +class private_node_allocator_base + : public node_pool_allocation_impl + < private_node_allocator_base < Version, T, SegmentManager, NodesPerChunk> + , Version + , T + , SegmentManager + > +{ + /// @cond + private: + typedef typename SegmentManager::void_pointer void_pointer; + typedef SegmentManager segment_manager; + typedef private_node_allocator_base + < Version, T, SegmentManager, NodesPerChunk> self_t; + typedef detail::private_node_pool + node_pool_t; + + BOOST_STATIC_ASSERT((Version <=2)); + + /// @endcond + + public: + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename detail::add_reference + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef detail::version_type + version; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; + + //!Obtains node_allocator from other node_allocator + template + struct rebind + { + typedef private_node_allocator_base + other; + }; + + /// @cond + private: + //!Not assignable from related private_node_allocator_base + template + private_node_allocator_base& operator= + (const private_node_allocator_base&); + + //!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 + private_node_allocator_base + (const private_node_allocator_base + &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(&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 inline +bool operator==(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) +{ return &alloc1 == &alloc2; } + +//!Inequality test for same type of private_node_allocator_base +template inline +bool operator!=(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) +{ return &alloc1 != &alloc2; } + +template < class T + , class SegmentManager + , std::size_t NodesPerChunk = 64 + > +class private_node_allocator_v1 + : public private_node_allocator_base + < 1 + , T + , SegmentManager + , NodesPerChunk + > +{ + public: + typedef detail::private_node_allocator_base + < 1, T, SegmentManager, NodesPerChunk> base_t; + + template + struct rebind + { + typedef private_node_allocator_v1 other; + }; + + private_node_allocator_v1(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_node_allocator_v1 + (const private_node_allocator_v1 &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. NodesPerChunk is the number of nodes allocated +//!at once when the allocator needs runs out of nodes +template < class T + , class SegmentManager + , std::size_t NodesPerChunk + > +class private_node_allocator + /// @cond + : public detail::private_node_allocator_base + < 2 + , T + , SegmentManager + , NodesPerChunk + > + /// @endcond +{ + + #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + typedef detail::private_node_allocator_base + < 2, T, SegmentManager, NodesPerChunk> base_t; + public: + typedef detail::version_type version; + + template + struct rebind + { + typedef private_node_allocator + other; + }; + + private_node_allocator(SegmentManager *segment_mngr) + : base_t(segment_mngr) + {} + + template + private_node_allocator + (const private_node_allocator &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 + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + //!Obtains private_node_allocator from + //!private_node_allocator + template + struct rebind + { + typedef private_node_allocator + other; + }; + + private: + //!Not assignable from + //!related private_node_allocator + template + private_node_allocator& operator= + (const private_node_allocator&); + + //!Not assignable from + //!other private_node_allocator + private_node_allocator& operator=(const private_node_allocator&); + + 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 + private_node_allocator + (const private_node_allocator &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 chunks + //!of the pool + void deallocate_free_chunks(); + + //!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); + + //!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 + 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 chunk + //!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_iterator 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 chunk + //!of memory. The elements must be deallocated + multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + + //!Allocates many elements of size elem_size in a contiguous chunk + //!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_iterator it); + + //!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 chunk + //!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_iterator 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 chunk + //!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_iterator it); + #endif +}; + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +//!Equality test for same type +//!of private_node_allocator +template inline +bool operator==(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); + +//!Inequality test for same type +//!of private_node_allocator +template inline +bool operator!=(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP + diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/detail/flat_tree.hpp index 001b213..5901a2f 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/detail/flat_tree.hpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 339cefc..7352019 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -74,6 +74,9 @@ struct node_alloc_holder typedef detail::integral_constant::value> alloc_version; + typedef typename ICont::iterator icont_iterator; + typedef typename ICont::const_iterator icont_citerator; + typedef allocator_destroyer Destroyer; node_alloc_holder(const ValAlloc &a) : members_(a) @@ -292,18 +295,41 @@ struct node_alloc_holder if(constructed){ this->destroy(p); } - this->deallocate_one(p); - multiallocation_iterator itend; - while(itbeg != itend){ - Node *n = &*itbeg; - ++itbeg; - this->deallocate_one(n); - } + this->node_alloc().deallocate_many(itbeg); } BOOST_CATCH_END return beg; } + void clear(allocator_v1) + { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + + void clear(allocator_v2) + { + allocator_multialloc_chain_node_deallocator chain_holder(this->node_alloc()); + this->icont().clear_and_dispose(chain_holder.get_chain_builder()); + } + + 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 chain_holder(this->node_alloc()); + return this->icont().erase_and_dispose(first, last, chain_holder.get_chain_builder()); + } + + template + 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 + size_type erase_key(const Key& k, const Comparator &comp, allocator_v2) + { + allocator_multialloc_chain_node_deallocator chain_holder(this->node_alloc()); + return this->icont().erase_and_dispose(k, comp, chain_holder.get_chain_builder()); + } + protected: struct cloner { @@ -359,10 +385,10 @@ struct node_alloc_holder { return this->members_.m_icont; } NodeAlloc &node_alloc() - { return this->members_; } + { return static_cast(this->members_); } const NodeAlloc &node_alloc() const - { return this->members_; } + { return static_cast(this->members_); } }; } //namespace detail { diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/detail/tree.hpp index ecaae35..b2e4428 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/detail/tree.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -732,13 +732,13 @@ class rbtree { return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc()))); } size_type erase(const key_type& k) - { return this->icont().erase_and_dispose(k, KeyNodeCompare(value_comp()), Destroyer(this->node_alloc())); } + { return AllocHolder::erase_key(k, KeyNodeCompare(value_comp()), alloc_version()); } iterator erase(const_iterator first, const_iterator last) - { return iterator(this->icont().erase_and_dispose(first.get(), last.get(), Destroyer(this->node_alloc()))); } + { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } void clear() - { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + { AllocHolder::clear(alloc_version()); } // set operations: iterator find(const key_type& k) diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index da45184..0478e2c 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index 00ee12b..d98677a 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index 902d89f..b9e0801 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -404,7 +404,7 @@ class list //! //! Complexity: Linear to the number of elements in the list. void clear() - { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + { AllocHolder::clear(alloc_version()); } //! Effects: Returns an iterator to the first element contained in the list. //! @@ -786,7 +786,7 @@ class list //! //! Complexity: Linear to the distance between first and last. iterator erase(iterator first, iterator last) - { return iterator(this->icont().erase_and_dispose(first.get(), last.get(), Destroyer(this->node_alloc()))); } + { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } //! Effects: Assigns the n copies of val to *this. //! @@ -1085,6 +1085,7 @@ class list /// @cond private: + //Iterator range version template void priv_create_and_insert_nodes @@ -1160,7 +1161,7 @@ class list template void priv_insert_dispatch(iterator p, Integer n, Integer x, detail::true_) - { this->priv_create_and_insert_nodes(p, n, x); } + { this->insert(p, (size_type)n, x); } void priv_fill_assign(size_type n, const T& val) { diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index 896262b..b8d45f3 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index e9d7cb0..bc4b364 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 195910f..9f57c24 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2004-2007. Distributed under the Boost +// (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) // @@ -8,7 +8,7 @@ // ////////////////////////////////////////////////////////////////////////////// // -// This file comes from SGI's stl_slist.h file. Modified by Ion Gaztanaga 2004-2007 +// 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. // diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index ac4ce46..37f3269 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -8,7 +8,7 @@ // ////////////////////////////////////////////////////////////////////////////// // -// This file comes from SGI's string file. Modified by Ion Gaztanaga 2004-2007 +// 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. // diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index a49e2a4..bd7fb5d 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -740,6 +740,9 @@ class vector : private detail::vector_alloc_holder //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 @@ -748,6 +751,9 @@ class vector : private detail::vector_alloc_holder copy_move_it dummy_it(detail::get_pointer(this->members_.m_start)); //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 @@ -758,6 +764,9 @@ class vector : private detail::vector_alloc_holder } //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 @@ -1184,11 +1193,17 @@ class vector : private detail::vector_alloc_holder //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), first, last, n); } //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 @@ -1199,6 +1214,9 @@ class vector : private detail::vector_alloc_holder } //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 @@ -1778,6 +1796,15 @@ class vector : private detail::vector_alloc_holder 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_alloc; + void reset_alloc_stats() + { num_expand_fwd = num_expand_bwd = num_alloc = 0; } + #endif /// @endcond }; diff --git a/include/boost/interprocess/creation_tags.hpp b/include/boost/interprocess/creation_tags.hpp index 521a9b5..190c6bd 100644 --- a/include/boost/interprocess/creation_tags.hpp +++ b/include/boost/interprocess/creation_tags.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index cc303f4..b95d301 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. +// (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 diff --git a/include/boost/interprocess/detail/atomic.hpp b/include/boost/interprocess/detail/atomic.hpp index e41248e..944d1a8 100644 --- a/include/boost/interprocess/detail/atomic.hpp +++ b/include/boost/interprocess/detail/atomic.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2006-2007 +// (C) Copyright Ion Gaztanaga 2006-2008 // (C) Copyright Markus Schoepflin 2007 // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/include/boost/interprocess/detail/cast_tags.hpp b/include/boost/interprocess/detail/cast_tags.hpp index 9099c0f..6d28a24 100644 --- a/include/boost/interprocess/detail/cast_tags.hpp +++ b/include/boost/interprocess/detail/cast_tags.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp index abde766..4db523a 100644 --- a/include/boost/interprocess/detail/config_begin.hpp +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -9,6 +9,7 @@ #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 diff --git a/include/boost/interprocess/detail/in_place_interface.hpp b/include/boost/interprocess/detail/in_place_interface.hpp index 57aeeba..dd8c4c0 100644 --- a/include/boost/interprocess/detail/in_place_interface.hpp +++ b/include/boost/interprocess/detail/in_place_interface.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/interprocess_tester.hpp b/include/boost/interprocess/detail/interprocess_tester.hpp index 0354a96..ffb66ea 100644 --- a/include/boost/interprocess/detail/interprocess_tester.hpp +++ b/include/boost/interprocess/detail/interprocess_tester.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/iterators.hpp b/include/boost/interprocess/detail/iterators.hpp index 5483de8..c566159 100644 --- a/include/boost/interprocess/detail/iterators.hpp +++ b/include/boost/interprocess/detail/iterators.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. +// (C) Copyright Ion Gaztanaga 2005-2008. // (C) Copyright Gennaro Prota 2003 - 2004. // // Distributed under the Boost Software License, Version 1.0. @@ -428,6 +428,12 @@ class transform_iterator operator->() const { return operator_arrow_proxy(dereference()); } + Iterator & base() + { return m_it; } + + const Iterator & base() const + { return m_it; } + private: Iterator m_it; diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index 91c5e0e..c659d9d 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index c754f9b..362b1cd 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Stephen Cleary 2000. -// (C) Copyright Ion Gaztanaga 2007. +// (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 diff --git a/include/boost/interprocess/detail/min_max.hpp b/include/boost/interprocess/detail/min_max.hpp index 92eb959..2c4f3e7 100644 --- a/include/boost/interprocess/detail/min_max.hpp +++ b/include/boost/interprocess/detail/min_max.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. +// (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 diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index 8ab2600..0ae2392 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. +// (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 diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index bb7588a..98a28ee 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp index bdecd8a..0a81c59 100644 --- a/include/boost/interprocess/detail/os_file_functions.hpp +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp index 0a26e44..4373152 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/pointer_type.hpp b/include/boost/interprocess/detail/pointer_type.hpp index 52a2274..9f17fa0 100644 --- a/include/boost/interprocess/detail/pointer_type.hpp +++ b/include/boost/interprocess/detail/pointer_type.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. +// (C) Copyright Ion Gaztanaga 2005-2008. // (C) Copyright Gennaro Prota 2003 - 2004. // // Distributed under the Boost Software License, Version 1.0. diff --git a/include/boost/interprocess/detail/posix_time_types_wrk.hpp b/include/boost/interprocess/detail/posix_time_types_wrk.hpp index ad077c3..bf6e485 100644 --- a/include/boost/interprocess/detail/posix_time_types_wrk.hpp +++ b/include/boost/interprocess/detail/posix_time_types_wrk.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 515516e..4961422 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/tmp_dir_helpers.hpp b/include/boost/interprocess/detail/tmp_dir_helpers.hpp index 5b742c4..34db635 100644 --- a/include/boost/interprocess/detail/tmp_dir_helpers.hpp +++ b/include/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/type_traits.hpp b/include/boost/interprocess/detail/type_traits.hpp index bc3fb1a..d06d041 100644 --- a/include/boost/interprocess/detail/type_traits.hpp +++ b/include/boost/interprocess/detail/type_traits.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // (C) Copyright John Maddock 2000. -// (C) Copyright Ion Gaztanaga 2005-2007. +// (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 diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index 0bb4a0f..0e507f8 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. +// (C) Copyright Ion Gaztanaga 2005-2008. // (C) Copyright Gennaro Prota 2003 - 2004. // // Distributed under the Boost Software License, Version 1.0. @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include @@ -70,14 +73,27 @@ template struct scoped_ptr_dealloc_functor { typedef typename Allocator::pointer pointer; + typedef detail::integral_constant::value> alloc_version; + typedef detail::integral_constant allocator_v1; + typedef detail::integral_constant 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) {} + : m_alloc(a) {} void operator()(pointer ptr) - { if (ptr) m_alloc.deallocate(ptr, 1); } + { if (ptr) priv_deallocate(ptr, alloc_version()); } }; //!A deleter for scoped_ptr that deallocates the memory @@ -86,7 +102,20 @@ template struct scoped_deallocator { typedef typename Allocator::pointer pointer; + typedef detail::integral_constant::value> alloc_version; + typedef detail::integral_constant allocator_v1; + typedef detail::integral_constant allocator_v2; + private: + void priv_deallocate(allocator_v1) + { m_alloc.deallocate(m_ptr, 1); } + + void priv_deallocate(allocator_v2) + { m_alloc.deallocate_one(m_ptr); } + + public: pointer m_ptr; Allocator& m_alloc; @@ -94,7 +123,7 @@ struct scoped_deallocator : m_ptr(p), m_alloc(a) {} ~scoped_deallocator() - { if (m_ptr) m_alloc.deallocate(m_ptr, 1); } + { if (m_ptr)priv_deallocate(alloc_version()); } void release() { m_ptr = 0; } @@ -189,9 +218,22 @@ template class allocator_destroyer { typedef typename A::value_type value_type; + typedef detail::integral_constant::value> alloc_version; + typedef detail::integral_constant allocator_v1; + typedef detail::integral_constant 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) @@ -200,35 +242,86 @@ class allocator_destroyer void operator()(const typename A::pointer &p) { detail::get_pointer(p)->~value_type(); - a_.deallocate(p, 1); + priv_deallocate(p, alloc_version()); } }; -//!A class used for exception-safe multi-allocation + construction. -template -struct multiallocation_deallocator +template +class allocator_destroyer_and_chain_builder { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + typedef typename A::value_type value_type; + typedef typename A::multiallocation_iterator multiallocation_iterator; + typedef typename A::multiallocation_chain multiallocation_chain; - multiallocation_iterator m_itbeg; - Allocator& m_alloc; + A & a_; + multiallocation_chain &c_; - multiallocation_deallocator(multiallocation_iterator itbeg, Allocator& a) - : m_itbeg(itbeg), m_alloc(a) {} + public: + allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) + : a_(a), c_(c) + {} - ~multiallocation_deallocator() - { - multiallocation_iterator endit; - while(m_itbeg != endit){ - m_alloc.deallocate(&*m_itbeg, 1); - ++m_itbeg; - } + void operator()(const typename A::pointer &p) + { + value_type *vp = detail::get_pointer(p); + vp->~value_type(); + c_.push_back(vp); } - - void increment() - { ++m_itbeg; } }; +template +class allocator_multialloc_chain_node_deallocator +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_iterator multiallocation_iterator; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_node_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_node_deallocator() + { + multiallocation_iterator it(c_.get_it()); + if(it != multiallocation_iterator()) + a_.deallocate_individual(it); + } +}; + +template +class allocator_multialloc_chain_array_deallocator +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_iterator multiallocation_iterator; + typedef typename A::multiallocation_chain multiallocation_chain; + typedef allocator_destroyer_and_chain_builder chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_array_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_array_deallocator() + { + multiallocation_iterator it(c_.get_it()); + if(it != multiallocation_iterator()) + a_.deallocate_many(it); + } +}; //!A class used for exception-safe multi-allocation + construction. template @@ -577,6 +670,14 @@ inline void swap(pair&&x, pair&&y) } #endif +template +struct cast_functor +{ + typedef typename detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + } //namespace detail { //!The pair is movable if any of its members is movable diff --git a/include/boost/interprocess/detail/version_type.hpp b/include/boost/interprocess/detail/version_type.hpp index 7b71268..ed43623 100644 --- a/include/boost/interprocess/detail/version_type.hpp +++ b/include/boost/interprocess/detail/version_type.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index 1800ea5..b6771d0 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index 6265d8d..b22e283 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -19,8 +19,8 @@ #if defined(_POSIX_THREAD_PROCESS_SHARED) # if !((_XOPEN_VERSION >= 600) && (_POSIX_THREAD_PROCESS_SHARED - 0 <= 0)) - // Cygwin defines _POSIX_THREAD_PROCESS_SHARED but does not support it. - // Mac Os X >= Leopard defines _POSIX_THREAD_PROCESS_SHARED but it does not seem to work + //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 diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index d7ba469..1374c8e 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/exceptions.hpp b/include/boost/interprocess/exceptions.hpp index dcc4f6d..8bbb211 100644 --- a/include/boost/interprocess/exceptions.hpp +++ b/include/boost/interprocess/exceptions.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index ac81ca0..a55ff03 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/indexes/flat_map_index.hpp b/include/boost/interprocess/indexes/flat_map_index.hpp index 7ea1600..ad338da 100644 --- a/include/boost/interprocess/indexes/flat_map_index.hpp +++ b/include/boost/interprocess/indexes/flat_map_index.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/indexes/iset_index.hpp b/include/boost/interprocess/indexes/iset_index.hpp index f29a771..5a4a1e6 100644 --- a/include/boost/interprocess/indexes/iset_index.hpp +++ b/include/boost/interprocess/indexes/iset_index.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/indexes/iunordered_set_index.hpp b/include/boost/interprocess/indexes/iunordered_set_index.hpp index dd5e1c1..d247adc 100644 --- a/include/boost/interprocess/indexes/iunordered_set_index.hpp +++ b/include/boost/interprocess/indexes/iunordered_set_index.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/indexes/map_index.hpp b/include/boost/interprocess/indexes/map_index.hpp index df568dc..024c647 100644 --- a/include/boost/interprocess/indexes/map_index.hpp +++ b/include/boost/interprocess/indexes/map_index.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/indexes/null_index.hpp b/include/boost/interprocess/indexes/null_index.hpp index 5d3be0d..1cc2908 100644 --- a/include/boost/interprocess/indexes/null_index.hpp +++ b/include/boost/interprocess/indexes/null_index.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/indexes/unordered_map_index.hpp b/include/boost/interprocess/indexes/unordered_map_index.hpp index 44f226c..8c2f670 100644 --- a/include/boost/interprocess/indexes/unordered_map_index.hpp +++ b/include/boost/interprocess/indexes/unordered_map_index.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index 4244e62..acb1b3e 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -129,13 +129,19 @@ class private_node_allocator; template class cached_node_allocator; -template +template class adaptive_pool; -template +template class private_adaptive_pool; -template +template class cached_adaptive_pool; @@ -151,10 +157,10 @@ class offset_ptr; ////////////////////////////////////////////////////////////////////////////// //Single segment memory allocation algorithms -template//offset_ptr > +template > class simple_seq_fit; -template > +template, std::size_t MemAlignment = 0> class rbtree_best_fit; ////////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index b6366f8..b28ba68 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index 23fe0ac..be18e4d 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -20,6 +20,7 @@ #include #include #include +#include //!\file //!Describes a named user memory allocation user class. @@ -49,6 +50,8 @@ class basic_managed_external_buffer 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(); } @@ -58,6 +61,8 @@ class basic_managed_external_buffer 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(); } diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp index 77843f5..36e97bd 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index bc0355b..cdd6267 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index e49fb22..551a7d3 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index 105e74b..b4acdf0 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index d859a52..71a28fb 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index a9b6219..acd2c16 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -104,6 +104,167 @@ class basic_multiallocation_iterator multi_allocation_next next_alloc_; }; +template +class basic_multiallocation_chain +{ + private: + basic_multiallocation_iterator it_; + VoidPointer last_mem_; + std::size_t num_mem_; + + basic_multiallocation_chain(const basic_multiallocation_chain &); + basic_multiallocation_chain &operator=(const basic_multiallocation_chain &); + + public: + typedef basic_multiallocation_iterator multiallocation_iterator; + + basic_multiallocation_chain() + : it_(0), last_mem_(0), num_mem_(0) + {} + + void push_back(void *mem) + { + typedef multi_allocation_next next_impl_t; + next_impl_t * tmp_mem = static_cast(mem); + + if(!this->last_mem_){ + this->it_ = basic_multiallocation_iterator(tmp_mem); + } + else{ + static_cast(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; + } + tmp_mem->next_ = 0; + this->last_mem_ = tmp_mem; + ++num_mem_; + } + + void push_back(multiallocation_iterator it, std::size_t n) + { + typedef multi_allocation_next next_impl_t; + next_impl_t * tmp_mem = (next_impl_t*)(&*it); + + if(!this->last_mem_){ + this->it_ = it; + } + else{ + static_cast(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; + } + tmp_mem->next_ = 0; + this->last_mem_ = tmp_mem; + ++num_mem_; + } + + void push_front(void *mem) + { + typedef multi_allocation_next next_impl_t; + + if(!this->last_mem_){ + push_back(mem); + } + else{ + next_impl_t * tmp_mem = static_cast(mem); + next_impl_t * old_first = (next_impl_t*)(&*this->it_); + static_cast(mem)->next_ = old_first; + this->it_ = basic_multiallocation_iterator(tmp_mem); + ++num_mem_; + } + } + + void swap(basic_multiallocation_chain &other_chain) + { + std::swap(this->it_, other_chain.it_); + std::swap(this->last_mem_, other_chain.last_mem_); + std::swap(this->num_mem_, other_chain.num_mem_); + } + + void splice_back(basic_multiallocation_chain &other_chain) + { + typedef multi_allocation_next next_impl_t; + multiallocation_iterator end_it; + multiallocation_iterator other_it = other_chain.get_it(); + multiallocation_iterator this_it = this->get_it(); + if(end_it == other_it){ + return; + } + else if(end_it == other_it){ + this->swap(other_chain); + } + + static_cast(detail::get_pointer(this->last_mem_))->next_ + = (next_impl_t*)&*this->it_; + this->last_mem_ = other_chain.last_mem_; + this->num_mem_ += other_chain.num_mem_; + } + + void *pop_front() + { + multiallocation_iterator itend; + if(this->it_ == itend){ + this->last_mem_= 0; + this->num_mem_ = 0; + return 0; + } + else{ + void *addr = &*it_; + ++it_; + --num_mem_; + if(!num_mem_){ + this->last_mem_ = 0; + this->it_ = multiallocation_iterator(); + } + return addr; + } + } + + bool empty() const + { return !num_mem_; } + + multiallocation_iterator get_it() const + { return it_; } + + std::size_t size() const + { return num_mem_; } +}; + +template +class allocator_multiallocation_chain +{ + typedef typename detail:: + pointer_to_other::type + void_ptr; + + typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + basic_multiallocation_chain chain_; + + public: + + allocator_multiallocation_chain() + : chain_() + {} + + void push_back(void *mem) + { chain_.push_back(mem); } + + multiallocation_iterator get_it() const + { return multiallocation_iterator(chain_.get_it()); } +}; + + +#define BOOST_MULTIALLOC_IT_CHAIN_INIT(IT_CHAIN) ((IT_CHAIN).it.next = 0, (IT_CHAIN).last_mem = 0) +#define BOOST_MULTIALLOC_IT_CHAIN_ADD(IT_CHAIN, MEM)\ + do{\ + multialloc_it_t *____tmp_mem____ = (multialloc_it_t*)(MEM);\ + if(!IT_CHAIN.last_mem){\ + (IT_CHAIN).it.next = ____tmp_mem____;\ + }else{\ + ((multialloc_it_t*)(IT_CHAIN.last_mem))->next = ____tmp_mem____;\ + }\ + ____tmp_mem____->next = 0;\ + IT_CHAIN.last_mem = ____tmp_mem____;\ + }while(0) + +#define BOOST_MULTIALLOC_IT_CHAIN_IT(IT_CHAIN) ((IT_CHAIN).it) + //!This class implements several allocation functions shared by different algorithms //!(aligned allocation, multiple allocation...). @@ -125,6 +286,7 @@ class memory_algorithm_common 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); } @@ -165,10 +327,11 @@ class memory_algorithm_common 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); + BOOST_ASSERT((alignment & (alignment - std::size_t(1u))) == 0); return 0; } @@ -176,6 +339,9 @@ class memory_algorithm_common 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 chunk that has alignment //nbytes + alignment bytes or more. @@ -191,7 +357,9 @@ class memory_algorithm_common // | MBU | // ----------------------------------------------------- std::size_t request = - minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes); + 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; @@ -207,7 +375,8 @@ class memory_algorithm_common 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 = new((char*)first + Alignment*first_min_units) block_ctrl; + //block_ctrl *second = new((char*)first + Alignment*first_min_units) block_ctrl; + block_ctrl *second = (block_ctrl *)((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); @@ -285,6 +454,7 @@ class memory_algorithm_common ,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; @@ -296,11 +466,11 @@ class memory_algorithm_common assert_alignment(ptr); //Put this to a safe value - received_size = (old_block_units - AllocatedCtrlUnits)*Alignment; + 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); - const std::size_t preferred_user_units = ceil_units(preferred_size); + 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) @@ -331,7 +501,7 @@ class memory_algorithm_common } //Update new size - received_size = shrunk_user_units*Alignment; + received_size = shrunk_user_units*Alignment + UsableByPreviousChunk; return true; } @@ -350,22 +520,23 @@ class memory_algorithm_common } //Check if the old size was just the shrunk size (no splitting) - if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size)) + 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/Alignment + AllocatedCtrlUnits; + block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits; BOOST_ASSERT(block->m_size >= BlockCtrlUnits); - memory_algo->priv_mark_new_allocated_block(block); //We create the new block - block_ctrl *new_block = new(reinterpret_cast - (detail::char_ptr_cast(block) + block->m_size*Alignment)) block_ctrl; - +// block_ctrl *new_block = new(reinterpret_cast +// (detail::char_ptr_cast(block) + block->m_size*Alignment)) block_ctrl; + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(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; @@ -401,11 +572,11 @@ class memory_algorithm_common multi_allocation_next_ptr first = 0, previous = 0; std::size_t low_idx = 0; while(low_idx < n_elements){ - std::size_t total_bytes = total_request_units*Alignment - AllocatedCtrlBytes; + 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; + min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; std::size_t received_size; std::pair ret = memory_algo->priv_allocate @@ -419,6 +590,7 @@ class memory_algorithm_common char *block_address = (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); @@ -428,7 +600,10 @@ class memory_algorithm_common break; total_request_units -= elem_units; //This is the position where the new block must be created - block_ctrl *new_block = new(block_address)block_ctrl; +// if(prev_block) +// memory_algo->priv_mark_new_allocated_block(prev_block); + block_ctrl *new_block = (block_ctrl *)(block_address); +// block_ctrl *new_block = new(block_address)block_ctrl; assert_alignment(new_block); //The last block should take all the remaining space @@ -446,7 +621,7 @@ class memory_algorithm_common //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; + std::size_t shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk; bool ret = shrink (memory_algo ,memory_algo->priv_get_user_buffer(new_block) @@ -457,7 +632,7 @@ class memory_algorithm_common BOOST_ASSERT(ret); //Some sanity checks BOOST_ASSERT(shrunk_request == shrunk_received); - BOOST_ASSERT(elem_units == (shrunk_request/Alignment + AllocatedCtrlUnits)); + 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 @@ -483,6 +658,7 @@ class memory_algorithm_common } previous = p; ++low_idx; + //prev_block = new_block; } //Sanity check BOOST_ASSERT(total_used_units == received_units); diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index 7300a7b..a724189 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -64,6 +64,8 @@ class simple_seq_fit_impl typedef detail::basic_multiallocation_iterator multiallocation_iterator; + typedef detail::basic_multiallocation_chain + multiallocation_chain; private: class block_ctrl; @@ -137,6 +139,9 @@ class simple_seq_fit_impl //!Multiple element allocation, different size multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + //!Multiple element deallocation + void deallocate_many(multiallocation_iterator it); + /// @endcond //!Deallocates previously allocated bytes @@ -170,8 +175,13 @@ class simple_seq_fit_impl std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); + std::pair + 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(void *ptr) const; + 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 @@ -247,13 +257,16 @@ class simple_seq_fit_impl void priv_mark_new_allocated_block(block_ctrl *block); + public: static const std::size_t Alignment = detail::alignment_of::value; + private: static const std::size_t BlockCtrlBytes = detail::ct_rounded_size::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; @@ -549,17 +562,32 @@ inline std::pair simple_seq_fit_impl:: std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { - if(command & try_shrink_in_place){ - bool success = - algo_impl_t::try_shrink(this, reuse_ptr, limit_size, preferred_size, received_size); - return std::pair ((success ? reuse_ptr : 0), true); - } std::pair ret = priv_allocation_command (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); } +template +inline std::pair simple_seq_fit_impl:: + 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(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 ((success ? reuse_ptr : 0), true); + } + return priv_allocation_command + (command, limit_objects, preferred_objects, received_objects, reuse_ptr, sizeof_object); +} + template inline std::pair simple_seq_fit_impl:: priv_allocation_command (allocation_type command, std::size_t limit_size, @@ -589,13 +617,13 @@ inline std::pair simple_seq_fit_impl:: template inline std::size_t simple_seq_fit_impl:: - size(void *ptr) const + 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 block_ctrl *block = reinterpret_cast - (priv_get_block(detail::char_ptr_cast(ptr))); + (priv_get_block(detail::char_ptr_cast(const_cast(ptr)))); return block->get_user_bytes(); } @@ -689,6 +717,20 @@ inline typename simple_seq_fit_impl::multiallocation_i allocate_many(this, elem_bytes, num_elements); } +template +inline void simple_seq_fit_impl:: + deallocate_many(typename simple_seq_fit_impl::multiallocation_iterator it) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + while(it){ + void *addr = &*it; + ++it; + this->priv_deallocate(addr); + } +} + template inline typename simple_seq_fit_impl::multiallocation_iterator simple_seq_fit_impl:: diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 19100ab..0d7bab9 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -60,7 +60,7 @@ namespace interprocess { //!This class implements an algorithm that stores the free nodes in a red-black tree //!to have logarithmic search/insert times. -template +template class rbtree_best_fit { /// @cond @@ -77,6 +77,8 @@ class rbtree_best_fit typedef VoidPointer void_pointer; typedef detail::basic_multiallocation_iterator multiallocation_iterator; + typedef detail::basic_multiallocation_chain + multiallocation_chain; /// @cond @@ -106,9 +108,9 @@ class rbtree_best_fit { //!This block's memory size (including block_ctrl //!header) in Alignment units - std::size_t m_prev_size : sizeof(std::size_t)*CHAR_BIT - 1; - std::size_t m_end : 1; - std::size_t m_size : sizeof(std::size_t)*CHAR_BIT - 1; + 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; }; @@ -117,7 +119,7 @@ class rbtree_best_fit : public SizeHolder, public TreeHook { block_ctrl() - { this->m_end = 0; this->m_size = 0; this->m_allocated = 0; } + { 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; } @@ -195,6 +197,9 @@ class rbtree_best_fit //!Multiple element allocation, different size multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + //!Multiple element allocation, different size + void deallocate_many(multiallocation_iterator it); + /// @endcond //!Deallocates previously allocated bytes @@ -230,6 +235,11 @@ class rbtree_best_fit std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); + std::pair + 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; @@ -279,18 +289,15 @@ class rbtree_best_fit ,bool only_preferred_backwards ,std::size_t backwards_multiple); - //!Set the size in the tail of the block - void priv_tail_size(block_ctrl *ptr, std::size_t size); - - //!Real private aligned allocation function - //void* priv_allocate_aligned (std::size_t nbytes, std::size_t alignment); - - //!Get the size in the tail of the block - std::size_t priv_tail_size(block_ctrl *ptr); - - //!Get the size in the tail of the previous block + //!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); @@ -316,44 +323,50 @@ class rbtree_best_fit void priv_mark_new_allocated_block(block_ctrl *block); - static const std::size_t Alignment = detail::alignment_of::value; + public: + + static const std::size_t Alignment = !MemAlignment + ? detail::alignment_of::value + : MemAlignment + ; + + private: //Due to embedded bits in size, Alignment must be at least 2 - BOOST_STATIC_ASSERT((Alignment >= 2)); + BOOST_STATIC_ASSERT((Alignment >= 4)); //Due to rbtree size optimizations, Alignment must have at least pointer alignment BOOST_STATIC_ASSERT((Alignment >= detail::alignment_of::value)); static const std::size_t AlignmentMask = (Alignment - 1); static const std::size_t BlockCtrlBytes = detail::ct_rounded_size::value; static const std::size_t BlockCtrlUnits = BlockCtrlBytes/Alignment; - static const std::size_t AllocatedCtrlBytes = detail::ct_rounded_size::value; - static const std::size_t AllocatedCtrlUnits = AllocatedCtrlBytes/Alignment; + static const std::size_t AllocatedCtrlBytes = detail::ct_rounded_size::value; + static const std::size_t AllocatedCtrlUnits = AllocatedCtrlBytes/Alignment; static const std::size_t EndCtrlBlockBytes = detail::ct_rounded_size::value; - static const std::size_t EndCtrlBlockUnits = EndCtrlBlockBytes/Alignment; - static const std::size_t MinBlockUnits = BlockCtrlUnits; + 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; + static const std::size_t PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk; }; -template -inline std::size_t rbtree_best_fit +template +inline std::size_t rbtree_best_fit ::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(rbtree_best_fit) + extra_hdr_bytes + this_disalignment, Alignment) - - this_disalignment; - algo_impl_t::assert_alignment(this_disalignment + block1_off); + 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 -inline rbtree_best_fit:: +template +inline rbtree_best_fit:: rbtree_best_fit(std::size_t size, std::size_t extra_hdr_bytes) { //Initialize the header @@ -368,26 +381,25 @@ inline rbtree_best_fit:: priv_add_segment(detail::char_ptr_cast(this) + block1_off, size - block1_off); } -template -inline rbtree_best_fit::~rbtree_best_fit() +template +inline rbtree_best_fit::~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 -void rbtree_best_fit::grow(std::size_t extra_size) -{ +template +void rbtree_best_fit::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 (detail::char_ptr_cast(this) + block1_off); - block_ctrl *old_end_block = priv_prev_block(first_block); + block_ctrl *old_end_block = priv_end_block(first_block); assert(priv_is_allocated_block(old_end_block)); - assert(old_end_block->m_end); std::size_t old_border_offset = (detail::char_ptr_cast(old_end_block) - detail::char_ptr_cast(this)) + EndCtrlBlockBytes; @@ -406,18 +418,16 @@ void rbtree_best_fit::grow(std::size_t extra_size) (detail::char_ptr_cast(old_end_block) + align_offset*Alignment); new_end_block->m_size = (detail::char_ptr_cast(first_block) - detail::char_ptr_cast(new_end_block))/Alignment; + first_block->m_prev_size = new_end_block->m_size; assert(first_block == priv_next_block(new_end_block)); - new_end_block->m_end = 1; priv_mark_new_allocated_block(new_end_block); - - assert(new_end_block == priv_prev_block(first_block)); + + assert(new_end_block == priv_end_block(first_block)); //The old end block is the new block - std::size_t old_end_prev = old_end_block->m_prev_size; - block_ctrl *new_block = new(old_end_block)block_ctrl; + block_ctrl *new_block = old_end_block; new_block->m_size = (detail::char_ptr_cast(new_end_block) - detail::char_ptr_cast(new_block))/Alignment; - new_block->m_prev_size = old_end_prev; assert(new_block->m_size >= BlockCtrlUnits); priv_mark_new_allocated_block(new_block); assert(priv_next_block(new_block) == new_end_block); @@ -428,8 +438,8 @@ void rbtree_best_fit::grow(std::size_t extra_size) this->priv_deallocate(priv_get_user_buffer(new_block)); } -template -void rbtree_best_fit::shrink_to_fit() +template +void rbtree_best_fit::shrink_to_fit() { //Get the address of the first block std::size_t block1_off = @@ -439,32 +449,36 @@ void rbtree_best_fit::shrink_to_fit() (detail::char_ptr_cast(this) + block1_off); algo_impl_t::assert_alignment(first_block); - block_ctrl *old_end_block = priv_prev_block(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)); - assert(old_end_block->m_end); - block_ctrl *last_block = priv_prev_block(old_end_block); algo_impl_t::assert_alignment(old_end_block); - std::size_t old_end_block_size = old_end_block->m_size; + std::size_t old_end_block_size = old_end_block->m_size; - void *unique_block = 0; - if(last_block == first_block){ + void *unique_buffer = 0; + block_ctrl *last_block; + if(priv_next_block(first_block) == old_end_block){ std::size_t ignore; - unique_block = priv_allocate(allocate_new, 0, 0, ignore).first; - if(!unique_block) + 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_prev_block(old_end_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); + } - //The last block must be free to be able to shrink - if(priv_is_allocated_block(last_block)) - return; - - std::size_t last_block_size = last_block->m_size; + 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)); @@ -474,20 +488,23 @@ void rbtree_best_fit::shrink_to_fit() block_ctrl *new_end_block = last_block; algo_impl_t::assert_alignment(new_end_block); - priv_mark_as_allocated_block(new_end_block); - new_end_block->m_end = 1; new_end_block->m_size = old_end_block_size + last_block_size; - priv_tail_size(new_end_block, new_end_block->m_size); - assert(priv_prev_block(first_block) == new_end_block); + 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_block) - priv_deallocate(unique_block); + if(unique_buffer) + priv_deallocate(unique_buffer); } -template -void rbtree_best_fit:: +template +void rbtree_best_fit:: priv_add_segment(void *addr, std::size_t size) { //Check alignment @@ -506,17 +523,15 @@ void rbtree_best_fit:: (detail::char_ptr_cast(addr) + first_big_block->m_size*Alignment))SizeHolder); //This will overwrite the prev part of the "end" node - priv_tail_size(first_big_block, first_big_block->m_size); priv_mark_as_free_block (first_big_block); first_big_block->m_prev_size = end_block->m_size = (detail::char_ptr_cast(first_big_block) - detail::char_ptr_cast(end_block))/Alignment; - end_block->m_end = 1; - end_block->m_allocated = 1; + priv_mark_as_allocated_block(end_block); assert(priv_next_block(first_big_block) == end_block); - assert(priv_prev_block(end_block) == first_big_block); assert(priv_next_block(end_block) == first_big_block); - assert(priv_prev_block(first_big_block) == end_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: @@ -530,27 +545,24 @@ void rbtree_best_fit:: m_header.m_imultiset.insert(*first_big_block); } -template -inline void rbtree_best_fit:: +template +inline void rbtree_best_fit:: priv_mark_new_allocated_block(block_ctrl *new_block) -{ - priv_tail_size(new_block, new_block->m_size); - priv_mark_as_allocated_block(new_block); -} +{ priv_mark_as_allocated_block(new_block); } -template -inline std::size_t rbtree_best_fit::get_size() const +template +inline std::size_t rbtree_best_fit::get_size() const { return m_header.m_size; } -template -inline std::size_t rbtree_best_fit::get_free_memory() const +template +inline std::size_t rbtree_best_fit::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 -inline std::size_t rbtree_best_fit:: +template +inline std::size_t rbtree_best_fit:: get_min_size (std::size_t extra_hdr_bytes) { return (algo_impl_t::ceil_units(sizeof(rbtree_best_fit)) + @@ -558,8 +570,8 @@ inline std::size_t rbtree_best_fit:: MinBlockUnits + EndCtrlBlockUnits)*Alignment; } -template -inline bool rbtree_best_fit:: +template +inline bool rbtree_best_fit:: all_memory_deallocated() { //----------------------- @@ -575,8 +587,8 @@ inline bool rbtree_best_fit:: (m_header.m_size - block1_off - EndCtrlBlockBytes)/Alignment; } -template -bool rbtree_best_fit:: +template +bool rbtree_best_fit:: check_sanity() { //----------------------- @@ -609,8 +621,8 @@ bool rbtree_best_fit:: return true; } -template -inline void* rbtree_best_fit:: +template +inline void* rbtree_best_fit:: allocate(std::size_t nbytes) { //----------------------- @@ -621,8 +633,8 @@ inline void* rbtree_best_fit:: return ret; } -template -inline void* rbtree_best_fit:: +template +inline void* rbtree_best_fit:: allocate_aligned(std::size_t nbytes, std::size_t alignment) { //----------------------- @@ -631,26 +643,42 @@ inline void* rbtree_best_fit:: return algo_impl_t::allocate_aligned(this, nbytes, alignment); } -template +template template -inline std::pair rbtree_best_fit:: +inline std::pair rbtree_best_fit:: allocation_command (allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { - if(command & try_shrink_in_place){ - bool success = - algo_impl_t::try_shrink(this, reuse_ptr, limit_size, preferred_size, received_size); - return std::pair ((success ? reuse_ptr : 0), true); - } std::pair ret = priv_allocation_command (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); } -template -inline std::pair rbtree_best_fit:: +template +inline std::pair rbtree_best_fit:: + 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(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 ((success ? reuse_ptr : 0), true); + } + return priv_allocation_command + (command, limit_objects, preferred_objects, received_objects, reuse_ptr, sizeof_object); +} + + +template +inline std::pair rbtree_best_fit:: 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) @@ -673,18 +701,18 @@ inline std::pair rbtree_best_fit:: return ret; } -template -inline std::size_t rbtree_best_fit:: +template +inline std::size_t rbtree_best_fit:: 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; + return (priv_get_block(ptr)->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; } -template -inline void rbtree_best_fit::zero_free_memory() +template +inline void rbtree_best_fit::zero_free_memory() { //----------------------- boost::interprocess::scoped_lock guard(m_header); @@ -700,8 +728,8 @@ inline void rbtree_best_fit::zero_free_memory() } } -template -void* rbtree_best_fit:: +template +void* rbtree_best_fit:: priv_expand_both_sides(allocation_type command ,std::size_t min_size ,std::size_t preferred_size @@ -717,7 +745,7 @@ void* rbtree_best_fit:: } else{ received_size = this->size(reuse_ptr); - if(received_size >= preferred_size) + if(received_size >= preferred_size || received_size >= min_size) return reuse_ptr; } @@ -731,18 +759,21 @@ void* rbtree_best_fit:: block_ctrl *reuse = priv_get_block(reuse_ptr); //Sanity check - assert(reuse->m_size == priv_tail_size(reuse)); + //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_allocated_block(prev_block = priv_prev_block(reuse))){ + 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 == priv_tail_size(prev_block)); + assert(prev_block->m_size == reuse->m_prev_size); algo_impl_t::assert_alignment(prev_block); //Let's calculate the number of extra bytes of data before the current @@ -769,32 +800,41 @@ void* rbtree_best_fit:: if(std::size_t(prev_block->m_size*Alignment) >= needs_backwards_aligned){ //Now take all next space. This will succeed if(command & expand_fwd){ - if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){ + 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 (detail::char_ptr_cast(reuse) - needs_backwards_aligned); - //Erase old previous block, since we will change it - m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); - //Free old previous buffer new_block->m_size = - AllocatedCtrlUnits + (needs_backwards_aligned + received_size)/Alignment; + 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 = (detail::char_ptr_cast(new_block) - detail::char_ptr_cast(prev_block))/Alignment; assert(prev_block->m_size >= BlockCtrlUnits); - priv_tail_size(prev_block, prev_block->m_size); priv_mark_as_free_block(prev_block); - //Insert the remaining previous block in the free tree - m_header.m_imultiset.insert( m_header.m_imultiset.begin(), *prev_block); + //Update the old previous block in the free chunks 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; @@ -812,14 +852,15 @@ void* rbtree_best_fit:: //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 % lcm)) { + 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 - const std::size_t needs_backwards_aligned = prev_block->m_size*Alignment; - const std::size_t needs_backwards = detail::get_truncated_size(needs_backwards_aligned, backwards_multiple); - received_size = received_size/backwards_multiple*backwards_multiple + needs_backwards; + needs_backwards = detail::get_truncated_size + (prev_block->m_size*Alignment, backwards_multiple); + //received_size = received_size/backwards_multiple*backwards_multiple + needs_backwards; + received_size = received_size + needs_backwards; m_header.m_allocated += prev_block->m_size*Alignment; //Now update sizes @@ -843,9 +884,9 @@ void* rbtree_best_fit:: return 0; } -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: +template +inline typename rbtree_best_fit::multiallocation_iterator + rbtree_best_fit:: allocate_many(std::size_t elem_bytes, std::size_t num_elements) { //----------------------- @@ -854,9 +895,23 @@ inline typename rbtree_best_fit::multiallocation_itera return algo_impl_t::allocate_many(this, elem_bytes, num_elements); } -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: +template +inline void rbtree_best_fit:: + deallocate_many(typename rbtree_best_fit::multiallocation_iterator it) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + while(it){ + void *addr = &*it; + ++it; + this->priv_deallocate(addr); + } +} + +template +inline typename rbtree_best_fit::multiallocation_iterator + rbtree_best_fit:: allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) { //----------------------- @@ -865,8 +920,8 @@ inline typename rbtree_best_fit::multiallocation_itera return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); } -template -std::pair rbtree_best_fit:: +template +std::pair rbtree_best_fit:: priv_allocate(allocation_type command ,std::size_t limit_size ,std::size_t preferred_size @@ -929,32 +984,34 @@ std::pair rbtree_best_fit:: return return_type(0, false); } -template +template inline -typename rbtree_best_fit::block_ctrl * - rbtree_best_fit::priv_get_block(const void *ptr) +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_get_block(const void *ptr) { return reinterpret_cast(detail::char_ptr_cast(ptr) - AllocatedCtrlBytes); } -template +template inline -void *rbtree_best_fit:: - priv_get_user_buffer(const typename rbtree_best_fit::block_ctrl *block) +void *rbtree_best_fit:: + priv_get_user_buffer(const typename rbtree_best_fit::block_ctrl *block) { return detail::char_ptr_cast(block) + AllocatedCtrlBytes; } -template +template inline -std::size_t rbtree_best_fit:: +std::size_t rbtree_best_fit:: priv_get_total_units(std::size_t userbytes) { - std::size_t units = detail::get_rounded_size(userbytes, Alignment)/Alignment + AllocatedCtrlUnits; + 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 -bool rbtree_best_fit:: +template +bool rbtree_best_fit:: priv_expand (void *ptr ,const std::size_t min_size ,const std::size_t preferred_size @@ -966,16 +1023,16 @@ bool rbtree_best_fit:: //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)); + //assert(old_block_units == priv_tail_size(block)); //Put this to a safe value - received_size = (old_block_units - AllocatedCtrlUnits)*Alignment; - if(received_size > preferred_size) + 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); - const std::size_t preferred_user_units = algo_impl_t::ceil_units(preferred_size); + 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); @@ -994,7 +1051,7 @@ bool rbtree_best_fit:: const std::size_t merged_user_units = merged_units - AllocatedCtrlUnits; if(merged_user_units < min_user_units){ - received_size = merged_user_units*Alignment; + received_size = merged_units*Alignment - UsableByPreviousChunk; return false; } @@ -1007,30 +1064,44 @@ bool rbtree_best_fit:: //Check if we can split the next one in two parts if((merged_units - intended_units) >= BlockCtrlUnits){ - //Now we have to update the data in the tree - m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block)); - //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_tail_size(next_block)); + 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 chunks 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 chunk might + //overwrite the tree hook of the old next chunk. 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 *new_block = new(reinterpret_cast + block_ctrl *rem_block = new(reinterpret_cast (detail::char_ptr_cast(block) + intended_units*Alignment))block_ctrl; - new_block->m_size = merged_units - intended_units; - algo_impl_t::assert_alignment(new_block); - assert(new_block->m_size >= BlockCtrlUnits); - priv_tail_size(new_block, new_block->m_size); - priv_mark_as_free_block(new_block); + 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); - //Insert the new block in the container - m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *new_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); - priv_tail_size(block, block->m_size); m_header.m_allocated += (intended_units - old_block_units)*Alignment; } //There is no free space to create a new node: just merge both blocks @@ -1041,61 +1112,95 @@ bool rbtree_best_fit:: //Write the new length block->m_size = merged_units; assert(block->m_size >= BlockCtrlUnits); - priv_tail_size(block, merged_units); m_header.m_allocated += (merged_units - old_block_units)*Alignment; } - - received_size = (block->m_size - AllocatedCtrlUnits)*Alignment; + priv_mark_as_allocated_block(block); + received_size = (block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; return true; } -template inline -void rbtree_best_fit::priv_tail_size - (typename rbtree_best_fit::block_ctrl *ptr, std::size_t size) -{ priv_next_block(ptr)->m_prev_size = size; } - -template inline -std::size_t rbtree_best_fit::priv_tail_size - (typename rbtree_best_fit::block_ctrl *ptr) -{ return priv_next_block(ptr)->m_prev_size; } - -template inline -typename rbtree_best_fit::block_ctrl * - rbtree_best_fit::priv_prev_block - (typename rbtree_best_fit::block_ctrl *ptr) +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_prev_block + (typename rbtree_best_fit::block_ctrl *ptr) { + assert(!ptr->m_prev_allocated); return reinterpret_cast (detail::char_ptr_cast(ptr) - ptr->m_prev_size*Alignment); } -template inline -typename rbtree_best_fit::block_ctrl * - rbtree_best_fit::priv_next_block - (typename rbtree_best_fit::block_ctrl *ptr) +template inline +bool rbtree_best_fit::priv_is_prev_allocated + (typename rbtree_best_fit::block_ctrl *ptr) +{ + if(ptr->m_prev_allocated){ + return true; + } + else{ + block_ctrl *prev = priv_prev_block(ptr); + assert(!priv_is_allocated_block(prev)); + return false; + } +} + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_end_block + (typename rbtree_best_fit::block_ctrl *first_segment_block) +{ + assert(first_segment_block->m_prev_allocated); + block_ctrl *end_block = reinterpret_cast + (detail::char_ptr_cast(first_segment_block) - first_segment_block->m_prev_size*Alignment); + assert(priv_is_allocated_block(end_block)); + assert(end_block > first_segment_block); + return end_block; +} + +template inline +typename rbtree_best_fit::block_ctrl * + rbtree_best_fit::priv_next_block + (typename rbtree_best_fit::block_ctrl *ptr) { return reinterpret_cast (detail::char_ptr_cast(ptr) + ptr->m_size*Alignment); } -template inline -bool rbtree_best_fit::priv_is_allocated_block - (typename rbtree_best_fit::block_ctrl *block) -{ return block->m_allocated != 0; } +template inline +bool rbtree_best_fit::priv_is_allocated_block + (typename rbtree_best_fit::block_ctrl *block) +{ + bool allocated = block->m_allocated != 0; + block_ctrl *next_block = (block_ctrl *) + (detail::char_ptr_cast(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 inline -void rbtree_best_fit::priv_mark_as_allocated_block - (typename rbtree_best_fit::block_ctrl *block) -{ block->m_allocated = 1; } +template inline +void rbtree_best_fit::priv_mark_as_allocated_block + (typename rbtree_best_fit::block_ctrl *block) +{ + //assert(!priv_is_allocated_block(block)); + block->m_allocated = 1; + ((block_ctrl *)(((char*)block) + block->m_size*Alignment))->m_prev_allocated = 1; +} -template inline -void rbtree_best_fit::priv_mark_as_free_block - (typename rbtree_best_fit::block_ctrl *block) -{ block->m_allocated = 0; } +template inline +void rbtree_best_fit::priv_mark_as_free_block + (typename rbtree_best_fit::block_ctrl *block) +{ + block->m_allocated = 0; + ((block_ctrl *)(((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 inline -void* rbtree_best_fit::priv_check_and_allocate +template inline +void* rbtree_best_fit::priv_check_and_allocate (std::size_t nunits - ,typename rbtree_best_fit::block_ctrl* block + ,typename rbtree_best_fit::block_ctrl* block ,std::size_t &received_size) { std::size_t upper_nunits = nunits + BlockCtrlUnits; @@ -1109,32 +1214,30 @@ void* rbtree_best_fit::priv_check_and_allocate std::size_t block_old_size = block->m_size; block->m_size = nunits; assert(block->m_size >= BlockCtrlUnits); - priv_tail_size(block, block->m_size); //This is the remaining block - block_ctrl *new_block = new(reinterpret_cast + block_ctrl *rem_block = new(reinterpret_cast (detail::char_ptr_cast(block) + Alignment*nunits))block_ctrl; - algo_impl_t::assert_alignment(new_block); - new_block->m_size = block_old_size - nunits; - assert(new_block->m_size >= BlockCtrlUnits); - priv_tail_size(new_block, new_block->m_size); - priv_mark_as_free_block(new_block); + 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 < new_block->m_size){ + || (--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), *new_block); + //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(*new_block); - //block->swap_nodes(*new_block); + //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), *new_block); + 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(), *new_block); + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *rem_block); } } @@ -1148,7 +1251,7 @@ void* rbtree_best_fit::priv_check_and_allocate //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; + received_size = (block->m_size - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk; //Mark the block as allocated priv_mark_as_allocated_block(block); @@ -1157,11 +1260,12 @@ void* rbtree_best_fit::priv_check_and_allocate //cleared with zero_free_memory TreeHook *t = static_cast(block); std::memset(t, 0, sizeof(*t)); + this->priv_next_block(block)->m_prev_size = 0; return priv_get_user_buffer(block); } -template -void rbtree_best_fit::deallocate(void* addr) +template +void rbtree_best_fit::deallocate(void* addr) { if(!addr) return; //----------------------- @@ -1170,8 +1274,8 @@ void rbtree_best_fit::deallocate(void* addr) return this->priv_deallocate(addr); } -template -void rbtree_best_fit::priv_deallocate(void* addr) +template +void rbtree_best_fit::priv_deallocate(void* addr) { if(!addr) return; @@ -1179,7 +1283,7 @@ void rbtree_best_fit::priv_deallocate(void* 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)); +// assert(block->m_size == priv_tail_size(block)); //Check if alignment and block size are right algo_impl_t::assert_alignment(addr); @@ -1194,33 +1298,48 @@ void rbtree_best_fit::priv_deallocate(void* addr) block_ctrl *block_to_insert = block; //Get the next block - block_ctrl *next_block = priv_next_block(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 if the next is free - if(!priv_is_allocated_block(next_block)){ - block->m_size += next_block->m_size; - assert(block->m_size >= BlockCtrlUnits); - priv_tail_size(block, block->m_size); - m_header.m_imultiset.erase(Imultiset::s_iterator_to(*next_block)); + //Merge logic. First just update block sizes, then fix free chunks 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); + } } - - //Get the previous block - block_ctrl *prev_block = priv_prev_block(block); - - //Now check that tail size and control size are equal - assert(prev_block->m_size == priv_tail_size(prev_block)); - - //Merge if the previous is free - if(!priv_is_allocated_block(prev_block)){ - prev_block->m_size += block->m_size; - assert(prev_block->m_size >= BlockCtrlUnits); - priv_tail_size(prev_block, prev_block->m_size); - m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); - block_to_insert = prev_block; + else{ + m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert); } - priv_mark_as_free_block(block_to_insert); - m_header.m_imultiset.insert(m_header.m_imultiset.begin(), *block_to_insert); } } //namespace interprocess { diff --git a/include/boost/interprocess/mem_algo/simple_seq_fit.hpp b/include/boost/interprocess/mem_algo/simple_seq_fit.hpp index 05dd128..dfa2a0e 100644 --- a/include/boost/interprocess/mem_algo/simple_seq_fit.hpp +++ b/include/boost/interprocess/mem_algo/simple_seq_fit.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index 510f61b..c3853a1 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -61,7 +61,7 @@ class offset_ptr typedef void (self_t::*unspecified_bool_type)() const; #if defined(_MSC_VER) && (_MSC_VER >= 1400) - __declspec(noinline) + __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0 #endif void set_offset(const volatile void *ptr) { @@ -77,7 +77,7 @@ class offset_ptr } #if defined(_MSC_VER) && (_MSC_VER >= 1400) - __declspec(noinline) + __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0 #endif void* get_pointer() const { return (m_offset == 1) ? 0 : (detail::char_ptr_cast(this) + m_offset); } diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index b602b85..daf61a8 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // @@ -70,7 +70,8 @@ class segment_manager_base /// @cond //Experimental. Don't use - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; + typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; /// @endcond @@ -148,6 +149,11 @@ class segment_manager_base multiallocation_iterator 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_iterator it) + { MemoryAlgorithm::deallocate_many(it); } + /// @endcond //!Allocates nbytes bytes. Throws boost::interprocess::bad_alloc @@ -189,6 +195,19 @@ class segment_manager_base return ret; } + std::pair + 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 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) @@ -219,6 +238,10 @@ class segment_manager_base 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 diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index 59d25f6..9d2eda3 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/smart_ptr/deleter.hpp b/include/boost/interprocess/smart_ptr/deleter.hpp index 993f879..5909808 100644 --- a/include/boost/interprocess/smart_ptr/deleter.hpp +++ b/include/boost/interprocess/smart_ptr/deleter.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007. +// (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 diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 0ca7a00..1b26426 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -4,7 +4,7 @@ // // (C) Copyright Peter Dimov and Multi Media Ltd. 2001, 2002, 2003 // (C) Copyright Peter Dimov 2004-2005 -// (C) Copyright Ion Gaztanaga 2006-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp index 40cacfe..3fee4e7 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_base_atomic.hpp @@ -9,7 +9,7 @@ // Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. // Copyright 2004-2005 Peter Dimov -// Copyright 2007 Ion Gaztanaga +// Copyright 2007-2008 Ion Gaztanaga // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index 2cc31bf..9566224 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -4,7 +4,7 @@ // // (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. // (C) Copyright Peter Dimov 2001, 2002, 2003 -// (C) Copyright Ion Gaztanaga 2006-2007. +// (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) diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index 979958f..7e48cd7 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -3,7 +3,7 @@ // This file is the adaptation for Interprocess of boost/weak_ptr.hpp // // (C) Copyright Peter Dimov 2001, 2002, 2003 -// (C) Copyright Ion Gaztanaga 2006-2007. +// (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) diff --git a/include/boost/interprocess/streams/bufferstream.hpp b/include/boost/interprocess/streams/bufferstream.hpp index c29e98b..91cb548 100644 --- a/include/boost/interprocess/streams/bufferstream.hpp +++ b/include/boost/interprocess/streams/bufferstream.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/streams/vectorstream.hpp b/include/boost/interprocess/streams/vectorstream.hpp index c75b172..64795b7 100644 --- a/include/boost/interprocess/streams/vectorstream.hpp +++ b/include/boost/interprocess/streams/vectorstream.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index d7bf137..d967809 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp index 036cd04..4ef74c2 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp index fff61b1..83235be 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp b/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp index 23d5963..6c75bfd 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/emulation/named_creation_functor.hpp b/include/boost/interprocess/sync/emulation/named_creation_functor.hpp index aa651a2..1714de7 100644 --- a/include/boost/interprocess/sync/emulation/named_creation_functor.hpp +++ b/include/boost/interprocess/sync/emulation/named_creation_functor.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 1de1407..d9ef89f 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/interprocess_barrier.hpp b/include/boost/interprocess/sync/interprocess_barrier.hpp index 635aa6b..6ba5a66 100644 --- a/include/boost/interprocess/sync/interprocess_barrier.hpp +++ b/include/boost/interprocess/sync/interprocess_barrier.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 6237c29..1ec3f74 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index ee375a8..c7a1ee1 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index 0c902b3..d84be12 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp index a23128b..ccd5ec4 100644 --- a/include/boost/interprocess/sync/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp index ee22e84..c600e4c 100644 --- a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/lock_options.hpp b/include/boost/interprocess/sync/lock_options.hpp index 5161182..dad8f67 100644 --- a/include/boost/interprocess/sync/lock_options.hpp +++ b/include/boost/interprocess/sync/lock_options.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/mutex_family.hpp b/include/boost/interprocess/sync/mutex_family.hpp index 9a7caa6..f31d42c 100644 --- a/include/boost/interprocess/sync/mutex_family.hpp +++ b/include/boost/interprocess/sync/mutex_family.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index 4551025..cfdbe13 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/named_mutex.hpp b/include/boost/interprocess/sync/named_mutex.hpp index e897485..a1f5e21 100644 --- a/include/boost/interprocess/sync/named_mutex.hpp +++ b/include/boost/interprocess/sync/named_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/named_recursive_mutex.hpp b/include/boost/interprocess/sync/named_recursive_mutex.hpp index 84f6018..3d62284 100644 --- a/include/boost/interprocess/sync/named_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/named_recursive_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/named_semaphore.hpp b/include/boost/interprocess/sync/named_semaphore.hpp index 0378d3f..7754750 100644 --- a/include/boost/interprocess/sync/named_semaphore.hpp +++ b/include/boost/interprocess/sync/named_semaphore.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/named_upgradable_mutex.hpp b/include/boost/interprocess/sync/named_upgradable_mutex.hpp index 3c4d97b..853ced4 100644 --- a/include/boost/interprocess/sync/named_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/null_mutex.hpp b/include/boost/interprocess/sync/null_mutex.hpp index fa7a9cf..fac5243 100644 --- a/include/boost/interprocess/sync/null_mutex.hpp +++ b/include/boost/interprocess/sync/null_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/interprocess_condition.hpp b/include/boost/interprocess/sync/posix/interprocess_condition.hpp index 2cc76f0..8ac8c8e 100644 --- a/include/boost/interprocess/sync/posix/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_condition.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp index 06b36b2..692542f 100644 --- a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp index be92550..0701a3e 100644 --- a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp b/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp index 9cf1d12..e55b0fd 100644 --- a/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/pthread_helpers.hpp b/include/boost/interprocess/sync/posix/pthread_helpers.hpp index bd580df..82e61c2 100644 --- a/include/boost/interprocess/sync/posix/pthread_helpers.hpp +++ b/include/boost/interprocess/sync/posix/pthread_helpers.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp b/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp index 67f18d4..80a2f09 100644 --- a/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp +++ b/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp index c6c9663..51d1e57 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index 9792f4d..2e4442c 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index 80ed1cb..1fbe7d1 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 75ef211..6399400 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index 23b2350..c8b3c1a 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2007. Distributed under the Boost +// (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) // diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 8c0bd92..5ccbb82 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -172,6 +172,9 @@ + + @@ -571,6 +574,9 @@ + + node_pool_t; + node_pool_t; if(!test::test_all_node_pool()) return 1; diff --git a/test/adaptive_pool_test.cpp b/test/adaptive_pool_test.cpp index 728c3bf..7b36131 100644 --- a/test/adaptive_pool_test.cpp +++ b/test/adaptive_pool_test.cpp @@ -11,11 +11,13 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; @@ -24,14 +26,36 @@ using namespace boost::interprocess; typedef adaptive_pool shmem_node_allocator_t; +typedef detail::adaptive_pool_v1 + shmem_node_allocator_v1_t; + +//Explicit instantiations to catch compilation errors +template class adaptive_pool; +template class detail::adaptive_pool_v1; + //Alias list types typedef list MyShmList; +typedef list MyShmListV1; + +//Alias vector types +typedef vector MyShmVector; +typedef vector MyShmVectorV1; + int main () { if(test::list_test()) return 1; + if(test::list_test()) + return 1; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + return 0; } diff --git a/test/cached_adaptive_pool_test.cpp b/test/cached_adaptive_pool_test.cpp index 96dcee4..0a0574e 100644 --- a/test/cached_adaptive_pool_test.cpp +++ b/test/cached_adaptive_pool_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; @@ -25,14 +26,37 @@ typedef cached_adaptive_pool cached_node_allocator_t; +typedef detail::cached_adaptive_pool_v1 + + cached_node_allocator_v1_t; + +//Explicit instantiations to catch compilation errors +template class cached_adaptive_pool; +template class detail::cached_adaptive_pool_v1; + + //Alias list types typedef list MyShmList; +typedef list MyShmListV1; + +//Alias vector types +typedef vector MyShmVector; +typedef vector MyShmVectorV1; int main () { if(test::list_test()) return 1; + if(test::list_test()) + return 1; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + return 0; } diff --git a/test/cached_node_allocator_test.cpp b/test/cached_node_allocator_test.cpp index 62ff407..597c90d 100644 --- a/test/cached_node_allocator_test.cpp +++ b/test/cached_node_allocator_test.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2004-2007. Distributed under the Boost +// (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) // @@ -16,23 +16,40 @@ #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; -//We will work with wide characters for shared memory objects //Alias a integer node allocator type typedef cached_node_allocator cached_node_allocator_t; +typedef detail::cached_node_allocator_v1 + + cached_node_allocator_v1_t; + +//Explicit instantiations to catch compilation errors +template class cached_node_allocator; +template class detail::cached_node_allocator_v1; //Alias list types typedef list MyShmList; +typedef list MyShmListV1; + +//Alias vector types +typedef vector MyShmVector; +typedef vector MyShmVectorV1; int main () { if(test::list_test()) return 1; - + if(test::list_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; return 0; } diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 53182d1..b9851c9 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/test/map_test.hpp b/test/map_test.hpp index 899773c..4d9902f 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -296,6 +296,8 @@ int map_test () } //Now do count exercise + shmmap->erase(shmmap->begin(), shmmap->end()); + shmmultimap->erase(shmmultimap->begin(), shmmultimap->end()); shmmap->clear(); shmmultimap->clear(); diff --git a/test/memory_algorithm_test.cpp b/test/memory_algorithm_test.cpp index 036d5b7..fa93ec2 100644 --- a/test/memory_algorithm_test.cpp +++ b/test/memory_algorithm_test.cpp @@ -19,47 +19,67 @@ #include #include "get_process_id_name.hpp" +using namespace boost::interprocess; + +const int memsize = 16384; +const char *const shMemName = test::get_process_id_name(); + +int test_simple_seq_fit() +{ + //A shared memory with simple sequential fit algorithm + typedef basic_managed_shared_memory + + ,null_index + > my_managed_shared_memory; + + //Create shared memory + shared_memory_object::remove(shMemName); + my_managed_shared_memory segment(create_only, shMemName, memsize); + + //Now take the segment manager and launch memory test + if(!test::test_all_allocation(*segment.get_segment_manager())){ + return 1; + } + return 0; +} + +template +int test_rbtree_best_fit() +{ + //A shared memory with red-black tree best fit algorithm + typedef basic_managed_shared_memory + , Alignment> + ,null_index + > my_managed_shared_memory; + + //Create shared memory + shared_memory_object::remove(shMemName); + my_managed_shared_memory segment(create_only, shMemName, memsize); + + //Now take the segment manager and launch memory test + if(!test::test_all_allocation(*segment.get_segment_manager())){ + return 1; + } + return 0; +} + int main () { - using namespace boost::interprocess; - const int memsize = 16384; - const char *const shMemName = test::get_process_id_name(); - - { - //A shared memory with simple sequential fit algorithm - typedef basic_managed_shared_memory - - ,null_index - > my_managed_shared_memory; - - //Create shared memory - shared_memory_object::remove(shMemName); - my_managed_shared_memory segment(create_only, shMemName, memsize); - - //Now take the segment manager and launch memory test - if(!test::test_all_allocation(*segment.get_segment_manager())){ - return 1; - } + if(test_simple_seq_fit()){ + return 1; + } + if(test_rbtree_best_fit<4>()){ + return 1; + } + if(test_rbtree_best_fit<8>()){ + return 1; + } + if(test_rbtree_best_fit<16>()){ + return 1; } - { - //A shared memory with red-black tree best fit algorithm - typedef basic_managed_shared_memory - - ,null_index - > my_managed_shared_memory; - - //Create shared memory - shared_memory_object::remove(shMemName); - my_managed_shared_memory segment(create_only, shMemName, memsize); - - //Now take the segment manager and launch memory test - if(!test::test_all_allocation(*segment.get_segment_manager())){ - return 1; - } - } shared_memory_object::remove(shMemName); return 0; } diff --git a/test/memory_algorithm_test_template.hpp b/test/memory_algorithm_test_template.hpp index 817283f..29a85ef 100644 --- a/test/memory_algorithm_test_template.hpp +++ b/test/memory_algorithm_test_template.hpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include //std::memset #include //std::remove namespace boost { namespace interprocess { namespace test { @@ -38,6 +38,8 @@ bool test_allocation(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers.push_back(ptr); } @@ -94,6 +96,8 @@ bool test_allocation_shrink(Allocator &a) void *ptr = a.allocate(i*2, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers.push_back(ptr); } @@ -111,6 +115,7 @@ bool test_allocation_shrink(Allocator &a) if(received_size < std::size_t(i)){ return false; } + std::memset(buffers[i], 0, a.size(buffers[i])); } } @@ -139,6 +144,8 @@ bool test_allocation_expand(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers.push_back(ptr); } @@ -203,7 +210,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) //Now shrink to half for(int i = 0, max = (int)buffers.size() - ;i < max + ; i < max ; ++i){ std::size_t received_size; if(a.template allocation_command @@ -224,9 +231,10 @@ bool test_allocation_shrink_and_expand(Allocator &a) ;i < max ;++i){ std::size_t received_size; + std::size_t request_size = received_sizes[i]; if(a.template allocation_command - ( expand_fwd | nothrow_allocation, received_sizes[i] - , received_sizes[i], received_size, (char*)buffers[i]).first){ + ( expand_fwd | nothrow_allocation, request_size + , request_size, received_size, (char*)buffers[i]).first){ if(received_size != received_sizes[i]){ return false; } @@ -262,6 +270,8 @@ bool test_allocation_deallocation_expand(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers.push_back(ptr); } @@ -327,19 +337,21 @@ template bool test_allocation_with_reuse(Allocator &a) { //We will repeat this test for different sized elements - for(int size = 1; size < 20; ++size){ + for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){ std::vector buffers; //Allocate buffers with extra memory for(int i = 0; true; ++i){ - void *ptr = a.allocate(i*size, std::nothrow); + void *ptr = a.allocate(i*sizeof_object, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers.push_back(ptr); } //Now deallocate all except the latest - //Now try to expand to the double of the size + //Now try to expand to the double of the sizeof_object for(int i = 0, max = (int)buffers.size() - 1 ;i < max ;++i){ @@ -353,14 +365,18 @@ bool test_allocation_with_reuse(Allocator &a) //Now allocate with reuse std::size_t received_size = 0; for(int i = 0; true; ++i){ - std::pair ret = a.template allocation_command - ( expand_bwd | nothrow_allocation, received_size/size*size + size - , received_size/size*size+(i+1)*size*2, received_size, (char*)ptr); + std::size_t min_size = (received_size + 1); + std::size_t prf_size = (received_size + (i+1)*2); + std::pair ret = a.raw_allocation_command + ( expand_bwd | nothrow_allocation, min_size + , prf_size, received_size, (char*)ptr, sizeof_object); if(!ret.first) break; //If we have memory, this must be a buffer reuse if(!ret.second) return 1; + if(received_size < min_size) + return 1; ptr = ret.first; } //There is only a single block so deallocate it @@ -456,6 +472,8 @@ bool test_clear_free_memory(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 1, size); buffers.push_back(ptr); } @@ -544,6 +562,8 @@ bool test_grow_shrink_to_fit(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers.push_back(ptr); } @@ -564,7 +584,11 @@ bool test_grow_shrink_to_fit(Allocator &a) for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ - int pos = (j%4)*((int)buffers.size())/4; + int pos = (j%5)*((int)buffers.size())/4; + if(pos == int(buffers.size())) + --pos; + a.deallocate(buffers[pos]); + buffers.erase(buffers.begin()+pos); std::size_t old_free = a.get_free_memory(); a.shrink_to_fit(); if(!a.check_sanity()) return false; @@ -576,9 +600,6 @@ bool test_grow_shrink_to_fit(Allocator &a) if(!a.check_sanity()) return false; if(original_size != a.get_size()) return false; if(old_free != a.get_free_memory()) return false; - - a.deallocate(buffers[pos]); - buffers.erase(buffers.begin()+pos); } //Now shrink it to the maximum @@ -623,6 +644,8 @@ bool test_many_equal_allocation(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); if(!a.check_sanity()) return false; buffers2.push_back(ptr); @@ -736,6 +759,8 @@ bool test_many_different_allocation(Allocator &a) void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; + std::size_t size = a.size(ptr); + std::memset(ptr, 0, size); buffers2.push_back(ptr); } @@ -816,6 +841,57 @@ bool test_many_different_allocation(Allocator &a) return true; } +//This test allocates multiple values until there is no more memory +//and after that deallocates all in the inverse order +template +bool test_many_deallocation(Allocator &a) +{ + typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + const std::size_t ArraySize = 11; + std::vector buffers; + std::size_t requested_sizes[ArraySize]; + for(std::size_t i = 0; i < ArraySize; ++i){ + requested_sizes[i] = 4*i; + } + std::size_t free_memory = a.get_free_memory(); + + { + for(int i = 0; true; ++i){ + multiallocation_iterator it = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); + if(!it) + break; + buffers.push_back(it); + } + for(int i = 0, max = (int)buffers.size(); i != max; ++i){ + a.deallocate_many(buffers[i]); + } + buffers.clear(); + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + + { + for(int i = 0; true; ++i){ + multiallocation_iterator it = a.allocate_many(i*4, ArraySize, std::nothrow); + if(!it) + break; + buffers.push_back(it); + } + for(int i = 0, max = (int)buffers.size(); i != max; ++i){ + a.deallocate_many(buffers[i]); + } + buffers.clear(); + + bool ok = free_memory == a.get_free_memory() && + a.all_memory_deallocated() && a.check_sanity(); + if(!ok) return ok; + } + + return true; +} + + //This function calls all tests template bool test_all_allocation(Allocator &a) @@ -847,6 +923,12 @@ bool test_all_allocation(Allocator &a) return false; } + if(!test_many_deallocation(a)){ + std::cout << "test_many_deallocation failed. Class: " + << typeid(a).name() << std::endl; + return false; + } + std::cout << "Starting test_allocation_shrink. Class: " << typeid(a).name() << std::endl; diff --git a/test/node_allocator_test.cpp b/test/node_allocator_test.cpp index 486f4b6..dbe7b5d 100644 --- a/test/node_allocator_test.cpp +++ b/test/node_allocator_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; @@ -23,15 +24,31 @@ using namespace boost::interprocess; //Alias a integer node allocator type typedef node_allocator shmem_node_allocator_t; +typedef detail::node_allocator_v1 + shmem_node_allocator_v1_t; + +//Explicit instantiations to catch compilation errors +template class node_allocator; +template class detail::node_allocator_v1; //Alias list types typedef list MyShmList; +typedef list MyShmListV1; + +//Alias vector types +typedef vector MyShmVector; +typedef vector MyShmVectorV1; int main () { if(test::list_test()) return 1; - + if(test::list_test()) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; return 0; } diff --git a/test/node_pool_test.hpp b/test/node_pool_test.hpp index e4bc832..2e2b608 100644 --- a/test/node_pool_test.hpp +++ b/test/node_pool_test.hpp @@ -42,7 +42,7 @@ bool test_node_pool::allocate_then_deallocate(NodePool &pool) //First allocate nodes for(std::size_t i = 0; i < num_alloc; ++i){ - nodes.push_back(pool.allocate(1)); + nodes.push_back(pool.allocate_node()); } //Check that the free count is correct @@ -52,7 +52,7 @@ bool test_node_pool::allocate_then_deallocate(NodePool &pool) //Now deallocate all and check again for(std::size_t i = 0; i < num_alloc; ++i){ - pool.deallocate(nodes[i], 1); + pool.deallocate_node(nodes[i]); } //Check that the free count is correct @@ -85,7 +85,7 @@ bool test_node_pool::deallocate_free_chunks(NodePool &pool) //First allocate nodes for(std::size_t i = 0; i < max_nodes; ++i){ - nodes.push_back(pool.allocate(1)); + nodes.push_back(pool.allocate_node()); } //Check that the free count is correct @@ -97,7 +97,7 @@ bool test_node_pool::deallocate_free_chunks(NodePool &pool) for(std::size_t node_i = 0; node_i < nodes_per_chunk; ++node_i){ //Deallocate a node per chunk for(std::size_t i = 0; i < max_chunks; ++i){ - pool.deallocate(nodes[i*nodes_per_chunk + node_i], 1); + pool.deallocate_node(nodes[i*nodes_per_chunk + node_i]); } //Check that the free count is correct diff --git a/test/private_adaptive_pool_test.cpp b/test/private_adaptive_pool_test.cpp index c46f9ae..a914e83 100644 --- a/test/private_adaptive_pool_test.cpp +++ b/test/private_adaptive_pool_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; @@ -23,15 +24,31 @@ using namespace boost::interprocess; //Alias a private adaptive pool that allocates ints typedef private_adaptive_pool priv_node_allocator_t; +typedef detail::private_adaptive_pool_v1 + priv_node_allocator_v1_t; + +//Explicit instantiations to catch compilation errors +template class private_adaptive_pool; +template class detail::private_adaptive_pool_v1; //Alias list types typedef list MyShmList; +typedef list MyShmListV1; + +//Alias vector types +typedef vector MyShmVector; +typedef vector MyShmVectorV1; int main () { if(test::list_test(false)) return 1; - + if(test::list_test(false)) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; return 0; } diff --git a/test/private_node_allocator_test.cpp b/test/private_node_allocator_test.cpp index fd125c2..4190c6a 100644 --- a/test/private_node_allocator_test.cpp +++ b/test/private_node_allocator_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "movable_int.hpp" #include "list_test.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; @@ -23,15 +24,31 @@ using namespace boost::interprocess; //Alias a integer node allocator type typedef private_node_allocator priv_node_allocator_t; +typedef detail::private_node_allocator_v1 + priv_node_allocator_v1_t; + +//Explicit instantiations to catch compilation errors +template class private_node_allocator; +template class detail::private_node_allocator_v1; //Alias list types -typedef list MyShmList; +typedef list MyShmList; +typedef list MyShmListV1; + +//Alias vector types +typedef vector MyShmVector; +typedef vector MyShmVectorV1; int main () { if(test::list_test(false)) return 1; - + if(test::list_test(false)) + return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) + return 1; return 0; } diff --git a/test/set_test.hpp b/test/set_test.hpp index 01c90f6..f35ccee 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -384,6 +384,8 @@ int set_test () } //Now do count exercise + shmset->erase(shmset->begin(), shmset->end()); + shmmultiset->erase(shmmultiset->begin(), shmmultiset->end()); shmset->clear(); shmmultiset->clear(); diff --git a/test/vector_test.cpp b/test/vector_test.cpp index f6e9031..0e76115 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -17,227 +17,22 @@ #include #include -#include #include #include "allocator_v1.hpp" -#include -#include -#include -#include "print_container.hpp" #include "check_equal_containers.hpp" #include "movable_int.hpp" #include "expand_bwd_test_allocator.hpp" #include "expand_bwd_test_template.hpp" #include "dummy_test_allocator.hpp" -#include -#include "get_process_id_name.hpp" +#include "vector_test.hpp" using namespace boost::interprocess; -typedef basic_managed_shared_memory - , - flat_map_index - > managed_shared_memory_t; - //Explicit instantiation to detect compilation errors template class boost::interprocess::vector >; -template -bool copyable_only(V1 *, V2 *, detail::false_type) -{ - return true; -} - -//Function to check if both sets are equal -template -bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) -{ - typedef typename V1::value_type IntType; - std::size_t size = shmvector->size(); - stdvector->insert(stdvector->end(), 50, 1); - shmvector->insert(shmvector->end(), 50, 1); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - { - IntType move_me(1); - stdvector->insert(stdvector->begin()+size/2, 50, 1); - shmvector->insert(shmvector->begin()+size/2, 50, move(move_me)); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - } - { - IntType move_me(2); - shmvector->assign(shmvector->size()/2, move(move_me)); - stdvector->assign(stdvector->size()/2, 2); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - } - { - IntType move_me(3); - shmvector->assign(shmvector->size()*3-1, move(move_me)); - stdvector->assign(stdvector->size()*3-1, 3); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - } - return true; -} - -template class AllocatorType > -bool do_test() -{ - //Customize managed_shared_memory class - typedef basic_managed_shared_memory - , - rbtree_best_fit, - flat_map_index - > my_managed_shared_memory; - - //Alias AllocatorType type - typedef AllocatorType - shmem_allocator_t; - - //Alias vector types - typedef vector MyShmVector; - typedef std::vector MyStdVector; - - std::string process_name; - test::get_process_id_name(process_name); - - const int Memsize = 65536; - const char *const shMemName = process_name.c_str(); - const int max = 100; - - { - //Compare several shared memory vector operations with std::vector - //Create shared memory - shared_memory_object::remove(shMemName); - try{ - my_managed_shared_memory segment(create_only, shMemName, Memsize); - - segment.reserve_named_objects(100); - - //Shared memory allocator must be always be initialized - //since it has no default constructor - MyShmVector *shmvector = segment.template construct("MyShmVector") - (segment.get_segment_manager()); - MyStdVector *stdvector = new MyStdVector; - - shmvector->resize(100); - stdvector->resize(100); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - shmvector->resize(200); - stdvector->resize(200); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - shmvector->resize(0); - stdvector->resize(0); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - for(int i = 0; i < max; ++i){ - IntType new_int(i); - shmvector->insert(shmvector->end(), move(new_int)); - stdvector->insert(stdvector->end(), i); - } - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - typename MyShmVector::iterator shmit(shmvector->begin()); - typename MyStdVector::iterator stdit(stdvector->begin()); - typename MyShmVector::const_iterator cshmit = shmit; - ++shmit; ++stdit; - shmvector->erase(shmit); - stdvector->erase(stdit); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - shmvector->erase(shmvector->begin()); - stdvector->erase(stdvector->begin()); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - { - //Initialize values - IntType aux_vect[50]; - for(int i = 0; i < 50; ++i){ - IntType new_int(-1); - aux_vect[i] = move(new_int); - } - int aux_vect2[50]; - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - - shmvector->insert(shmvector->end() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); - stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - for(int i = 0, j = static_cast(shmvector->size()); i < j; ++i){ - shmvector->erase(shmvector->begin()); - stdvector->erase(stdvector->begin()); - } - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - } - { - IntType aux_vect[50]; - for(int i = 0; i < 50; ++i){ - IntType new_int(-1); - aux_vect[i] = move(new_int); - } - int aux_vect2[50]; - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - shmvector->insert(shmvector->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); - stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - } - - shmvector->reserve(shmvector->size()*2); - stdvector->reserve(stdvector->size()*2); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - IntType push_back_this(1); - shmvector->push_back(move(push_back_this)); - stdvector->push_back(int(1)); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - if(!copyable_only(shmvector, stdvector - ,detail::bool_::value>())){ - return false; - } - - shmvector->erase(shmvector->begin()); - stdvector->erase(stdvector->begin()); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - for(int i = 0; i < max; ++i){ - IntType insert_this(i); - shmvector->insert(shmvector->begin(), move(insert_this)); - stdvector->insert(stdvector->begin(), i); - } - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; - - delete stdvector; - segment.template destroy("MyShmVector"); - segment.shrink_to_fit_indexes(); - - if(!segment.all_memory_deallocated()) - return false; - } - catch(std::exception &ex){ - shared_memory_object::remove(shMemName); - std::cout << ex.what() << std::endl; - return false; - } - } - shared_memory_object::remove(shMemName); - std::cout << std::endl << "Test OK!" << std::endl; - return true; -} - -bool test_expand_bwd() +int test_expand_bwd() { //Now test all back insertion possibilities @@ -248,7 +43,7 @@ bool test_expand_bwd() int_vector; if(!test::test_all_expand_bwd()) - return false; + return 1; //Now user defined wrapped int typedef test::expand_bwd_test_allocator @@ -257,7 +52,7 @@ bool test_expand_bwd() int_holder_vector; if(!test::test_all_expand_bwd()) - return false; + return 1; //Now user defined bigger wrapped int typedef test::expand_bwd_test_allocator @@ -267,26 +62,32 @@ bool test_expand_bwd() triple_int_holder_vector; if(!test::test_all_expand_bwd()) - return false; + return 1; - return true; + return 0; } int main() { - if(!do_test()) + typedef allocator ShmemAllocator; + typedef vector MyVector; + + typedef allocator ShmemMoveAllocator; + typedef vector MyMoveVector; + + typedef allocator ShmemCopyMoveAllocator; + typedef vector MyCopyMoveVector; + + if(test::vector_test()) return 1; - if(!do_test()) + if(test::vector_test()) return 1; - if(!do_test()) + if(test::vector_test()) return 1; - if(!do_test()) - return 1; - - if(!test_expand_bwd()) + if(test_expand_bwd()) return 1; return 0; diff --git a/test/vector_test.hpp b/test/vector_test.hpp new file mode 100644 index 0000000..3d76790 --- /dev/null +++ b/test/vector_test.hpp @@ -0,0 +1,219 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-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. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "print_container.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include +#include "get_process_id_name.hpp" + +namespace boost{ +namespace interprocess{ +namespace test{ + +template +bool copyable_only(V1 *, V2 *, detail::false_type) +{ + return true; +} + +//Function to check if both sets are equal +template +bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) +{ + typedef typename V1::value_type IntType; + std::size_t size = shmvector->size(); + stdvector->insert(stdvector->end(), 50, 1); + shmvector->insert(shmvector->end(), 50, 1); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + + { + IntType move_me(1); + stdvector->insert(stdvector->begin()+size/2, 50, 1); + shmvector->insert(shmvector->begin()+size/2, 50, move(move_me)); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + } + { + IntType move_me(2); + shmvector->assign(shmvector->size()/2, move(move_me)); + stdvector->assign(stdvector->size()/2, 2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + } + { + IntType move_me(3); + shmvector->assign(shmvector->size()*3-1, move(move_me)); + stdvector->assign(stdvector->size()*3-1, 3); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + } + return true; +} + +template +int vector_test() +{ + typedef std::vector MyStdVector; + typedef typename MyShmVector::value_type IntType; + + std::string process_name; + test::get_process_id_name(process_name); + + const int Memsize = 65536; + const char *const shMemName = process_name.c_str(); + const int max = 100; + + { + //Compare several shared memory vector operations with std::vector + //Create shared memory + shared_memory_object::remove(shMemName); + try{ + ManagedSharedMemory segment(create_only, shMemName, Memsize); + + segment.reserve_named_objects(100); + + //Shared memory allocator must be always be initialized + //since it has no default constructor + MyShmVector *shmvector = segment.template construct("MyShmVector") + (segment.get_segment_manager()); + MyStdVector *stdvector = new MyStdVector; + + shmvector->resize(100); + stdvector->resize(100); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + shmvector->resize(200); + stdvector->resize(200); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + shmvector->resize(0); + stdvector->resize(0); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + for(int i = 0; i < max; ++i){ + IntType new_int(i); + shmvector->insert(shmvector->end(), move(new_int)); + stdvector->insert(stdvector->end(), i); + } + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + typename MyShmVector::iterator shmit(shmvector->begin()); + typename MyStdVector::iterator stdit(stdvector->begin()); + typename MyShmVector::const_iterator cshmit = shmit; + ++shmit; ++stdit; + shmvector->erase(shmit); + stdvector->erase(stdit); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + shmvector->erase(shmvector->begin()); + stdvector->erase(stdvector->begin()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + { + //Initialize values + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType new_int(-1); + aux_vect[i] = move(new_int); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + + shmvector->insert(shmvector->end() + ,detail::make_move_iterator(&aux_vect[0]) + ,detail::make_move_iterator(aux_vect + 50)); + stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + for(int i = 0, j = static_cast(shmvector->size()); i < j; ++i){ + shmvector->erase(shmvector->begin()); + stdvector->erase(stdvector->begin()); + } + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } + { + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + IntType new_int(-1); + aux_vect[i] = move(new_int); + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = -1; + } + shmvector->insert(shmvector->begin() + ,detail::make_move_iterator(&aux_vect[0]) + ,detail::make_move_iterator(aux_vect + 50)); + stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } + + shmvector->reserve(shmvector->size()*2); + stdvector->reserve(stdvector->size()*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + IntType push_back_this(1); + shmvector->push_back(move(push_back_this)); + stdvector->push_back(int(1)); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + if(!copyable_only(shmvector, stdvector + ,detail::bool_::value>())){ + return 1; + } + + shmvector->erase(shmvector->begin()); + stdvector->erase(stdvector->begin()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + for(int i = 0; i < max; ++i){ + IntType insert_this(i); + shmvector->insert(shmvector->begin(), move(insert_this)); + stdvector->insert(stdvector->begin(), i); + } + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + + delete stdvector; + segment.template destroy("MyShmVector"); + segment.shrink_to_fit_indexes(); + + if(!segment.all_memory_deallocated()) + return 1; + } + catch(std::exception &ex){ + shared_memory_object::remove(shMemName); + std::cout << ex.what() << std::endl; + return 1; + } + } + shared_memory_object::remove(shMemName); + std::cout << std::endl << "Test OK!" << std::endl; + return 0; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include From 59fbc2d90acd746c68a6b4b25f698a333102d8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 22 Jan 2008 16:49:22 +0000 Subject: [PATCH 09/77] Refactor some allocation code and fix instantiation problem in 64 bit platforms [SVN r42911] --- .../interprocess/allocators/allocator.hpp | 9 +- .../allocators/detail/adaptive_node_pool.hpp | 156 ++++++++++-------- .../allocators/detail/node_pool.hpp | 53 +++--- .../boost/interprocess/detail/utilities.hpp | 48 +++++- .../mem_algo/detail/mem_algo_common.hpp | 98 ++++------- test/memory_algorithm_test.cpp | 8 +- 6 files changed, 197 insertions(+), 175 deletions(-) diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 9d7ce2d..7ce825b 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -101,10 +101,11 @@ class allocator typedef transform_iterator < typename SegmentManager:: multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; - + , detail::cast_functor > multiallocation_iterator; + typedef detail::multiallocation_chain_adaptor + multiallocation_chain; /// @endcond //!Obtains an allocator that allocates diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 02dca7a..136d29d 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -186,39 +186,11 @@ class private_adaptive_node_pool_impl //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - priv_invariants(); - chunk_info_t *chunk_info = priv_chunk_from_node(pElem); - assert(chunk_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(pElem); - chunk_info->free_nodes.push_front(*to_deallocate); - - chunk_iterator this_chunk(chunk_multiset_t::s_iterator_to(*chunk_info)); - chunk_iterator next_chunk(this_chunk); - ++next_chunk; - - //Cache the free nodes from the chunk - std::size_t this_chunk_free_nodes = this_chunk->free_nodes.size(); - - if(this_chunk_free_nodes == 1){ - m_chunk_multiset.insert(m_chunk_multiset.begin(), *chunk_info); - } - else{ - chunk_iterator next_chunk(this_chunk); - ++next_chunk; - if(next_chunk != m_chunk_multiset.end()){ - std::size_t next_free_nodes = next_chunk->free_nodes.size(); - if(this_chunk_free_nodes > next_free_nodes){ - //Now move the chunk to the new position - m_chunk_multiset.erase(this_chunk); - m_chunk_multiset.insert(*chunk_info); - } - } - } + this->priv_reinsert_nodes_in_chunk + (multiallocation_iterator::create_simple_range(pElem)); //Update free chunk count - if(this_chunk_free_nodes == m_real_num_node){ - ++m_totally_free_chunks; - priv_deallocate_free_chunks(m_max_free_chunks); + if(m_totally_free_chunks > m_max_free_chunks){ + this->priv_deallocate_free_chunks(m_max_free_chunks); } priv_invariants(); } @@ -239,8 +211,8 @@ class private_adaptive_node_pool_impl } } catch(...){ - priv_deallocate_nodes(nodes, nodes.size()); - priv_deallocate_free_chunks(m_max_free_chunks); + this->deallocate_nodes(nodes, nodes.size()); + this->priv_deallocate_free_chunks(m_max_free_chunks); throw; } //remove me @@ -259,25 +231,31 @@ class private_adaptive_node_pool_impl //!Deallocates a linked list of nodes. Never throws void deallocate_nodes(multiallocation_chain &nodes) - { priv_deallocate_nodes(nodes, nodes.size()); } + { + this->deallocate_nodes(nodes.get_it()); + nodes.reset(); + } //!Deallocates the first n nodes of a linked list of nodes. Never throws void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) - { priv_deallocate_nodes(nodes, n); } + { + assert(nodes.size() >= n); + for(std::size_t i = 0; i < n; ++i){ + this->deallocate_node(nodes.pop_front()); + } + } //!Deallocates the nodes pointed by the multiallocation iterator. Never throws void deallocate_nodes(multiallocation_iterator it) { - multiallocation_iterator itend; - while(it != itend){ - void *addr = &*it; - ++it; - deallocate_node(addr); + this->priv_reinsert_nodes_in_chunk(it); + if(m_totally_free_chunks > m_max_free_chunks){ + this->priv_deallocate_free_chunks(m_max_free_chunks); } } void deallocate_free_chunks() - { priv_deallocate_free_chunks(0); } + { this->priv_deallocate_free_chunks(0); } std::size_t num_free_nodes() { @@ -302,6 +280,71 @@ class private_adaptive_node_pool_impl } private: + void priv_deallocate_free_chunks(std::size_t max_free_chunks) + { + priv_invariants(); + //Now check if we've reached the free nodes limit + //and check if we have free chunks. If so, deallocate as much + //as we can to stay below the limit + for( chunk_iterator itend = m_chunk_multiset.end() + ; m_totally_free_chunks > max_free_chunks + ; --m_totally_free_chunks + ){ + assert(!m_chunk_multiset.empty()); + chunk_iterator it = itend; + --it; + std::size_t num_nodes = it->free_nodes.size(); + assert(num_nodes == m_real_num_node); + (void)num_nodes; + m_chunk_multiset.erase_and_dispose + (it, chunk_destroyer(this)); + } + } + + void priv_reinsert_nodes_in_chunk(multiallocation_iterator it) + { + multiallocation_iterator itend; + chunk_iterator chunk_it(m_chunk_multiset.end()); + while(it != itend){ + void *pElem = &*it; + ++it; + priv_invariants(); + chunk_info_t *chunk_info = this->priv_chunk_from_node(pElem); + assert(chunk_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(pElem); + chunk_info->free_nodes.push_front(*to_deallocate); + + chunk_iterator this_chunk(chunk_multiset_t::s_iterator_to(*chunk_info)); + chunk_iterator next_chunk(this_chunk); + ++next_chunk; + + //Cache the free nodes from the chunk + std::size_t this_chunk_free_nodes = this_chunk->free_nodes.size(); + + if(this_chunk_free_nodes == 1){ + m_chunk_multiset.insert(m_chunk_multiset.begin(), *chunk_info); + } + else{ + chunk_iterator next_chunk(this_chunk); + ++next_chunk; + if(next_chunk != chunk_it){ + std::size_t next_free_nodes = next_chunk->free_nodes.size(); + if(this_chunk_free_nodes > next_free_nodes){ + //Now move the chunk to the new position + m_chunk_multiset.erase(this_chunk); + m_chunk_multiset.insert(*chunk_info); + } + } + } + //Update free chunk count + if(this_chunk_free_nodes == m_real_num_node){ + ++m_totally_free_chunks; + } + priv_invariants(); + } + } + node_t *priv_take_first_node() { assert(m_chunk_multiset.begin() != m_chunk_multiset.end()); @@ -321,14 +364,6 @@ class private_adaptive_node_pool_impl return first_node; } - void priv_deallocate_nodes(multiallocation_chain &nodes, const std::size_t num) - { - assert(nodes.size() >= num); - for(std::size_t i = 0; i < num; ++i){ - deallocate_node(nodes.pop_front()); - } - } - class chunk_destroyer; friend class chunk_destroyer; @@ -451,27 +486,6 @@ class private_adaptive_node_pool_impl return hdr_off_holder; } - void priv_deallocate_free_chunks(std::size_t max_free_chunks) - { - priv_invariants(); - //Now check if we've reached the free nodes limit - //and check if we have free chunks. If so, deallocate as much - //as we can to stay below the limit - for( chunk_iterator itend = m_chunk_multiset.end() - ; m_totally_free_chunks > max_free_chunks - ; --m_totally_free_chunks - ){ - assert(!m_chunk_multiset.empty()); - chunk_iterator it = itend; - --it; - std::size_t num_nodes = it->free_nodes.size(); - assert(num_nodes == m_real_num_node); - (void)num_nodes; - m_chunk_multiset.erase_and_dispose - (it, chunk_destroyer(this)); - } - } - //!Allocates a several chunks of nodes. Can throw boost::interprocess::bad_alloc void priv_alloc_chunk(std::size_t n) { diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index ce2c74b..cfcbcf8 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -91,11 +91,26 @@ class private_node_pool_impl //!Allocates array of count elements. Can throw boost::interprocess::bad_alloc void *allocate_node() - { return priv_alloc_node(); } + { + //If there are no free nodes we allocate a new block + if (m_freelist.empty()) + priv_alloc_chunk(); + //We take the first free node + node_t *n = (node_t*)&m_freelist.front(); + m_freelist.pop_front(); + ++m_allocated; + return n; + } //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *ptr) - { priv_dealloc_node(ptr); } + { + //We put the node at the beginning of the free node list + node_t * to_deallocate = static_cast(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 and pushes them in the chain. //!can throw boost::interprocess::bad_alloc @@ -104,7 +119,7 @@ class private_node_pool_impl std::size_t i = 0; try{ for(; i < n; ++i){ - nodes.push_front(priv_alloc_node()); + nodes.push_front(this->allocate_node()); } } catch(...){ @@ -121,7 +136,7 @@ class private_node_pool_impl std::size_t i = 0; try{ for(; i < n; ++i){ - nodes.push_front(priv_alloc_node()); + nodes.push_front(this->allocate_node()); } } catch(...){ @@ -133,7 +148,10 @@ class private_node_pool_impl //!Deallocates a linked list of nodes. Never throws void deallocate_nodes(multiallocation_chain &nodes) - { this->deallocate_nodes(nodes.get_it()); } + { + this->deallocate_nodes(nodes.get_it()); + nodes.reset(); + } //!Deallocates the first n nodes of a linked list of nodes. Never throws void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) @@ -287,31 +305,6 @@ class private_node_pool_impl const char * end_; }; - //!Allocates one node, using single segregated storage algorithm. - //!Never throws - node_t *priv_alloc_node() - { - //If there are no free nodes we allocate a new block - if (m_freelist.empty()) - priv_alloc_chunk(); - //We take the first free node - node_t *n = (node_t*)&m_freelist.front(); - m_freelist.pop_front(); - ++m_allocated; - return n; - } - - //!Deallocates one node, using single segregated storage algorithm. - //!Never throws - void priv_dealloc_node(void *pElem) - { - //We put the node at the beginning of the free node list - node_t * to_deallocate = static_cast(pElem); - m_freelist.push_front(*to_deallocate); - assert(m_allocated>0); - --m_allocated; - } - //!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc void priv_alloc_chunk() { diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index 0e507f8..7cb2eef 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -678,6 +678,52 @@ struct cast_functor { return *static_cast(static_cast(&ptr)); } }; +template +class multiallocation_chain_adaptor +{ + private: + MultiallocChain chain_; + + multiallocation_chain_adaptor + (const multiallocation_chain_adaptor &); + multiallocation_chain_adaptor &operator= + (const multiallocation_chain_adaptor &); + + public: + typedef transform_iterator + < typename MultiallocChain:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + + multiallocation_chain_adaptor() + : chain_() + {} + + void push_back(T *mem) + { chain_.push_back(mem); } + + void push_front(T *mem) + { chain_.push_front(mem); } + + void swap(multiallocation_chain_adaptor &other_chain) + { chain_.swap(other_chain.chain_); } + + void splice_back(multiallocation_chain_adaptor &other_chain) + { chain_.splice_back(other_chain.chain_); } + + T *pop_front() + { return static_cast(chain_.pop_front()); } + + bool empty() const + { return chain_.empty(); } + + multiallocation_iterator get_it() const + { return multiallocation_iterator(chain_.get_it()); } + + std::size_t size() const + { return chain_.size(); } +}; + } //namespace detail { //!The pair is movable if any of its members is movable diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index acd2c16..8c776ff 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -100,6 +101,16 @@ class basic_multiallocation_iterator pointer operator->() const { return &(*(*this)); } + static basic_multiallocation_iterator create_simple_range(void *mem) + { + basic_multiallocation_iterator it; + typedef multi_allocation_next next_impl_t; + next_impl_t * tmp_mem = static_cast(mem); + it = basic_multiallocation_iterator(tmp_mem); + tmp_mem->next_ = 0; + return it; + } + private: multi_allocation_next next_alloc_; }; @@ -122,6 +133,13 @@ class basic_multiallocation_chain : it_(0), last_mem_(0), num_mem_(0) {} + void reset() + { + this->it_ = multiallocation_iterator(); + this->last_mem_ = 0; + this->num_mem_ = 0; + } + void push_back(void *mem) { typedef multi_allocation_next next_impl_t; @@ -138,35 +156,21 @@ class basic_multiallocation_chain ++num_mem_; } - void push_back(multiallocation_iterator it, std::size_t n) - { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = (next_impl_t*)(&*it); - - if(!this->last_mem_){ - this->it_ = it; - } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; - } - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - ++num_mem_; - } - void push_front(void *mem) { typedef multi_allocation_next next_impl_t; - + next_impl_t * tmp_mem = static_cast(mem); + ++num_mem_; + if(!this->last_mem_){ - push_back(mem); + this->it_ = basic_multiallocation_iterator(tmp_mem); + tmp_mem->next_ = 0; + this->last_mem_ = tmp_mem; } else{ - next_impl_t * tmp_mem = static_cast(mem); next_impl_t * old_first = (next_impl_t*)(&*this->it_); - static_cast(mem)->next_ = old_first; + tmp_mem->next_ = old_first; this->it_ = basic_multiallocation_iterator(tmp_mem); - ++num_mem_; } } @@ -186,14 +190,15 @@ class basic_multiallocation_chain if(end_it == other_it){ return; } - else if(end_it == other_it){ + else if(end_it == this_it){ this->swap(other_chain); } - - static_cast(detail::get_pointer(this->last_mem_))->next_ - = (next_impl_t*)&*this->it_; - this->last_mem_ = other_chain.last_mem_; - this->num_mem_ += other_chain.num_mem_; + else{ + static_cast(detail::get_pointer(this->last_mem_))->next_ + = (next_impl_t*)&*other_chain.it_; + this->last_mem_ = other_chain.last_mem_; + this->num_mem_ += other_chain.num_mem_; + } } void *pop_front() @@ -226,45 +231,6 @@ class basic_multiallocation_chain { return num_mem_; } }; -template -class allocator_multiallocation_chain -{ - typedef typename detail:: - pointer_to_other::type - void_ptr; - - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; - basic_multiallocation_chain chain_; - - public: - - allocator_multiallocation_chain() - : chain_() - {} - - void push_back(void *mem) - { chain_.push_back(mem); } - - multiallocation_iterator get_it() const - { return multiallocation_iterator(chain_.get_it()); } -}; - - -#define BOOST_MULTIALLOC_IT_CHAIN_INIT(IT_CHAIN) ((IT_CHAIN).it.next = 0, (IT_CHAIN).last_mem = 0) -#define BOOST_MULTIALLOC_IT_CHAIN_ADD(IT_CHAIN, MEM)\ - do{\ - multialloc_it_t *____tmp_mem____ = (multialloc_it_t*)(MEM);\ - if(!IT_CHAIN.last_mem){\ - (IT_CHAIN).it.next = ____tmp_mem____;\ - }else{\ - ((multialloc_it_t*)(IT_CHAIN.last_mem))->next = ____tmp_mem____;\ - }\ - ____tmp_mem____->next = 0;\ - IT_CHAIN.last_mem = ____tmp_mem____;\ - }while(0) - -#define BOOST_MULTIALLOC_IT_CHAIN_IT(IT_CHAIN) ((IT_CHAIN).it) - //!This class implements several allocation functions shared by different algorithms //!(aligned allocation, multiple allocation...). diff --git a/test/memory_algorithm_test.cpp b/test/memory_algorithm_test.cpp index fa93ec2..5e877b5 100644 --- a/test/memory_algorithm_test.cpp +++ b/test/memory_algorithm_test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "memory_algorithm_test_template.hpp" #include #include @@ -67,16 +68,17 @@ int test_rbtree_best_fit() int main () { + const std::size_t void_ptr_align = detail::alignment_of::value; if(test_simple_seq_fit()){ return 1; } - if(test_rbtree_best_fit<4>()){ + if(test_rbtree_best_fit()){ return 1; } - if(test_rbtree_best_fit<8>()){ + if(test_rbtree_best_fit<2*void_ptr_align>()){ return 1; } - if(test_rbtree_best_fit<16>()){ + if(test_rbtree_best_fit<4*void_ptr_align>()){ return 1; } From 3cd278a1692de1947e5ed14481fb414020b0bb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 23 Jan 2008 19:34:39 +0000 Subject: [PATCH 10/77] Ticket #1593: [interprocess] 'streamoff' : is not a member of 'std' [SVN r42931] --- test/file_mapping_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index b9851c9..abe97dd 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -9,6 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// #include +#include // for std::streamoff #include #include #include From ed5e79b6d383484e8fc1263bcc7f6109350b588a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 25 Jan 2008 23:07:51 +0000 Subject: [PATCH 11/77] 1)Fixed gcc release mode warnings. 2)Replaced throw with BOOST_RETHROW when BOOST_TRY is used. 3)Fixed issues with singly linked lists [SVN r42974] --- .../interprocess/allocators/allocator.hpp | 3 ++ .../allocators/detail/adaptive_node_pool.hpp | 3 -- .../allocators/detail/allocator_common.hpp | 2 +- .../boost/interprocess/containers/deque.hpp | 5 ++-- .../containers/detail/node_alloc_holder.hpp | 5 ++-- .../boost/interprocess/containers/slist.hpp | 22 +++++++------- .../boost/interprocess/containers/string.hpp | 2 +- .../boost/interprocess/containers/vector.hpp | 2 +- .../boost/interprocess/detail/algorithms.hpp | 2 +- .../detail/managed_open_or_create_impl.hpp | 3 +- .../detail/segment_manager_helper.hpp | 2 +- .../indexes/iunordered_set_index.hpp | 5 ++-- .../mem_algo/detail/mem_algo_common.hpp | 5 ++-- .../mem_algo/detail/simple_seq_fit_impl.hpp | 1 + .../interprocess/mem_algo/rbtree_best_fit.hpp | 2 ++ .../boost/interprocess/segment_manager.hpp | 13 ++++---- .../smart_ptr/detail/shared_count.hpp | 2 +- test/file_mapping_test.cpp | 10 +++---- test/get_process_id_name.hpp | 5 ++-- test/list_test.hpp | 30 ++++++++++++------- 20 files changed, 71 insertions(+), 53 deletions(-) diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 7ce825b..08136dc 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -106,6 +106,9 @@ class allocator multiallocation_chain; +// typedef typename SegmentManager:: +// multiallocation_chain multiallocation_chain; + /// @endcond //!Obtains an allocator that allocates diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 136d29d..87fea06 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -199,7 +199,6 @@ class private_adaptive_node_pool_impl //!can throw boost::interprocess::bad_alloc void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) { - std::size_t old_node_count = nodes.size(); try{ priv_invariants(); for(std::size_t i = 0; i != n; ++i){ @@ -215,8 +214,6 @@ class private_adaptive_node_pool_impl this->priv_deallocate_free_chunks(m_max_free_chunks); throw; } - //remove me - assert((n+old_node_count) == (std::size_t)std::distance(nodes.get_it(), multiallocation_iterator())); priv_invariants(); } diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index 7c5bbcc..da18fc9 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -174,7 +174,7 @@ class cache_impl } BOOST_CATCH(...){ this->cached_deallocation(multiallocation_iterator(chain.get_it())); - throw; + BOOST_RETHROW } BOOST_CATCH_END } diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index eb5b17d..0b7183d 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -1359,9 +1359,9 @@ class deque : protected deque_base size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / this->s_buffer_size(); this->priv_reserve_map_at_front(new_nodes); - size_type i; + size_type i = 1; BOOST_TRY { - for (i = 1; i <= new_nodes; ++i) + for (; i <= new_nodes; ++i) *(this->members_.m_start.m_node - i) = this->priv_allocate_node(); } BOOST_CATCH(...) { @@ -1453,6 +1453,7 @@ class deque : protected deque_base for(;first2 != mid2; ++first2){ detail::get_pointer(&*first2)->~value_type(); } + BOOST_RETHROW } BOOST_CATCH_END } diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 7352019..19901ca 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -176,7 +176,7 @@ struct node_alloc_holder BOOST_CATCH(...){ valueptr->first.~first_type(); static_cast(nodeptr)->~hook_type(); - throw; + BOOST_RETHROW } BOOST_CATCH_END } @@ -201,7 +201,7 @@ struct node_alloc_holder BOOST_CATCH(...){ valueptr->first.~first_type(); static_cast(nodeptr)->~hook_type(); - throw; + BOOST_RETHROW } BOOST_CATCH_END } @@ -296,6 +296,7 @@ struct node_alloc_holder this->destroy(p); } this->node_alloc().deallocate_many(itbeg); + BOOST_RETHROW } BOOST_CATCH_END return beg; diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 9f57c24..3424175 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -347,7 +347,7 @@ class slist slist(InpIt first, InpIt last, const allocator_type& a = allocator_type()) : AllocHolder(a) - { this->insert_after(this->end_node(), first, last); } + { this->insert_after(this->before_begin(), first, last); } //! Effects: Copy constructs a list. //! @@ -804,7 +804,7 @@ class slist //! Complexity: 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(end_n), cur_next; + 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; @@ -823,7 +823,7 @@ class slist //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - typename Icont::iterator end_n(this->icont().end()), cur(end_n), cur_next; + 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; @@ -835,7 +835,7 @@ class slist this->erase_after(iterator(cur), iterator(end_n)); } else{ - this->priv_create_and_insert_nodes(this->end(), new_size - len); + this->priv_create_and_insert_nodes(iterator(cur), new_size - len); } } @@ -1252,9 +1252,9 @@ class slist void priv_fill_assign(size_type n, const T& val) { - iterator end_n(end()); - iterator prev(before_begin()); - iterator node(begin()); + 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; @@ -1274,9 +1274,9 @@ class slist void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) { - iterator end_n(end()); - iterator prev(before_begin()); - iterator node(begin()); + iterator end_n(this->end()); + iterator prev(this->before_begin()); + iterator node(this->begin()); while (node != end_n && first != last){ *node = *first; prev = node; @@ -1295,7 +1295,7 @@ class slist template void priv_insert_after_range_dispatch(iterator prev_pos, InIter first, InIter last, detail::false_) - { return priv_create_and_insert_nodes(prev_pos, first, last); } + { this->priv_create_and_insert_nodes(prev_pos, first, last); } //Functors for member algorithm defaults struct value_less diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 37f3269..1c83a75 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -1684,7 +1684,7 @@ class basic_string for (; constructed--; ++dest_init){ this->destroy(dest_init); } - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END return (constructed); diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index bd7fb5d..f1af804 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -731,7 +731,7 @@ class vector : private detail::vector_alloc_holder //There is not enough memory, allocate a new //buffer or expand the old one. bool same_buffer_start; - size_type real_cap; + size_type real_cap = 0; std::pair ret = this->allocation_command (allocate_new | expand_fwd | expand_bwd, diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index b95d301..233080d 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -92,7 +92,7 @@ InIt n_uninitialized_copy_n for (; new_count--; ++dest_init){ detail::get_pointer(&*dest_init)->~value_type(); } - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END return first; diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index 2be5c0f..068223e 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -332,7 +332,8 @@ class managed_open_or_create_impl //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 = static_cast(region.get_address()); + boost::uint32_t *patomic_word = 0; //avoid gcc warning + patomic_word = static_cast(region.get_address()); boost::uint32_t previous = detail::atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment); if(previous == UninitializedSegment){ diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 4961422..58bbb56 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -210,7 +210,7 @@ inline void array_construct(void *mem, std::size_t num, detail::in_place_interfa BOOST_CATCH(...){ std::size_t destroyed = 0; table.destroy_n(mem, constructed, destroyed); - BOOST_RETHROW; + BOOST_RETHROW } BOOST_CATCH_END } diff --git a/include/boost/interprocess/indexes/iunordered_set_index.hpp b/include/boost/interprocess/indexes/iunordered_set_index.hpp index d247adc..1b059a3 100644 --- a/include/boost/interprocess/indexes/iunordered_set_index.hpp +++ b/include/boost/interprocess/indexes/iunordered_set_index.hpp @@ -289,15 +289,14 @@ class iunordered_set_index size_type cur_size = this->size(); size_type cur_count = this->bucket_count(); bucket_ptr old_p = this->bucket_pointer(); - size_type sug_count; if(!this->size() && old_p != bucket_ptr(&this->init_bucket)){ - sug_count = 1; this->rehash(bucket_traits(bucket_ptr(&this->init_bucket), 1)); destroy_buckets(this->alloc, old_p, cur_count); } else{ - sug_count = index_type::suggested_upper_bucket_count(cur_size); + size_type sug_count = 0; //gcc warning + sug_count = index_type::suggested_upper_bucket_count(cur_size); if(sug_count >= cur_count) return; diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index 8c776ff..c98ec06 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -588,14 +588,15 @@ class memory_algorithm_common 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 ret = shrink + 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(ret); + BOOST_ASSERT(shrink_ok); //Some sanity checks BOOST_ASSERT(shrunk_request == shrunk_received); BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits)); diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index a724189..88394ff 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -394,6 +394,7 @@ void simple_seq_fit_impl::shrink_to_fit() 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); diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 0d7bab9..f675f1d 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -1138,6 +1138,7 @@ bool rbtree_best_fit::priv_is_prev_alloc } else{ block_ctrl *prev = priv_prev_block(ptr); + (void)prev; assert(!priv_is_allocated_block(prev)); return false; } @@ -1151,6 +1152,7 @@ typename rbtree_best_fit::block_ctrl * assert(first_segment_block->m_prev_allocated); block_ctrl *end_block = reinterpret_cast (detail::char_ptr_cast(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; diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index daf61a8..c8ee79e 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -272,7 +272,8 @@ class segment_manager_base //Now construct the header block_header_t * hdr = new(ptr_struct) block_header_t(block_info); - void *ptr = hdr->value(); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); //Now call constructors detail::array_construct(ptr, num, table); @@ -1062,7 +1063,7 @@ class segment_manager //Ignore exceptions BOOST_CATCH(...){ if(dothrow) - BOOST_RETHROW; + BOOST_RETHROW return 0; } BOOST_CATCH_END @@ -1096,7 +1097,8 @@ class segment_manager //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 = hdr->value(); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); //Copy name to memory segment and insert data CharT *name_ptr = static_cast(hdr->template name()); @@ -1109,7 +1111,7 @@ class segment_manager //Ignore exceptions BOOST_CATCH(...){ if(dothrow) - BOOST_RETHROW; + BOOST_RETHROW return 0; } BOOST_CATCH_END @@ -1235,7 +1237,8 @@ class segment_manager } hdr = new(hdr)block_header_t(block_info); - void *ptr = hdr->value(); + void *ptr = 0; //avoid gcc warning + ptr = hdr->value(); //Copy name to memory segment and insert data CharT *name_ptr = static_cast(hdr->template name()); diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 1b26426..3c48eda 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -92,7 +92,7 @@ class shared_count } BOOST_CATCH (...){ d(p); // delete p - throw; + BOOST_RETHROW } BOOST_CATCH_END } diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index abe97dd..4c4495e 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -9,15 +9,15 @@ ////////////////////////////////////////////////////////////////////////////// #include -#include // for std::streamoff -#include +#include //std::streamoff +#include //std::ofstream, std::ifstream #include #include #include -#include -#include -#include +#include //std::auto_ptr +#include //std::exception #include //std::remove +#include //std::size_t #include "get_process_id_name.hpp" using namespace boost::interprocess; diff --git a/test/get_process_id_name.hpp b/test/get_process_id_name.hpp index 26250f6..df3bb8f 100644 --- a/test/get_process_id_name.hpp +++ b/test/get_process_id_name.hpp @@ -12,9 +12,8 @@ #define BOOST_INTERPROCESS_GET_PROCESS_ID_NAME_HPP #include -#include -#include -#include +#include //std::string +#include //std::stringstream #include namespace boost{ diff --git a/test/list_test.hpp b/test/list_test.hpp index c557d1a..a8982f6 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -39,7 +39,8 @@ struct push_data_function shmlist->push_back(move(move_me)); stdlist->push_back(i); } - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; return 0; } }; @@ -56,7 +57,8 @@ struct push_data_function shmlist->push_front(move(move_me)); stdlist->push_front(i); } - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; return 0; } }; @@ -69,7 +71,8 @@ struct pop_back_function { shmlist->pop_back(); stdlist->pop_back(); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; return 0; } }; @@ -177,12 +180,14 @@ int list_test (bool copied_allocators_equal = true) shmlist->unique(); stdlist->unique(); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; if(copied_allocators_equal){ shmlist->sort(std::greater()); stdlist->sort(std::greater()); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; } shmlist->resize(25); @@ -191,7 +196,8 @@ int list_test (bool copied_allocators_equal = true) stdlist->resize(50); shmlist->resize(0); stdlist->resize(0); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; if(push_data_t::execute(max, shmlist, stdlist)){ return 1; @@ -209,7 +215,8 @@ int list_test (bool copied_allocators_equal = true) if(copied_allocators_equal){ shmlist->splice(shmlist->begin(), othershmlist); stdlist->splice(stdlist->begin(), otherstdlist); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; } listsize = (int)shmlist->size(); @@ -225,15 +232,18 @@ int list_test (bool copied_allocators_equal = true) if(copied_allocators_equal){ shmlist->sort(std::greater()); stdlist->sort(std::greater()); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; othershmlist.sort(std::greater()); otherstdlist.sort(std::greater()); - if(!CheckEqualContainers(&othershmlist, &otherstdlist)) return 1; + if(!CheckEqualContainers(&othershmlist, &otherstdlist)) + return 1; shmlist->merge(othershmlist, std::greater()); stdlist->merge(otherstdlist, std::greater()); - if(!CheckEqualContainers(shmlist, stdlist)) return 1; + if(!CheckEqualContainers(shmlist, stdlist)) + return 1; } } From de62388dc750405d3a84a1cb3c0e8eeb54345719 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 2 Apr 2008 01:42:32 +0000 Subject: [PATCH 12/77] Replaced all occurrences of non-ASCII copyright symbol with '(c)' for people using non-ASCII code pages [SVN r43992] --- include/boost/interprocess/errors.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index 1374c8e..ec17f0b 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -10,8 +10,8 @@ // ////////////////////////////////////////////////////////////////////////////// // -// Copyright © 2002 Beman Dawes -// Copyright © 2001 Dietmar Kühl +// Copyright (c) 2002 Beman Dawes +// Copyright (c) 2001 Dietmar Kühl // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) From 5c06570b14e0bb90c8430baddf3cc3a52db7e00b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 27 Apr 2008 07:39:49 +0000 Subject: [PATCH 13/77] Merge in documentation fixes. Apart from the change to optional's documenation Jamfile, which I included by mistake. Fixes #1659, #1661, #1684, #1685, 1687, #1690, #1801 I wrote about this at: http://lists.boost.org/Archives/boost/2008/04/136405.php Merged revisions 44585-44806 via svnmerge from https://svn.boost.org/svn/boost/branches/doc ........ r44585 | danieljames | 2008-04-19 16:25:27 +0100 (Sat, 19 Apr 2008) | 2 lines Fix broken link to vacpp in bjam docs. Refs #1512 ........ r44586 | danieljames | 2008-04-19 16:27:36 +0100 (Sat, 19 Apr 2008) | 2 lines Fix broken link to bcpp in bjam docs. Refs #1513 ........ r44587 | danieljames | 2008-04-19 16:33:58 +0100 (Sat, 19 Apr 2008) | 2 lines DateTime documentation - Fix a link to the serialization library. Refs #1659 ........ r44588 | danieljames | 2008-04-19 16:35:36 +0100 (Sat, 19 Apr 2008) | 2 lines Fix some links in interprocess & intrusive. Refs #1661 ........ r44589 | danieljames | 2008-04-19 16:37:39 +0100 (Sat, 19 Apr 2008) | 2 lines Fix some links in the python docs. Refs #1684. ........ r44590 | danieljames | 2008-04-19 16:38:29 +0100 (Sat, 19 Apr 2008) | 2 lines Work around a quickbook bug which is affecting the python docs. Refs #1684. ........ r44591 | danieljames | 2008-04-19 16:39:34 +0100 (Sat, 19 Apr 2008) | 2 lines Fix a broken link in the numeric conversion docs. Refs #1685 ........ r44592 | danieljames | 2008-04-19 16:40:45 +0100 (Sat, 19 Apr 2008) | 2 lines Fix some links in the optional docs. Refs #1687 ........ r44593 | danieljames | 2008-04-19 16:42:09 +0100 (Sat, 19 Apr 2008) | 2 lines Fix link to the hash documentation from bimap. Refs #1690 ........ r44599 | danieljames | 2008-04-19 18:07:33 +0100 (Sat, 19 Apr 2008) | 2 lines Fix a typo in the format library. Refs #1801 ........ r44600 | danieljames | 2008-04-19 19:20:59 +0100 (Sat, 19 Apr 2008) | 1 line Initialise svnmerge. ........ r44641 | danieljames | 2008-04-20 18:59:47 +0100 (Sun, 20 Apr 2008) | 2 lines Fix the lincense url in shared container iterator documentation. ........ r44642 | danieljames | 2008-04-20 19:00:00 +0100 (Sun, 20 Apr 2008) | 2 lines Fix image link in the mpi documentation. ........ r44643 | danieljames | 2008-04-20 19:00:11 +0100 (Sun, 20 Apr 2008) | 2 lines Fix a typo in the spirit docs. ........ r44644 | danieljames | 2008-04-20 19:00:23 +0100 (Sun, 20 Apr 2008) | 2 lines Escape the slash so that quickbook doesn't think it the start of an italic section, and mess up the link. Refs #1844 ........ r44647 | danieljames | 2008-04-20 19:39:47 +0100 (Sun, 20 Apr 2008) | 2 lines Fix another typo in spirit docs. ........ [SVN r44807] --- doc/interprocess.qbk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index a05d77a..eed8e52 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -5704,7 +5704,7 @@ between all managed memory segments, since many times they just forward the func to the segment manager. Because of this, in [*Boost.Interprocess] all managed memory segments derive from a common class that implements memory-independent (shared memory, memory mapped files) functions: -[@../../../../boost/interprocess/detail/managed_memory_impl.hpp +[@../../boost/interprocess/detail/managed_memory_impl.hpp boost::interprocess::detail::basic_managed_memory_impl] Deriving from this class, [*Boost.Interprocess] implements several managed memory @@ -5766,7 +5766,7 @@ Segregated storage pools are simple and follow the classic segregated storage al to the segment manager. The pool is implemented by the -[@../../../../boost/interprocess/allocators/detail/node_pool.hpp +[@../../boost/interprocess/allocators/detail/node_pool.hpp private_node_pool and shared_node_pool] classes. [endsect] @@ -5809,7 +5809,7 @@ approach: to the segment manager. The adaptive pool is implemented by the -[@../../../../boost/interprocess/allocators/detail/adaptive_node_pool.hpp +[@../../boost/interprocess/allocators/detail/adaptive_node_pool.hpp private_adaptive_node_pool and adaptive_node_pool] classes. [endsect] From 15990aea8c6234c707c7a8d12775813bbda0f7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 27 Apr 2008 14:57:11 +0000 Subject: [PATCH 14/77] Intrusive: * Added `linear<>` and `cache_last<>` options to singly linked lists. * Added `optimize_multikey<>` option to unordered container hooks. * Optimized unordered containers when `store_hash` option is used in the hook. * Implementation changed to be exception agnostic so that it can be used in environments without exceptions. * Added `container_from_iterator` function to tree-based containers. Interprocess: * Added anonymous shared memory for UNIX systems. * Fixed file lock compilation errors [SVN r44818] --- .../interprocess/anonymous_shared_memory.hpp | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 include/boost/interprocess/anonymous_shared_memory.hpp diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp new file mode 100644 index 0000000..bb89979 --- /dev/null +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -0,0 +1,117 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include +#include +#include +#include +#include +#include + +#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +# include //open, O_CREAT, O_*... +# include //mmap +# include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#else +#include +#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 move_return 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 detail::move_return anonymous_shared_memory(std::size_t size, void *address = 0) +#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +{ + 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( (void*)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); + mapped_region region(anonymous_mapping, read_write, 0, size, address); + return detail::move_return(region); +} + +#endif + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_ANONYMOUS_SHARED_MEMORY_HPP From 3af7cdba54d23fa57306119ef18ec306be4bddcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 27 Apr 2008 15:03:06 +0000 Subject: [PATCH 15/77] Intrusive: * Added `linear<>` and `cache_last<>` options to singly linked lists. * Added `optimize_multikey<>` option to unordered container hooks. * Optimized unordered containers when `store_hash` option is used in the hook. * Implementation changed to be exception agnostic so that it can be used in environments without exceptions. * Added `container_from_iterator` function to tree-based containers. Interprocess: * Added anonymous shared memory for UNIX systems. * Fixed file lock compilation errors [SVN r44819] --- doc/interprocess.qbk | 92 +++++-- example/doc_anonymous_shared_memory.cpp | 36 +++ example/doc_multi_index.cpp | 91 +++++++ example/doc_unordered_map.cpp | 66 +++++ .../interprocess/allocators/adaptive_pool.hpp | 162 ++++++++++++- .../interprocess/allocators/allocator.hpp | 11 +- .../allocators/cached_adaptive_pool.hpp | 8 +- .../allocators/cached_node_allocator.hpp | 14 +- .../allocators/detail/adaptive_node_pool.hpp | 26 +- .../allocators/detail/allocator_common.hpp | 52 +++- .../allocators/detail/node_pool.hpp | 2 +- .../allocators/node_allocator.hpp | 75 +++--- .../allocators/private_adaptive_pool.hpp | 22 +- .../allocators/private_node_allocator.hpp | 226 ++---------------- .../boost/interprocess/containers/deque.hpp | 24 +- .../containers/detail/node_alloc_holder.hpp | 6 +- .../boost/interprocess/containers/string.hpp | 2 +- .../boost/interprocess/containers/vector.hpp | 79 +++--- .../boost/interprocess/detail/algorithms.hpp | 4 +- .../interprocess/detail/config_begin.hpp | 1 + include/boost/interprocess/detail/move.hpp | 2 +- include/boost/interprocess/detail/mpl.hpp | 20 +- .../boost/interprocess/detail/named_proxy.hpp | 20 +- .../boost/interprocess/detail/utilities.hpp | 15 +- .../boost/interprocess/ipc/message_queue.hpp | 14 +- include/boost/interprocess/mapped_region.hpp | 7 +- .../mem_algo/detail/mem_algo_common.hpp | 97 ++++++++ .../mem_algo/detail/simple_seq_fit_impl.hpp | 2 +- .../interprocess/mem_algo/rbtree_best_fit.hpp | 34 +-- include/boost/interprocess/offset_ptr.hpp | 72 ++---- .../sync/emulation/interprocess_condition.hpp | 27 ++- include/boost/interprocess/sync/file_lock.hpp | 69 +----- .../interprocess/sync/named_condition.hpp | 4 +- .../interprocess/windows_shared_memory.hpp | 2 +- proj/to-do.txt | 54 +++++ proj/vc7ide/Interprocess.sln | 56 +++++ .../anonymous_shared_memory_test.vcproj | 135 +++++++++++ .../vc7ide/doc_anonymous_shared_memory.vcproj | 138 +++++++++++ proj/vc7ide/doc_multi_index.vcproj | 133 +++++++++++ proj/vc7ide/doc_unordered_map.vcproj | 133 +++++++++++ proj/vc7ide/file_lock_test.vcproj | 134 +++++++++++ proj/vc7ide/interprocesslib.vcproj | 3 + proj/vc7ide/multi_index_test.vcproj | 133 +++++++++++ proj/vc7ide/unordered_test.vcproj | 133 +++++++++++ test/adaptive_node_pool_test.cpp | 2 + test/adaptive_pool_test.cpp | 1 - test/allocator_v1.hpp | 8 +- test/anonymous_shared_memory_test.cpp | 54 +++++ test/dummy_test_allocator.hpp | 8 +- test/expand_bwd_test_allocator.hpp | 8 +- test/expand_bwd_test_template.hpp | 135 ++++++----- test/file_lock_test.cpp | 62 +++++ test/list_test.cpp | 6 + test/multi_index_test.cpp | 149 ++++++++++++ test/shared_memory_mapping_test.cpp | 23 ++ test/tree_test.cpp | 2 +- test/unordered_test.cpp | 94 ++++++++ test/vector_test.cpp | 15 ++ test/windows_shared_memory_mapping_test.cpp | 137 +++++------ test/windows_shared_memory_test.cpp | 1 + 60 files changed, 2472 insertions(+), 669 deletions(-) create mode 100644 example/doc_anonymous_shared_memory.cpp create mode 100644 example/doc_multi_index.cpp create mode 100644 example/doc_unordered_map.cpp create mode 100644 proj/to-do.txt create mode 100644 proj/vc7ide/anonymous_shared_memory_test.vcproj create mode 100644 proj/vc7ide/doc_anonymous_shared_memory.vcproj create mode 100644 proj/vc7ide/doc_multi_index.vcproj create mode 100644 proj/vc7ide/doc_unordered_map.vcproj create mode 100644 proj/vc7ide/file_lock_test.vcproj create mode 100644 proj/vc7ide/multi_index_test.vcproj create mode 100644 proj/vc7ide/unordered_test.vcproj create mode 100644 test/anonymous_shared_memory_test.cpp create mode 100644 test/file_lock_test.cpp create mode 100644 test/multi_index_test.cpp create mode 100644 test/unordered_test.cpp diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index eed8e52..0b6096c 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -58,6 +58,15 @@ separate compilation. However, the subset used by [*Boost.Interprocess] does not need any separate compilation so the user can define `BOOST_DATE_TIME_NO_LIB` to avoid Boost from trying to automatically link the [*Boost.DateTime]. +In POSIX systems, [*Boost.Interprocess] uses pthread system calls to implement +classes like mutexes, condition variables, etc... In some operating systems, +these POSIX calls are implemented in separate libraries that are not automatically +linked by the compiler. For example, in some Linux systems POSIX pthread functions +are implemented in `librt.a` library, so you might need to add that library +when linking an executable or shared library that uses [*Boost.Interprocess]. +If you obtain linking errors related to those pthread functions, please revise +your system's documentation to know which library implements them. + [endsect] [section:tested_compilers Tested compilers] @@ -551,6 +560,30 @@ behavior as the standard C (stdio.h) `int remove(const char *path)` function. [endsect] +[section:anonymous_shared_memory Anonymous shared memory for UNIX systems] + +Creating a shared memory segment and mapping it can be a bit tedious when several +processes are involved. When processes are related via `fork()` operating system +call in UNIX sytems a simpler method is available using anonymous shared memory. + +This feature has been implemented in UNIX systems mapping the device `\dev\zero` or +just using the `MAP_ANONYMOUS` in a POSIX conformant `mmap` system call. + +This feature is wrapped in [*Boost.Interprocess] using the `anonymous_shared_memory()` +function, which returns a `mapped_region` object holding an anonymous shared memory +segment that can be shared by related processes. + +Here's is an example: + +[import ../example/doc_anonymous_shared_memory.cpp] +[doc_anonymous_shared_memory] + +Once the segment is created, a `fork()` call can +be used so that `region` is used to communicate two related processes. + +[endsect] + + [section:windows_shared_memory Native windows shared memory] Windows operating system also offers shared memory, but the lifetime of this @@ -1298,7 +1331,7 @@ All the mutex types from [*Boost.Interprocess] implement the following operation [blurb ['[*void lock()]]] [*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. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. + 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 thread. If the mutex supports recursive locking, the mutex must be unlocked the same number of times it is locked. [*Throws:] *interprocess_exception* on error. @@ -4935,6 +4968,41 @@ Boost.Interprocess containers: [endsect] +[section:additional_containers Boost containers compatible with Boost.Interprocess] + +As mentioned, container developers might need to change their implementation to make them +compatible with Boost.Interprocess, because implementation usually ignore allocators with +smart pointers. Hopefully several Boost containers are compatible with [*Interprocess]. + +[section:unordered Boost unordered containers] + +[*Boost.Unordered] containers are compatible with Interprocess, so programmers can store +hash containers in shared memory and memory mapped files. Here's an small example storing +`unordered_map` in shared memory: + +[import ../example/doc_unordered_map.cpp] +[doc_unordered_map] + +[endsect] + +[section:multi_index Boost.MultiIndex containers] + +The widely used [*Boost.MultiIndex] library is compatible with [*Boost.Interprocess] so +we can construct pretty good databases in shared memory. Constructing databases in shared +memory is a bit tougher than in normal memory, usually because those databases contain strings +and those strings need to be placed in shared memory. Shared memory strings require +an allocator in their constructors so this usually makes object insertion a bit more +complicated. + +Here's is an example that shows how to put a multi index container in shared memory: + +[import ../example/doc_multi_index.cpp] +[doc_multi_index] + +[endsect] + +[endsect] + [section:memory_algorithms Memory allocation algorithms] [section:simple_seq_fit simple_seq_fit: A simple shared memory management algorithm] @@ -6262,7 +6330,7 @@ will manage the index. `segment_manager` will define interesting internal types For example, the index type `flat_map_index` based in `boost::interprocess::flat_map` is just defined as: -[import ../../../boost/interprocess/indexes/flat_map_index.hpp] +[import ../../boost/interprocess/indexes/flat_map_index.hpp] [flat_map_index] @@ -6385,6 +6453,12 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_36_00 Boost 1.36 Release] + +* Added anonymous shared memory for UNIX systems. + +[endsect] + [section:release_notes_boost_1_35_00 Boost 1.35 Release] * Added auxiliary utilities to ease the definition and construction of @@ -6654,20 +6728,6 @@ But the work to implement PF_UNIX-like sockets and doors would be huge [endsect] -[section:future_containers Unordered associative containers and other containers] - -We should be able to construct boost::unordered_xxx family in managed memory segments, -so that there is no code duplication in boost. So [*Boost.Interprocess] should cooperate -with boost container developers instead of duplicating effort writing it's own containers. - -A very interesting project is making [*boost::multi_index] compatible with -[*Boost.Interprocess] ready for shared memory. This could be a good basis for memory -mapped data-bases. The work to achieve this, however, can be huge. It would be -interesting a collaboration with [*Intrusive] library to achieve shared memory -intrusive containers. - -[endsect] - [endsect] [endsect] diff --git a/example/doc_anonymous_shared_memory.cpp b/example/doc_anonymous_shared_memory.cpp new file mode 100644 index 0000000..b0dbcf2 --- /dev/null +++ b/example/doc_anonymous_shared_memory.cpp @@ -0,0 +1,36 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_anonymous_shared_memory +#include +#include +#include +#include + +int main () +{ + using namespace boost::interprocess; + try{ + //Create an anonymous shared memory segment with size 1000 + mapped_region region(anonymous_shared_memory(1000)); + + //Write all the memory to 1 + std::memset(region.get_address(), 1, region.get_size()); + + //The segment is unmapped when "region" goes out of scope + } + catch(interprocess_exception &ex){ + std::cout << ex.what() << std::endl; + return 1; + } + return 0; +} +//] +#include diff --git a/example/doc_multi_index.cpp b/example/doc_multi_index.cpp new file mode 100644 index 0000000..24cbd63 --- /dev/null +++ b/example/doc_multi_index.cpp @@ -0,0 +1,91 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_multi_index +#include +#include +#include + +#include +#include +#include + +using namespace boost::interprocess; +namespace bmi = boost::multi_index; + +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator>shm_string; + +//Data to insert in shared memory +struct employee +{ + int id; + int age; + shm_string name; + employee( int id_ + , int age_ + , const char *name_ + , const char_allocator &a) + : id(id_), age(age_), name(name_, a) + {} +}; + +//Tags +struct id{}; +struct age{}; +struct name{}; + +// Define a multi_index_container of employees with following indices: +// - a unique index sorted by employee::int, +// - a non-unique index sorted by employee::name, +// - a non-unique index sorted by employee::age. +typedef bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + managed_shared_memory::allocator::type +> employee_set; + +int main () +{ + //Erase previous shared memory with the name + shared_memory_object::remove("MySharedMemory"); + + try{ + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); + + //Construct the multi_index in shared memory + employee_set *es = segment.construct + ("My MultiIndex Container") //Container's name in shared memory + ( employee_set::ctor_args_list() + , segment.get_allocator()); //Ctor parameters + + //Now insert elements + char_allocator ca(segment.get_allocator()); + es->insert(employee(0,31, "Joe", ca)); + es->insert(employee(1,27, "Robert", ca)); + es->insert(employee(2,40, "John", ca)); + } + catch(...){ + shared_memory_object::remove("MySharedMemory"); + throw; + } + shared_memory_object::remove("MySharedMemory"); + return 0; +} +//] +#include diff --git a/example/doc_unordered_map.cpp b/example/doc_unordered_map.cpp new file mode 100644 index 0000000..3839c6f --- /dev/null +++ b/example/doc_unordered_map.cpp @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_unordered_map +#include +#include + +#include //boost::unordered_map +#include //std::equal_to +#include //boost::hash + +int main () +{ + using namespace boost::interprocess; + //Erase previous shared memory with the name + shared_memory_object::remove("MySharedMemory"); + + try{ + //Create shared memory + managed_shared_memory segment(create_only ,"MySharedMemory" ,65536); + + //Note that unordered_map's value_type is std::pair, + //so the allocator must allocate that pair. + typedef int KeyType; + typedef float MappedType; + typedef std::pair ValueType; + + //Typedef the allocator + typedef allocator ShmemAllocator; + + //Alias an unordered_map of ints that uses the previous STL-like allocator. + typedef boost::unordered_map + < KeyType , MappedType + , boost::hash ,std::equal_to + , ShmemAllocator> + MyHashMap; + + //Construct a shared memory hash map. + //Note that the first parameter is the initial bucket count and + //after that, the hash function, the equality function and the allocator + MyHashMap *myhashmap = segment.construct("MyHashMap") //object name + ( 3, boost::hash(), std::equal_to() // + , segment.get_allocator()); //allocator instance + + //Insert data in the hash map + for(int i = 0; i < 100; ++i){ + myhashmap->insert(ValueType(i, (float)i)); + } + } + catch(...){ + shared_memory_object::remove("MySharedMemory"); + throw; + } + shared_memory_object::remove("MySharedMemory"); + return 0; +} +//] +#include diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index 0c00006..01b2b06 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,7 @@ namespace interprocess { /// @cond namespace detail{ - +/* template < unsigned int Version , class T , class SegmentManager @@ -61,8 +62,9 @@ class adaptive_pool_base typedef SegmentManager segment_manager; typedef adaptive_pool_base self_t; + static const std::size_t SizeOfT = sizeof(detail::if_c::value, int, T>::type); typedef detail::shared_adaptive_node_pool - < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; + < SegmentManager, SizeOfT, NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; typedef typename detail:: pointer_to_other::type node_pool_ptr; @@ -157,19 +159,153 @@ class adaptive_pool_base node_pool_ptr mp_node_pool; /// @endcond }; +*/ + +template < unsigned int Version + , class T + , class SegmentManager + , std::size_t NodesPerChunk + , std::size_t MaxFreeChunks + , unsigned char OverheadPercent + > +class adaptive_pool_base + : public node_pool_allocation_impl + < adaptive_pool_base + < Version, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> + , Version + , T + , SegmentManager + > +{ + public: + typedef typename SegmentManager::void_pointer void_pointer; + typedef SegmentManager segment_manager; + typedef adaptive_pool_base + self_t; + + /// @cond + + template + struct node_pool + { + typedef detail::shared_adaptive_node_pool + < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> type; + + static type *get(void *p) + { return static_cast(p); } + }; + /// @endcond + + BOOST_STATIC_ASSERT((Version <=2)); + + public: + //------- + typedef typename detail:: + pointer_to_other::type pointer; + typedef typename detail:: + pointer_to_other::type const_pointer; + typedef T value_type; + typedef typename detail::add_reference + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef detail::version_type version; + typedef transform_iterator + < typename SegmentManager:: + multiallocation_iterator + , detail::cast_functor > multiallocation_iterator; + typedef typename SegmentManager:: + multiallocation_chain multiallocation_chain; + + //!Obtains adaptive_pool_base from + //!adaptive_pool_base + template + struct rebind + { + typedef adaptive_pool_base other; + }; + + /// @cond + private: + //!Not assignable from related adaptive_pool_base + template + adaptive_pool_base& operator= + (const adaptive_pool_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 + adaptive_pool_base(segment_manager *segment_mngr) + : mp_node_pool(detail::get_or_create_node_pool::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 + adaptive_pool_base + (const adaptive_pool_base &other) + : mp_node_pool(detail::get_or_create_node_pool::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 inline -bool operator==(const adaptive_pool_base &alloc1, - const adaptive_pool_base &alloc2) +template inline +bool operator==(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type //!of adaptive_pool_base -template inline -bool operator!=(const adaptive_pool_base &alloc1, - const adaptive_pool_base &alloc2) +template inline +bool operator!=(const adaptive_pool_base &alloc1, + const adaptive_pool_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } template < class T @@ -299,7 +435,7 @@ class adaptive_pool //!Not assignable from //!other adaptive_pool - adaptive_pool& operator=(const adaptive_pool&); + //adaptive_pool& operator=(const adaptive_pool&); public: //!Constructor from a segment manager. If not present, constructs a node @@ -324,7 +460,7 @@ class adaptive_pool //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const; + void* get_node_pool() const; //!Returns the segment manager. //!Never throws @@ -358,9 +494,9 @@ class adaptive_pool //!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); + //!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 diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 08136dc..f5cbbb1 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -106,8 +106,6 @@ class allocator multiallocation_chain; -// typedef typename SegmentManager:: -// multiallocation_chain multiallocation_chain; /// @endcond @@ -153,7 +151,7 @@ class allocator //!Deallocates memory previously allocated. //!Never throws void deallocate(const pointer &ptr, size_type) - { mp_mngr->deallocate(detail::get_pointer(ptr)); } + { mp_mngr->deallocate((void*)detail::get_pointer(ptr)); } //!Returns the number of elements that could be allocated. //!Never throws @@ -253,10 +251,15 @@ class allocator 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(detail::get_pointer(ptr)) value_type; } + { new((void*)detail::get_pointer(ptr)) value_type; } //!Destroys object. Throws if object's //!destructor throws diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index ec75948..0b31f0a 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -119,7 +119,7 @@ class cached_adaptive_pool < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) + , sizeof(typename detail::if_c::value, int, T>::type) , NodesPerChunk , MaxFreeChunks , OverheadPercent @@ -252,9 +252,9 @@ class cached_adaptive_pool //!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); + //!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 diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 4ee4767..6d470de 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -225,7 +225,7 @@ class cached_node_allocator //!Default construct an object. //!Throws if T's default constructor throws - void construct(const pointer &ptr); + void construct(const pointer &ptr, const_reference v); //!Destroys object. Throws if object's //!destructor throws @@ -302,15 +302,15 @@ class cached_node_allocator //!Equality test for same type //!of cached_node_allocator -template inline -bool operator==(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2); +template inline +bool operator==(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); //!Inequality test for same type //!of cached_node_allocator -template inline -bool operator!=(const cached_node_allocator &alloc1, - const cached_node_allocator &alloc2); +template inline +bool operator!=(const cached_node_allocator &alloc1, + const cached_node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 87fea06..0495f41 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -49,7 +49,7 @@ class 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::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; @@ -106,9 +106,11 @@ class private_adaptive_node_pool_impl std::size_t candidate_power_of_2 = upper_power_of_2(elements_per_subchunk*real_node_size + HdrOffsetSize); bool overhead_satisfied = false; + //Now calculate the wors-case overhead for a subchunk + const std::size_t max_subchunk_overhead = HdrSize + PayloadPerAllocation; while(!overhead_satisfied){ - elements_per_subchunk = (candidate_power_of_2 - HdrOffsetSize)/real_node_size; - std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*real_node_size; + elements_per_subchunk = (candidate_power_of_2 - max_subchunk_overhead)/real_node_size; + const std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*real_node_size; if(overhead_size*100/candidate_power_of_2 < overhead_percent){ overhead_satisfied = true; } @@ -121,14 +123,26 @@ class private_adaptive_node_pool_impl static void calculate_num_subchunks (std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_chunk - ,std::size_t &num_subchunks, std::size_t &real_num_node) + ,std::size_t &num_subchunks, std::size_t &real_num_node, std::size_t overhead_percent) { std::size_t elements_per_subchunk = (alignment - HdrOffsetSize)/real_node_size; std::size_t possible_num_subchunk = (elements_per_chunk - 1)/elements_per_subchunk + 1; - std::size_t hdr_subchunk_elements = (alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/real_node_size; + std::size_t hdr_subchunk_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size; while(((possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements) < elements_per_chunk){ ++possible_num_subchunk; } + elements_per_subchunk = (alignment - HdrOffsetSize)/real_node_size; + bool overhead_satisfied = false; + while(!overhead_satisfied){ + const std::size_t total_data = (elements_per_subchunk*(possible_num_subchunk-1) + hdr_subchunk_elements)*real_node_size; + const std::size_t total_size = alignment*possible_num_subchunk; + if((total_size - total_data)*100/total_size < overhead_percent){ + overhead_satisfied = true; + } + else{ + ++possible_num_subchunk; + } + } num_subchunks = possible_num_subchunk; real_num_node = (possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements; } @@ -157,7 +171,7 @@ class private_adaptive_node_pool_impl , m_chunk_multiset() , m_totally_free_chunks(0) { - calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node); + calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node, overhead_percent); } //!Destructor. Deallocates all allocated chunks. Never throws diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index da18fc9..bd64f3c 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -342,7 +342,12 @@ class array_allocation_impl //!Default construct an object. //!Throws if T's default constructor throws void construct(const pointer &ptr) - { new(detail::get_pointer(ptr)) value_type; } + { 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 @@ -386,36 +391,53 @@ class node_pool_allocation_impl typedef typename SegmentManager:: multiallocation_chain multiallocation_chain; + template + struct node_pool + { + typedef typename Derived::template node_pool<0>::type type; + static type *get(void *p) + { return static_cast(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(this->derived()->get_node_pool()->allocate_node())); + return pointer(static_cast + (pool->allocate_node())); else return pointer(static_cast - (this->derived()->get_node_pool()->get_segment_manager()->allocate(sizeof(T)*count))); + (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) - this->derived()->get_node_pool()->deallocate_node(detail::get_pointer(ptr)); + pool->deallocate_node(detail::get_pointer(ptr)); else - this->derived()->get_node_pool()->get_segment_manager()->deallocate(detail::get_pointer(ptr)); + 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() - { return pointer(static_cast(this->derived()->get_node_pool()->allocate_node())); } + { + 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(pool->allocate_node())); + } //!Allocates many elements of size == 1 in a contiguous chunk //!of memory. The minimum number to be allocated is min_elements, @@ -424,13 +446,21 @@ class node_pool_allocation_impl //!will be assigned to received_size. Memory allocated with this function //!must be deallocated only with deallocate_one(). multiallocation_iterator allocate_individual(std::size_t num_elements) - { return multiallocation_iterator(this->derived()->get_node_pool()->allocate_nodes(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_iterator(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) - { this->derived()->get_node_pool()->deallocate_node(detail::get_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 chunk //!of memory. The minimum number to be allocated is min_elements, @@ -439,11 +469,11 @@ class node_pool_allocation_impl //!will be assigned to received_size. Memory allocated with this function //!must be deallocated only with deallocate_one(). void deallocate_individual(multiallocation_iterator it) - { this->derived()->get_node_pool()->deallocate_nodes(it.base()); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } //!Deallocates all free chunks of the pool void deallocate_free_chunks() - { this->derived()->get_node_pool()->deallocate_free_chunks(); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_chunks(); } }; template @@ -536,7 +566,7 @@ class cached_allocator_impl m_cache.cached_deallocation(detail::get_pointer(ptr)); } else{ - this->get_segment_manager()->deallocate(detail::get_pointer(ptr)); + this->get_segment_manager()->deallocate((void*)detail::get_pointer(ptr)); } } diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index cfcbcf8..3418d9f 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -253,7 +253,7 @@ class private_node_pool_impl while(!m_chunklist.empty()){ void *addr = get_chunk_from_hook(&m_chunklist.front(), blocksize); m_chunklist.pop_front(); - mp_segment_mngr_base->deallocate(addr); + mp_segment_mngr_base->deallocate((void*)addr); } //Just clear free node list m_freelist.clear(); diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index eed6e9e..fabc3af 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -59,10 +59,19 @@ class node_allocator_base typedef SegmentManager segment_manager; typedef node_allocator_base self_t; - typedef detail::shared_node_pool - < SegmentManager, sizeof(T), NodesPerChunk> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; + + /// @cond + + template + struct node_pool + { + typedef detail::shared_node_pool + < SegmentManager, sizeof(T), NodesPerChunk> type; + + static type *get(void *p) + { return static_cast(p); } + }; + /// @endcond BOOST_STATIC_ASSERT((Version <=2)); @@ -104,7 +113,7 @@ class node_allocator_base (const node_allocator_base&); //!Not assignable from other node_allocator_base - node_allocator_base& operator=(const node_allocator_base&); + //node_allocator_base& operator=(const node_allocator_base&); /// @endcond public: @@ -112,14 +121,14 @@ class node_allocator_base //!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(segment_mngr)) { } + : mp_node_pool(detail::get_or_create_node_pool::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()) { - mp_node_pool->inc_ref_count(); + node_pool<0>::get(detail::get_pointer(mp_node_pool))->inc_ref_count(); } //!Copy constructor from related node_allocator_base. If not present, constructs @@ -128,22 +137,30 @@ class node_allocator_base template node_allocator_base (const node_allocator_base &other) - : mp_node_pool(detail::get_or_create_node_pool(other.get_segment_manager())) { } + : mp_node_pool(detail::get_or_create_node_pool::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(detail::get_pointer(mp_node_pool)); } + { 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 - node_pool_t* get_node_pool() const + 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 mp_node_pool->get_segment_manager(); } + { 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. @@ -152,22 +169,22 @@ class node_allocator_base /// @cond private: - node_pool_ptr mp_node_pool; + void_pointer mp_node_pool; /// @endcond }; //!Equality test for same type //!of node_allocator_base -template inline -bool operator==(const node_allocator_base &alloc1, - const node_allocator_base &alloc2) +template inline +bool operator==(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() == alloc2.get_node_pool(); } //!Inequality test for same type //!of node_allocator_base -template inline -bool operator!=(const node_allocator_base &alloc1, - const node_allocator_base &alloc2) +template inline +bool operator!=(const node_allocator_base &alloc1, + const node_allocator_base &alloc2) { return alloc1.get_node_pool() != alloc2.get_node_pool(); } template < class T @@ -283,7 +300,7 @@ class node_allocator //!Not assignable from //!other node_allocator - node_allocator& operator=(const node_allocator&); + //node_allocator& operator=(const node_allocator&); public: //!Constructor from a segment manager. If not present, constructs a node @@ -308,7 +325,7 @@ class node_allocator //!Returns a pointer to the node pool. //!Never throws - node_pool_t* get_node_pool() const; + void* get_node_pool() const; //!Returns the segment manager. //!Never throws @@ -342,9 +359,9 @@ class node_allocator //!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); + //!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 @@ -414,15 +431,15 @@ class node_allocator //!Equality test for same type //!of node_allocator -template inline -bool operator==(const node_allocator &alloc1, - const node_allocator &alloc2); +template inline +bool operator==(const node_allocator &alloc1, + const node_allocator &alloc2); //!Inequality test for same type //!of node_allocator -template inline -bool operator!=(const node_allocator &alloc1, - const node_allocator &alloc2); +template inline +bool operator!=(const node_allocator &alloc1, + const node_allocator &alloc2); #endif diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index 5552348..0e34ba4 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -104,6 +104,22 @@ class private_adaptive_pool_base }; /// @cond + + template + struct node_pool + { + typedef detail::private_adaptive_node_pool + type; + + static type *get(void *p) + { return static_cast(p); } + }; + private: //!Not assignable from related private_adaptive_pool_base template @@ -355,9 +371,9 @@ class private_adaptive_pool //!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); + //!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 diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index 608bacc..9db03a6 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -7,201 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -/* -#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP -#define BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP - -#if (defined _MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//!\file -//!Describes private_node_allocator pooled shared memory STL compatible allocator - -namespace boost { -namespace interprocess { - -//!An STL node allocator that uses a segment manager as memory -//!source. The internal pointer type will of the same type (raw, smart) as -//!"typename SegmentManager::void_pointer" type. This allows -//!placing the allocator in shared memory, memory mapped-files, etc... -//!This allocator has its own node pool. NodesPerChunk is the number of nodes allocated -//!at once when the allocator needs runs out of nodes -template -class private_node_allocator -{ - /// @cond - private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: - pointer_to_other::type cvoid_pointer; - typedef SegmentManager segment_manager; - typedef typename detail::pointer_to_other - ::type segment_mngr_ptr_t; - typedef private_node_allocator - self_t; - typedef detail::private_node_pool - priv_node_pool_t; - /// @endcond - - public: - //------- - typedef typename detail:: - pointer_to_other::type pointer; - typedef typename detail:: - pointer_to_other::type const_pointer; - typedef T value_type; - typedef typename detail::add_reference - ::type reference; - typedef typename detail::add_reference - ::type const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - //!Obtains node_allocator from other node_allocator - template - struct rebind - { - typedef private_node_allocator other; - }; - - /// @cond - private: - //!Not assignable from related private_node_allocator - template - private_node_allocator& operator= - (const private_node_allocator&); - - //!Not assignable from other private_node_allocator - private_node_allocator& operator=(const private_node_allocator&); - /// @endcond - - public: - - //!Constructor from a segment manager - private_node_allocator(segment_manager *segment_mngr) - : m_node_pool(segment_mngr){} - - //!Copy constructor from other private_node_allocator. Never throws - private_node_allocator(const private_node_allocator &other) - : m_node_pool(other.get_segment_manager()){} - - //!Copy constructor from related private_node_allocator. Never throws. - template - private_node_allocator - (const private_node_allocator &other) - : m_node_pool(other.get_segment_manager()) - {} - - //!Destructor, frees all used memory. Never throws - ~private_node_allocator() - {} - - //!Returns the segment manager. Never throws - segment_manager* get_segment_manager()const - { return m_node_pool.get_segment_manager(); } - - //!Returns the number of elements that could be allocated. Never throws - size_type max_size() const - { return this->get_segment_manager()->get_size()/sizeof(value_type); } - - //!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; - if(count > this->max_size()) - throw bad_alloc(); - else if(count == 1) - return pointer(static_cast(m_node_pool.allocate_node())); - else - return pointer(static_cast - (m_node_pool.get_segment_manager()->allocate(sizeof(T)*count))); - } - - //!Deallocate allocated memory. Never throws - void deallocate(const pointer &ptr, size_type count) - { - if(count == 1) - m_node_pool.deallocate_node(detail::get_pointer(ptr)); - else - m_node_pool.get_segment_manager()->deallocate(detail::get_pointer(ptr)); - } - - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { m_node_pool.deallocate_free_chunks(); } - - //!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); } - - //These functions are obsolete. These are here to conserve - //backwards compatibility with containers using them... - - //!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(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(); } - - /// @cond - private: - priv_node_pool_t m_node_pool; - /// @endcond -}; - -//!Equality test for same type of private_node_allocator -template inline -bool operator==(const private_node_allocator &alloc1, - const private_node_allocator &alloc2) -{ return &alloc1 == &alloc2; } - -//!Inequality test for same type of private_node_allocator -template inline -bool operator!=(const private_node_allocator &alloc1, - const private_node_allocator &alloc2) -{ - return &alloc1 != &alloc2; -} - -} //namespace interprocess { -} //namespace boost { - -#include - -#endif //#ifndef BOOST_INTERPROCESS_PRIVATE_NODE_ALLOCATOR_HPP - -*/ ////////////////////////////////////////////////////////////////////////////// // @@ -303,6 +108,19 @@ class private_node_allocator_base }; /// @cond + template + struct node_pool + { + typedef detail::private_node_pool + type; + + static type *get(void *p) + { return static_cast(p); } + }; + private: //!Not assignable from related private_node_allocator_base template @@ -356,15 +174,15 @@ class private_node_allocator_base }; //!Equality test for same type of private_node_allocator_base -template inline -bool operator==(const private_node_allocator_base &alloc1, - const private_node_allocator_base &alloc2) +template inline +bool operator==(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) { return &alloc1 == &alloc2; } //!Inequality test for same type of private_node_allocator_base -template inline -bool operator!=(const private_node_allocator_base &alloc1, - const private_node_allocator_base &alloc2) +template inline +bool operator!=(const private_node_allocator_base &alloc1, + const private_node_allocator_base &alloc2) { return &alloc1 != &alloc2; } template < class T @@ -539,9 +357,9 @@ class private_node_allocator //!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); + //!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 diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index 0b7183d..9359db3 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -658,7 +658,7 @@ class deque : protected deque_base void push_back(const value_type& t) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); ++this->members_.m_finish.m_cur; } else @@ -669,7 +669,7 @@ class deque : protected deque_base void push_back(const detail::moved_object &mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); ++this->members_.m_finish.m_cur; } else @@ -679,7 +679,7 @@ class deque : protected deque_base void push_back(value_type &&mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); ++this->members_.m_finish.m_cur; } else @@ -690,7 +690,7 @@ class deque : protected deque_base void push_front(const value_type& t) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(t); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(t); --this->members_.m_start.m_cur; } else @@ -701,7 +701,7 @@ class deque : protected deque_base void push_front(const detail::moved_object &mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(mt); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(mt); --this->members_.m_start.m_cur; } else @@ -711,7 +711,7 @@ class deque : protected deque_base void push_front(value_type &&mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new(detail::get_pointer(this->members_.m_start.m_cur)- 1)value_type(move(mt)); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(move(mt)); --this->members_.m_start.m_cur; } else @@ -1217,7 +1217,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); 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_first; } @@ -1235,7 +1235,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); 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_first; } @@ -1251,7 +1251,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new(detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); 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_first; } @@ -1271,7 +1271,7 @@ class deque : protected deque_base BOOST_TRY { 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_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(t); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(t); } BOOST_CATCH(...){ ++this->members_.m_start; @@ -1289,7 +1289,7 @@ class deque : protected deque_base BOOST_TRY { 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_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); } BOOST_CATCH(...){ ++this->members_.m_start; @@ -1306,7 +1306,7 @@ class deque : protected deque_base BOOST_TRY { 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_last - 1; - new(detail::get_pointer(this->members_.m_start.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(move(mt)); } BOOST_CATCH(...){ ++this->members_.m_start; diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 19901ca..2f9f73a 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -145,15 +145,15 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static void construct(const NodePtr &ptr, const Convertible &value) - { new(detail::get_pointer(ptr)) Node(value); } + { new((void*)detail::get_pointer(ptr)) Node(value); } #else template static void construct(const NodePtr &ptr, Convertible &&value) - { new(detail::get_pointer(ptr)) Node(forward(value)); } + { new((void*)detail::get_pointer(ptr)) Node(forward(value)); } #endif static void construct(const NodePtr &ptr) - { new(detail::get_pointer(ptr)) Node(); } + { new((void*)detail::get_pointer(ptr)) Node(); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 1c83a75..c1d0c90 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -308,7 +308,7 @@ class basic_string_base } void construct(pointer p, const value_type &value = value_type()) - { new(detail::get_pointer(p)) value_type(value); } + { new((void*)detail::get_pointer(p)) value_type(value); } void destroy(pointer p, size_type n) { diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index f1af804..561c87d 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -301,8 +301,8 @@ struct vector_alloc_holder const pointer &reuse, allocator_v2) { - return this->alloc().allocation_command(command, limit_size, preferred_size, - received_size, reuse); + return this->alloc().allocation_command + (command, limit_size, preferred_size, received_size, reuse); } size_type next_capacity(size_type additional_objects) const @@ -434,7 +434,7 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for copy constructors //so that std::copy and similar can use memcpy typedef typename detail::if_c - ::value ,T* ,detail::move_iterator >::type copy_move_it; @@ -442,7 +442,7 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for assignments //so that std::uninitialized_copy and similar can use memcpy typedef typename detail::if_c - ::value ,T* ,detail::move_iterator >::type assign_move_it; @@ -859,7 +859,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start) + this->members_.m_size)value_type(x); + new((void*)(detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); ++this->members_.m_size; } else{ @@ -878,7 +878,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(mx); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(mx); ++this->members_.m_size; } else{ @@ -890,7 +890,7 @@ class vector : private detail::vector_alloc_holder { if (this->members_.m_size < this->members_.m_capacity){ //There is more memory, just construct a new object at the end - new(detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(move(mx)); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(move(mx)); ++this->members_.m_size; } else{ @@ -1101,7 +1101,7 @@ class vector : private detail::vector_alloc_holder T *ptr = detail::get_pointer(this->members_.m_start + this->members_.m_size); while(n--){ //Default construct - new(ptr++)T(); + new((void*)ptr++)T(); ++this->members_.m_size; } } @@ -1241,9 +1241,9 @@ class vector : private detail::vector_alloc_holder std::uninitialized_copy(copy_move_it(old_finish - n), copy_move_it(old_finish), old_finish); this->members_.m_size += n; //Copy previous to last objects to the initialized end - std::copy_backward(assign_move_it(detail::get_pointer(pos)), assign_move_it(old_finish - n), old_finish); + std::copy_backward(assign_move_it(pos), assign_move_it(old_finish - n), old_finish); //Insert new objects in the pos - std::copy(first, last, detail::get_pointer(pos)); + std::copy(first, last, pos); } else { //The new elements don't fit in the [pos, end()) range. Copy @@ -1254,12 +1254,12 @@ class vector : private detail::vector_alloc_holder this->members_.m_size += n - elems_after; //Copy old [pos, end()) elements to the uninitialized memory std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) + ( copy_move_it(pos) , copy_move_it(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 - std::copy(first, mid, detail::get_pointer(pos)); + std::copy(first, mid, pos); } } @@ -1277,7 +1277,7 @@ class vector : private detail::vector_alloc_holder //the start of the new buffer new_finish = std::uninitialized_copy ( copy_move_it(detail::get_pointer(this->members_.m_start)) - , copy_move_it(detail::get_pointer(pos)) + , copy_move_it(pos) , old_finish = new_finish); construted_values_destroyer.increment_size(new_finish - old_finish); //Initialize new objects, starting from previous point @@ -1287,9 +1287,9 @@ class vector : private detail::vector_alloc_holder //Initialize from the rest of the old buffer, //starting from previous point new_finish = std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) + ( copy_move_it(pos) , copy_move_it(detail::get_pointer(this->members_.m_start) + this->members_.m_size) - , detail::get_pointer(new_finish)); + , new_finish); //All construction successful, disable rollbacks construted_values_destroyer.release(); @@ -1345,13 +1345,11 @@ class vector : private detail::vector_alloc_holder //Copy first old values before pos, after that the //new objects boost::interprocess::uninitialized_copy_copy - (copy_move_it(old_start), copy_move_it(detail::get_pointer(pos)), first, last, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); //Now initialize the rest of memory with the last old values std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) - , copy_move_it(old_finish) - , detail::get_pointer(new_start) + elemsbefore + n); + (copy_move_it(pos), copy_move_it(old_finish), new_start + elemsbefore + n); //All new elements correctly constructed, avoid new element destruction new_values_destroyer.release(); this->members_.m_size = old_size + n; @@ -1376,17 +1374,13 @@ class vector : private detail::vector_alloc_holder //Copy first old values before pos, after that the //new objects boost::interprocess::uninitialized_copy_copy - ( copy_move_it(old_start) - , copy_move_it(detail::get_pointer(pos)) - , first, last, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); size_type raw_gap = s_before - (elemsbefore + n); //Now initialize the rest of s_before memory with the //first of elements after new values std::uninitialized_copy - ( copy_move_it(detail::get_pointer(pos)) - , copy_move_it(detail::get_pointer(pos) + raw_gap) - , detail::get_pointer(new_start) + elemsbefore + n); + (copy_move_it(pos), copy_move_it(pos + raw_gap), new_start + elemsbefore + n); //All new elements correctly constructed, avoid new element destruction new_values_destroyer.release(); //All new elements correctly constructed, avoid old element destruction @@ -1394,7 +1388,7 @@ class vector : private detail::vector_alloc_holder //Update size since we have a contiguous buffer this->members_.m_size = old_size + s_before; //Now copy remaining last objects in the old buffer begin - T *to_destroy = std::copy(assign_move_it(detail::get_pointer(pos) + raw_gap), assign_move_it(old_finish), old_start); + T *to_destroy = std::copy(assign_move_it(pos + raw_gap), assign_move_it(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; @@ -1460,24 +1454,22 @@ class vector : private detail::vector_alloc_holder //Copy the first part of old_begin to raw_mem T *start_n = old_start + difference_type(s_before); std::uninitialized_copy - ( copy_move_it(old_start) - , copy_move_it(start_n) - , detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(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 = std::copy(assign_move_it(start_n), assign_move_it(detail::get_pointer(pos)), old_start); + T* next = std::copy(assign_move_it(start_n), assign_move_it(pos), old_start); if(do_after){ //Now copy the new_beg elements - std::copy(first, before_end, detail::get_pointer(next)); + std::copy(first, before_end, next); } else{ //Now copy the all the new elements - T* move_start = std::copy(first, last, detail::get_pointer(next)); + T* move_start = std::copy(first, last, next); //Now displace old_end elements - T* move_end = std::copy(assign_move_it(detail::get_pointer(pos)), assign_move_it(old_finish), detail::get_pointer(move_start)); + T* move_end = std::copy(assign_move_it(pos), assign_move_it(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; @@ -1513,9 +1505,7 @@ class vector : private detail::vector_alloc_holder size_type n_new_init = difference_type(s_before) - elemsbefore; std::advance(mid, n_new_init); boost::interprocess::uninitialized_copy_copy - ( copy_move_it(old_start) - , copy_move_it(detail::get_pointer(pos)) - , first, mid, detail::get_pointer(new_start)); + (copy_move_it(old_start), copy_move_it(pos), first, mid, new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); @@ -1529,7 +1519,7 @@ class vector : private detail::vector_alloc_holder //Copy all new elements T* move_start = std::copy(mid, last, old_start); //Displace old_end - T* move_end = std::copy(copy_move_it(detail::get_pointer(pos)), copy_move_it(old_finish), detail::get_pointer(move_start)); + T* move_end = std::copy(copy_move_it(pos), copy_move_it(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; @@ -1584,14 +1574,12 @@ class vector : private detail::vector_alloc_holder //First copy the part of old_end raw_mem T* finish_n = old_finish - difference_type(n_after); std::uninitialized_copy - ( copy_move_it(detail::get_pointer(finish_n)) - , copy_move_it(old_finish) - , old_finish); + (copy_move_it(finish_n), copy_move_it(old_finish), old_finish); this->members_.m_size += n_after; //Displace the rest of old_end to the new position - std::copy_backward(assign_move_it(detail::get_pointer(pos)), assign_move_it(detail::get_pointer(finish_n)), old_finish); + std::copy_backward(assign_move_it(pos), assign_move_it(finish_n), old_finish); //Now overwrite with new_end - std::copy(first, last, detail::get_pointer(pos)); + std::copy(first, last, pos); } else { //The raw_mem from end will divide new_end part @@ -1610,13 +1598,10 @@ class vector : private detail::vector_alloc_holder std::advance(mid, elemsafter); //First initialize data in raw memory boost::interprocess::uninitialized_copy_copy - ( mid, last - , copy_move_it(detail::get_pointer(pos)) - , copy_move_it(old_finish) - , old_finish); + ( mid, last, copy_move_it(pos), copy_move_it(old_finish), old_finish); this->members_.m_size += n_after; //Now copy the part of new_end over constructed elements - std::copy(first, mid, detail::get_pointer(pos)); + std::copy(first, mid, pos); } } } diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index 233080d..ed61264 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -43,7 +43,7 @@ inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_) template inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_) { - new(dest)T(*source); + new((void*)dest)T(*source); } } //namespace detail { @@ -58,7 +58,7 @@ inline void construct_in_place(T* dest, InpIt source) template inline void construct_in_place(T *dest, default_construct_iterator) { - new(dest)T(); + new((void*)dest)T(); } template diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp index 4db523a..e872b53 100644 --- a/include/boost/interprocess/detail/config_begin.hpp +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -30,4 +30,5 @@ #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 #endif diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index aab0455..7e0c549 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -79,7 +79,7 @@ class move_return public: typedef T type; - move_return(T& returned) + move_return(const T& returned) : m_moved(moved_object(returned)) {} diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index 0ae2392..1c100c5 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -17,7 +17,7 @@ # pragma once #endif -//#include +#include namespace boost { namespace interprocess { @@ -121,6 +121,24 @@ struct identity { return x; } }; +template +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 { diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index 98a28ee..be6ee84 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -48,13 +48,13 @@ struct Ctor0Arg : public placement_destroy self_t operator++(int) { return *this; } void construct(void *mem) - { new(mem)T; } + { new((void*)mem)T; } virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) { - T* memory = static_cast(mem); + T* memory = (T*)(mem); for(constructed = 0; constructed < num; ++constructed) - new(memory++)T; + new((void*)memory++)T; } }; @@ -88,13 +88,13 @@ struct Ctor0Arg : public placement_destroy // : p1((P1 &)p_1), p2((P2 &)p_2) {} // // void construct(void *mem) -// { new(object)T(m_p1, m_p2); } +// { 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(mem); +// T* memory = (T*)(mem); // for(constructed = 0; constructed < num; ++constructed){ // this->construct(memory++, IsIterator()); // this->do_increment(IsIterator()); @@ -103,10 +103,10 @@ struct Ctor0Arg : public placement_destroy // // private: // void construct(void *mem, detail::true_) -// { new(mem)T(*m_p1, *m_p2); } +// { new((void*)mem)T(*m_p1, *m_p2); } // // void construct(void *mem, detail::false_) -// { new(mem)T(m_p1, m_p2); } +// { new((void*)mem)T(m_p1, m_p2); } // // P1 &m_p1; P2 &m_p2; // }; @@ -163,7 +163,7 @@ struct Ctor0Arg : public placement_destroy , std::size_t num \ , std::size_t &constructed) \ { \ - T* memory = static_cast(mem); \ + T* memory = (T*)(mem); \ for(constructed = 0; constructed < num; ++constructed){ \ this->construct(memory++, IsIterator()); \ this->do_increment(IsIterator()); \ @@ -172,10 +172,10 @@ struct Ctor0Arg : public placement_destroy \ private: \ void construct(void *mem, detail::true_) \ - { new(mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ + { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ \ void construct(void *mem, detail::false_) \ - { new(mem)T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \ + { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, m_p)); } \ \ BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ }; \ diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index 7cb2eef..a72e738 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -373,11 +373,24 @@ 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 struct ct_rounded_size { diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index b28ba68..4a48b5d 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -98,7 +98,7 @@ class 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 retries until time "abs_time" is reached. Returns true if + //!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, @@ -106,23 +106,23 @@ class message_queue //!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 full - //!the sender is blocked. Throws interprocess_error on error. + //!"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 full - //!the sender is not blocked and returns false, otherwise returns true. + //!"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 full - //!the sender is retries until time "abs_time" is reached. Returns true if + //!"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, diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 71a28fb..0e45ab4 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -45,6 +45,8 @@ 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 @@ -140,6 +142,7 @@ class mapped_region #endif friend class detail::interprocess_tester; + friend class detail::raw_mapped_region_creator; void dont_close_on_destruction(); /// @endcond }; @@ -362,9 +365,9 @@ inline void mapped_region::priv_close() m_base = 0; } #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) - if(m_file_mapping_hnd){ + if(m_file_mapping_hnd != detail::invalid_file()){ winapi::close_handle(m_file_mapping_hnd); - m_file_mapping_hnd = 0; + m_file_mapping_hnd = detail::invalid_file(); } #endif } diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index c98ec06..bc8b68d 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -281,6 +283,101 @@ class memory_algorithm_common return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0); } + 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_iterator allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index 88394ff..f011528 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -564,7 +564,7 @@ inline std::pair simple_seq_fit_impl:: T *reuse_ptr) { std::pair ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index f675f1d..639032e 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -651,7 +651,7 @@ inline std::pair rbtree_best_fit ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); @@ -776,26 +776,16 @@ void* rbtree_best_fit:: assert(prev_block->m_size == reuse->m_prev_size); algo_impl_t::assert_alignment(prev_block); - //Let's calculate the number of extra bytes of data before the current - //block's begin. The value is a multiple of backwards_multiple - std::size_t needs_backwards = preferred_size - - detail::get_truncated_size(received_size, backwards_multiple); - - const std::size_t lcm = detail::lcm(max_value(backwards_multiple, (std::size_t)Alignment) - ,min_value(backwards_multiple, (std::size_t)Alignment)); - - //If we want to use min_size data to get a buffer between preferred_size - //and min_size if preferred_size can't be achieved, calculate the - //biggest of all possibilities - if(!only_preferred_backwards){ - needs_backwards = min_size - detail::get_truncated_size(received_size, backwards_multiple); + 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; } - assert((needs_backwards % backwards_multiple) == 0); - - const std::size_t needs_backwards_aligned = - detail::get_rounded_size(needs_backwards, lcm); - //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 @@ -857,10 +847,8 @@ void* rbtree_best_fit:: m_header.m_imultiset.erase(Imultiset::s_iterator_to(*prev_block)); //Just merge the whole previous block - needs_backwards = detail::get_truncated_size - (prev_block->m_size*Alignment, backwards_multiple); - //received_size = received_size/backwards_multiple*backwards_multiple + needs_backwards; - received_size = received_size + needs_backwards; + //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 diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index c3853a1..627c440 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -53,9 +53,6 @@ class offset_ptr { /// @cond typedef offset_ptr self_t; - typedef const PointedType * const_pointer_t; - typedef typename detail::add_reference - ::type const_reference_t; void unspecified_bool_type_func() const {} typedef void (self_t::*unspecified_bool_type)() const; @@ -64,6 +61,9 @@ class offset_ptr __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 void*)ptr); } + + void set_offset(const void *ptr) { const char *p = static_cast(const_cast(ptr)); //offset == 1 && ptr != 0 is not legal for this pointer @@ -402,68 +402,44 @@ namespace intrusive { //Predeclaration to avoid including header template -struct has_pointer_plus_bit; +struct max_pointer_plus_bits; -template -struct has_pointer_plus_bit, N> +template +struct max_pointer_plus_bits, Alignment> { - static const bool value = (N % 4u == 0); + //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::value - 1; }; //Predeclaration -template -struct pointer_plus_bit; +template +struct pointer_plus_bits; -//Specialization -template -struct pointer_plus_bit > +template +struct pointer_plus_bits, NumBits> { typedef boost::interprocess::offset_ptr 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 (T*)(std::size_t(n.get()) & ~std::size_t(2u)); } + { return (T*)(std::size_t(n.get()) & ~std::size_t(Mask)); } static void set_pointer(pointer &n, pointer p) - { n = (T*)(std::size_t(p.get()) | (std::size_t(n.get()) & std::size_t(2u))); } - - static bool get_bit(const pointer &n) - { return 0 != (std::size_t(n.get()) & std::size_t(2u)); } - - static void set_bit(pointer &n, bool c) - { n = (T*)(std::size_t(get_pointer(n).get()) | (std::size_t(c) << 1u)); } -}; - -//Predeclaration to avoid including header -template -struct has_pointer_plus_2_bits; - -template -struct has_pointer_plus_2_bits, N> -{ - static const bool value = (N % 8u == 0); -}; - -//Predeclaration -template -struct pointer_plus_2_bits; - -template -struct pointer_plus_2_bits > -{ - typedef boost::interprocess::offset_ptr pointer; - - static pointer get_pointer(const pointer &n) - { return (T*)(std::size_t(n.get()) & ~std::size_t(6u)); } - - static void set_pointer(pointer &n, pointer p) - { n = (T*)(std::size_t(p.get()) | (std::size_t(n.get()) & std::size_t(6u))); } + { + std::size_t pint = std::size_t(p.get()); + assert(0 == (std::size_t(pint) & Mask)); + n = (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(6u)) >> 1u; } + { return(std::size_t(n.get()) & std::size_t(Mask)) >> 1u; } static void set_bits(pointer &n, std::size_t b) { - assert(b < 4); + assert(b < (std::size_t(1) << NumBits)); n = (T*)(std::size_t(get_pointer(n).get()) | (b << 1u)); } }; diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index d967809..bc3306c 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -86,11 +86,23 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, if(now >= abs_time) return false; } + typedef boost::interprocess::scoped_lock InternalLock; //The enter interprocess_mutex guarantees that while executing a notification, //no other thread can execute the do_timed_wait method. { //--------------------------------------------------------------- - boost::interprocess::scoped_lock lock(m_enter_mut); + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_enter_mut, abs_time); + lock = move(dummy); + } + else{ + InternalLock dummy(m_enter_mut); + lock = 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. @@ -146,7 +158,18 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, //Notification occurred, we will lock the checking interprocess_mutex so that //if a notify_one notification occurs, only one thread can exit //--------------------------------------------------------------- - boost::interprocess::scoped_lock lock(m_check_mut); + InternalLock lock; + if(tout_enabled){ + InternalLock dummy(m_check_mut, abs_time); + lock = move(dummy); + } + else{ + InternalLock dummy(m_check_mut); + lock = move(dummy); + } + + if(!lock) + return false; //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 ((boost::uint32_t*)&m_command, SLEEP, NOTIFY_ONE); diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index d9ef89f..ae3597a 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include //!\file @@ -106,62 +107,6 @@ class file_lock 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(!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 - winapi::sched_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(!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 - winapi::sched_yield(); - } - }while (true); - } - bool timed_acquire_file_lock (file_handle_t hnd, bool &acquired, const boost::posix_time::ptime &abs_time) { @@ -172,7 +117,7 @@ class file_lock if(now >= abs_time) return false; do{ - if(!try_acquire_file_lock(hnd, acquired)) + if(!detail::try_acquire_file_lock(hnd, acquired)) return false; if(acquired) @@ -185,7 +130,7 @@ class file_lock return true; } // relinquish current time slice - sleep(0); + detail::thread_yield(); } }while (true); } @@ -200,7 +145,7 @@ class file_lock if(now >= abs_time) return false; do{ - if(!try_acquire_file_lock_sharable(hnd, acquired)) + if(!detail::try_acquire_file_lock_sharable(hnd, acquired)) return false; if(acquired) @@ -213,7 +158,7 @@ class file_lock return true; } // relinquish current time slice - ::sleep(0); + detail::thread_yield(); } }while (true); } @@ -259,7 +204,7 @@ inline bool file_lock::try_lock() inline bool file_lock::timed_lock(const boost::posix_time::ptime &abs_time) { bool result; - if(!detail::timed_acquire_file_lock(m_file_hnd, result, abs_time)){ + if(!this->timed_acquire_file_lock(m_file_hnd, result, abs_time)){ error_info err(system_error_code()); throw interprocess_exception(err); } @@ -295,7 +240,7 @@ inline bool file_lock::try_lock_sharable() inline bool file_lock::timed_lock_sharable(const boost::posix_time::ptime &abs_time) { bool result; - if(!detail::timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){ + if(!this->timed_acquire_file_lock_sharable(m_file_hnd, result, abs_time)){ error_info err(system_error_code()); throw interprocess_exception(err); } diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index cfdbe13..c1d3c31 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -159,7 +159,9 @@ class named_condition //unlock internal first to avoid deadlock with near simultaneous waits lock_inverter inverted_lock(lock); scoped_lock > external_unlock(inverted_lock); - scoped_lock internal_lock(*this->mutex()); + if(!external_unlock) return false; + scoped_lock internal_lock(*this->mutex(), abs_time); + if(!internal_lock) return false; return this->condition()->timed_wait(internal_lock, abs_time); } #endif diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index c8b3c1a..912411a 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -169,7 +169,7 @@ inline mode_t windows_shared_memory::get_mode() const 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; + m_name = filename ? filename : ""; unsigned long file_map_access = 0; unsigned long map_access = 0; diff --git a/proj/to-do.txt b/proj/to-do.txt new file mode 100644 index 0000000..dc977b4 --- /dev/null +++ b/proj/to-do.txt @@ -0,0 +1,54 @@ +-> Implement zero_memory flag for allocation_command + +-> The general allocation funtion can be improved with some fixed size allocation bins. + +-> Adapt error reporting to TR1 system exceptions + +-> Improve exception messages + +-> Movability of containers should depend on the no-throw guarantee of allocators copy constructor + +-> Check self-assignment for vectors + +-> Update writing a new memory allocator explaining new functions (like alignment) + +-> private node allocators could take the number of nodes as a runtime parameter. + +-> Explain how to build intrusive indexes. + +-> Add intrusive index types as available indexes. + +-> Add maximum alignment allocation limit in PageSize bytes. Otherwise, we can't + guarantee alignment for process-shared allocations. + +-> Add default algorithm and index types. The user does not need to know how are + they implemented. + +-> Add private mapping to managed classes. + +-> Add unique_ptr documentation. + +-> Pass max size check in allocation to node pools + +-> Add atomic_func explanation in docs + +-> Once shrink to fit indexes is implemented test all memory has been deallocated + in tests to detect leaks/implementation failures. + +-> Improve allocate_many functions to allocate all the nodes forming a singly + linked list of nodes. + +-> Use in-place expansion capabilities to shrink_to_fit and reserve functions + from iunordered_index. + +-> Optimize copy_n with std::copy in vector. Revise other functions to improve optimizations + +-> Keep an eye on container iterator constness issue to bring Interprocess containers up-to-date. + +-> change unique_ptr to avoid using compressed_pair + +-> Improve unique_ptr test to test move assignment and other goodies like assigment from null + +-> barrier_test fails on MacOS X on PowerPC. + +-> void allocator instantiations fail. diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index 4758668..eed8eda 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -415,6 +415,34 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "offset_ptr_test", "offset_p ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_shared_memory", "doc_anonymous_shared_memory.vcproj", "{6DE178C3-12FE-6032-4FC7-879B63B9F651}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anonymous_shared_memory_test", "anonymous_shared_memory_test.vcproj", "{58DE8A13-4FA7-6252-36FE-B3A0A6D92812}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unordered_map", "doc_unordered_map.vcproj", "{9C185DF3-B75F-1928-8F6D-735108AABE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_multi_index", "doc_multi_index.vcproj", "{918C5DF3-1928-B73F-F626-7358518CBE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_test", "unordered_test.vcproj", "{C3CE1183-09F2-A46A-4FE6-D06BA7923A02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_index_test", "multi_index_test.vcproj", "{9285DFD3-1928-F662-CB73-73518CB53A62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_lock_test", "file_lock_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792639}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -839,6 +867,34 @@ Global {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.ActiveCfg = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.Build.0 = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.ActiveCfg = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.Build.0 = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.ActiveCfg = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.Build.0 = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.ActiveCfg = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.Build.0 = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.ActiveCfg = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.Build.0 = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.ActiveCfg = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.Build.0 = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.ActiveCfg = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.Build.0 = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.ActiveCfg = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.Build.0 = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.ActiveCfg = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.Build.0 = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.ActiveCfg = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.Build.0 = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.ActiveCfg = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.Build.0 = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.ActiveCfg = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/anonymous_shared_memory_test.vcproj b/proj/vc7ide/anonymous_shared_memory_test.vcproj new file mode 100644 index 0000000..4b81afc --- /dev/null +++ b/proj/vc7ide/anonymous_shared_memory_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_anonymous_shared_memory.vcproj b/proj/vc7ide/doc_anonymous_shared_memory.vcproj new file mode 100644 index 0000000..cd5d7a4 --- /dev/null +++ b/proj/vc7ide/doc_anonymous_shared_memory.vcproj @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_multi_index.vcproj b/proj/vc7ide/doc_multi_index.vcproj new file mode 100644 index 0000000..5a29cee --- /dev/null +++ b/proj/vc7ide/doc_multi_index.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/doc_unordered_map.vcproj b/proj/vc7ide/doc_unordered_map.vcproj new file mode 100644 index 0000000..a08a8ea --- /dev/null +++ b/proj/vc7ide/doc_unordered_map.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/file_lock_test.vcproj b/proj/vc7ide/file_lock_test.vcproj new file mode 100644 index 0000000..3e311dc --- /dev/null +++ b/proj/vc7ide/file_lock_test.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 5ccbb82..0f79970 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -315,6 +315,9 @@ Name="Managed Memory Classes" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + + diff --git a/proj/vc7ide/multi_index_test.vcproj b/proj/vc7ide/multi_index_test.vcproj new file mode 100644 index 0000000..5d2a807 --- /dev/null +++ b/proj/vc7ide/multi_index_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unordered_test.vcproj b/proj/vc7ide/unordered_test.vcproj new file mode 100644 index 0000000..6c91a73 --- /dev/null +++ b/proj/vc7ide/unordered_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/adaptive_node_pool_test.cpp b/test/adaptive_node_pool_test.cpp index 866b8f3..11ce510 100644 --- a/test/adaptive_node_pool_test.cpp +++ b/test/adaptive_node_pool_test.cpp @@ -11,6 +11,8 @@ #include "node_pool_test.hpp" #include +#include + int main () { using namespace boost::interprocess; diff --git a/test/adaptive_pool_test.cpp b/test/adaptive_pool_test.cpp index 7b36131..196d0d5 100644 --- a/test/adaptive_pool_test.cpp +++ b/test/adaptive_pool_test.cpp @@ -41,7 +41,6 @@ typedef list MyShmListV1; typedef vector MyShmVector; typedef vector MyShmVectorV1; - int main () { if(test::list_test()) diff --git a/test/allocator_v1.hpp b/test/allocator_v1.hpp index 6504df9..b46c3c4 100644 --- a/test/allocator_v1.hpp +++ b/test/allocator_v1.hpp @@ -114,17 +114,17 @@ class allocator_v1 //!Deallocates memory previously allocated. Never throws void deallocate(const pointer &ptr, size_type) - { mp_mngr->deallocate(detail::get_pointer(ptr)); } -/* + { mp_mngr->deallocate((void*)detail::get_pointer(ptr)); } + //!Construct object, calling constructor. //!Throws if T(const T&) throws void construct(const pointer &ptr, const_reference value) - { new(detail::get_pointer(ptr)) value_type(value); } + { new((void*)detail::get_pointer(ptr)) value_type(value); } //!Destroys object. Throws if object's destructor throws void destroy(const pointer &ptr) { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } -*/ + //!Returns the number of elements that could be allocated. Never throws size_type max_size() const { return mp_mngr->get_size(); } diff --git a/test/anonymous_shared_memory_test.cpp b/test/anonymous_shared_memory_test.cpp new file mode 100644 index 0000000..43ac48b --- /dev/null +++ b/test/anonymous_shared_memory_test.cpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-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. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +using namespace boost::interprocess; + +int main () +{ + try{ + const std::size_t MemSize = 99999*2; + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(MemSize)); + + //Write pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + *pattern = static_cast(i); + } + + //Check pattern + pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < MemSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } + } + } + } + catch(std::exception &exc){ + std::cout << "Unhandled exception: " << exc.what() << std::endl; + return 1; + } + return 0; +} + +#include diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index af691f9..7c66735 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -82,26 +82,26 @@ class dummy_test_allocator template dummy_test_allocator(const dummy_test_allocator &) {} -/* + pointer address(reference value) { return pointer(addressof(value)); } const_pointer address(const_reference value) const { return const_pointer(addressof(value)); } -*/ + pointer allocate(size_type, cvoid_ptr = 0) { return 0; } void deallocate(const pointer &, size_type) { } -/* + template void construct(pointer, const Convertible &) {} void destroy(pointer) {} -*/ + size_type max_size() const { return 0; } diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 840a45e..0a62b33 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -85,26 +85,26 @@ class expand_bwd_test_allocator expand_bwd_test_allocator(const expand_bwd_test_allocator &other) : mp_buffer(other.mp_buffer), m_size(other.m_size) , m_offset(other.m_offset), m_allocations(0){ } -/* + pointer address(reference value) { return pointer(addressof(value)); } const_pointer address(const_reference value) const { return const_pointer(addressof(value)); } -*/ + pointer allocate(size_type , cvoid_ptr hint = 0) { (void)hint; return 0; } void deallocate(const pointer &, size_type) {} -/* + template void construct(pointer ptr, const Convertible &value) { new((void*)ptr) value_type(value); } void destroy(pointer ptr) { (*ptr).~value_type(); } -*/ + size_type max_size() const { return m_size; } diff --git a/test/expand_bwd_test_template.hpp b/test/expand_bwd_test_template.hpp index 4ccf0ca..4a61d92 100644 --- a/test/expand_bwd_test_template.hpp +++ b/test/expand_bwd_test_template.hpp @@ -15,6 +15,7 @@ #include #include "expand_bwd_test_allocator.hpp" #include +#include namespace boost { namespace interprocess { namespace test { @@ -107,7 +108,8 @@ template bool test_insert_with_expand_bwd() { typedef typename VectorWithExpandBwdAllocator::value_type value_type; - typedef std::vector Vect; + typedef typename boost::remove_volatile::type non_volatile_value_type; + typedef std::vector Vect; const int MemorySize = 1000; //Distance old and new buffer @@ -131,37 +133,42 @@ bool test_insert_with_expand_bwd() for(int iteration = 0; iteration < Iterations; ++iteration) { - Vect memory; - memory.resize(MemorySize); + value_type *memory = new value_type[MemorySize]; + try { + std::vector initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } - Vect initial_data; - initial_data.resize(InitialSize[iteration]); - for(int i = 0; i < InitialSize[iteration]; ++i){ - initial_data[i] = value_type(i); - } + Vect data_to_insert; + data_to_insert.resize(InsertSize[iteration]); + for(int i = 0; i < InsertSize[iteration]; ++i){ + data_to_insert[i] = -i; + } - Vect data_to_insert; - data_to_insert.resize(InsertSize[iteration]); - for(int i = 0; i < InsertSize[iteration]; ++i){ - data_to_insert[i] = value_type(-i); + expand_bwd_test_allocator alloc + ((value_type*)&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + vector.insert( vector.begin() + Position[iteration] + , data_to_insert.begin(), data_to_insert.end()); + initial_data.insert(initial_data.begin() + Position[iteration] + , data_to_insert.begin(), data_to_insert.end()); + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } } - - expand_bwd_test_allocator alloc - (&memory[0], memory.size(), Offset[iteration]); - VectorWithExpandBwdAllocator vector(alloc); - vector.insert( vector.begin() - , initial_data.begin(), initial_data.end()); - vector.insert( vector.begin() + Position[iteration] - , data_to_insert.begin(), data_to_insert.end()); - initial_data.insert(initial_data.begin() + Position[iteration] - , data_to_insert.begin(), data_to_insert.end()); - //Now check that values are equal - if(!CheckEqualVector(vector, initial_data)){ - std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl - << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl - << " Iteration: " << iteration << std::endl; - return false; + catch(...){ + delete []((non_volatile_value_type*)memory); + throw; } + delete []((non_volatile_value_type*)memory); } return true; @@ -173,7 +180,8 @@ template bool test_assign_with_expand_bwd() { typedef typename VectorWithExpandBwdAllocator::value_type value_type; - typedef std::vector Vect; + typedef typename boost::remove_volatile::type non_volatile_value_type; + typedef std::vector Vect; const int MemorySize = 200; const int Offset[] = { 50, 50, 50}; @@ -183,41 +191,46 @@ bool test_assign_with_expand_bwd() for(int iteration = 0; iteration initial_data; + initial_data.resize(InitialSize[iteration]); + for(int i = 0; i < InitialSize[iteration]; ++i){ + initial_data[i] = i; + } - //Create initial data - Vect initial_data; - initial_data.resize(InitialSize[iteration]); - for(int i = 0; i < InitialSize[iteration]; ++i){ - initial_data[i] = i; + //Create data to assign + std::vector data_to_assign; + data_to_assign.resize(AssignSize[iteration]); + for(int i = 0; i < AssignSize[iteration]; ++i){ + data_to_assign[i] = -i; + } + + //Insert initial data to the vector to test + expand_bwd_test_allocator alloc + (&memory[0], MemorySize, Offset[iteration]); + VectorWithExpandBwdAllocator vector(alloc); + vector.insert( vector.begin() + , initial_data.begin(), initial_data.end()); + + //Assign data + vector.assign(data_to_assign.begin(), data_to_assign.end()); + initial_data.assign(data_to_assign.begin(), data_to_assign.end()); + + //Now check that values are equal + if(!CheckEqualVector(vector, initial_data)){ + std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl + << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl + << " Iteration: " << iteration << std::endl; + return false; + } } - - //Create data to assign - Vect data_to_assign; - data_to_assign.resize(AssignSize[iteration]); - for(int i = 0; i < AssignSize[iteration]; ++i){ - data_to_assign[i] = -i; - } - - //Insert initial data to the vector to test - expand_bwd_test_allocator alloc - (&memory[0], memory.size(), Offset[iteration]); - VectorWithExpandBwdAllocator vector(alloc); - vector.insert( vector.begin() - , initial_data.begin(), initial_data.end()); - - //Assign data - vector.assign(data_to_assign.begin(), data_to_assign.end()); - initial_data.assign(data_to_assign.begin(), data_to_assign.end()); - - //Now check that values are equal - if(!CheckEqualVector(vector, initial_data)){ - std::cout << "test_assign_with_expand_bwd::CheckEqualVector failed." << std::endl - << " Class: " << typeid(VectorWithExpandBwdAllocator).name() << std::endl - << " Iteration: " << iteration << std::endl; - return false; + catch(...){ + delete []((typename boost::remove_volatile::type*)memory); + throw; } + delete []((typename boost::remove_volatile::type*)memory); } return true; diff --git a/test/file_lock_test.cpp b/test/file_lock_test.cpp new file mode 100644 index 0000000..be0311c --- /dev/null +++ b/test/file_lock_test.cpp @@ -0,0 +1,62 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include "mutex_test_template.hpp" +#include "sharable_mutex_test_template.hpp" +#include "get_process_id_name.hpp" +#include +#include + +using namespace boost::interprocess; +//This wrapper is necessary to have a default constructor +//in generic mutex_test_template functions +class file_lock_lock_test_wrapper + : public boost::interprocess::file_lock +{ + public: + file_lock_lock_test_wrapper() + : boost::interprocess::file_lock(test::get_process_id_name()) + {} +}; + +int main () +{ + //Destroy and create file + { + std::remove(test::get_process_id_name()); + std::ofstream file(test::get_process_id_name()); + if(!file){ + return 1; + } + file_lock flock(test::get_process_id_name()); + { + scoped_lock sl(flock); + } + { + scoped_lock sl(flock, try_to_lock); + } + { + scoped_lock sl(flock, test::delay(1)); + } + } + + //test::test_all_lock(); + //test::test_all_mutex(); + //test::test_all_sharable_mutex(); + std::remove(test::get_process_id_name()); + + return 0; +} + +#include diff --git a/test/list_test.cpp b/test/list_test.cpp index a083d91..e2073fe 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -26,6 +26,9 @@ template class boost::interprocess::list ShmemAllocator; typedef list MyList; +typedef allocator ShmemVolatileAllocator; +typedef list MyVolatileList; + typedef allocator ShmemMoveAllocator; typedef list MyMoveList; @@ -37,6 +40,9 @@ int main () if(test::list_test()) return 1; + if(test::list_test()) + return 1; + if(test::list_test()) return 1; diff --git a/test/multi_index_test.cpp b/test/multi_index_test.cpp new file mode 100644 index 0000000..40ce912 --- /dev/null +++ b/test/multi_index_test.cpp @@ -0,0 +1,149 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace boost::interprocess; +namespace bmi = boost::multi_index; + +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator>shm_string; + +//Data to insert in shared memory +struct employee +{ + int id; + int age; + shm_string name; + employee( int id_ + , int age_ + , const char *name_ + , const char_allocator &a) + : id(id_), age(age_), name(name_, a) + {} +}; + +//Tags +struct id{}; +struct age{}; +struct name{}; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + allocator +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + adaptive_pool +>; +/* +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + cached_adaptive_pool +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + private_adaptive_pool +>; +*/ +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + node_allocator +>; +/* +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + cached_node_allocator +>; + +// Explicit instantiations to catch compile-time errors +template class bmi::multi_index_container< + employee, + bmi::indexed_by< + bmi::ordered_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, + bmi::ordered_non_unique< + bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, + bmi::ordered_non_unique + , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, + private_node_allocator +>; +*/ +int main () +{ + return 0; +} + +#include diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 723659c..036adb7 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "get_process_id_name.hpp" @@ -113,6 +114,28 @@ int main () } } } + { + //Now check anonymous mapping + mapped_region region(anonymous_shared_memory(FileSize)); + + //Write pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + *pattern = static_cast(i); + } + + //Check pattern + pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } + } + } } catch(std::exception &exc){ shared_memory_object::remove(test::get_process_id_name()); diff --git a/test/tree_test.cpp b/test/tree_test.cpp index eea66a1..2535ec6 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -61,7 +61,7 @@ template class boost::interprocess::multimap //Customize managed_shared_memory class typedef basic_managed_shared_memory , + simple_seq_fit >, map_index > my_managed_shared_memory; diff --git a/test/unordered_test.cpp b/test/unordered_test.cpp new file mode 100644 index 0000000..9604a32 --- /dev/null +++ b/test/unordered_test.cpp @@ -0,0 +1,94 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "get_process_id_name.hpp" +#include +#include + +#include //std::equal_to +#include //boost::hash + +namespace bip = boost::interprocess; + +typedef bip::allocator ShmemAllocator; +typedef boost::unordered_set, std::equal_to, ShmemAllocator> MyUnorderedSet; +typedef boost::unordered_multiset, std::equal_to, ShmemAllocator> MyUnorderedMultiSet; + +//Explicit instantiation to catch compile-time errors +template class boost::unordered_set, std::equal_to, ShmemAllocator>; +template class boost::unordered_multiset, std::equal_to, ShmemAllocator>; + +int main() +{ + //Remove any other old shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + try { + bip::managed_shared_memory shm(bip::create_only, bip::test::get_process_id_name(), 65536); + + //Elements to be inserted in unordered containers + const int elements[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + const int elements_size = sizeof(elements)/sizeof(elements[0]); + + MyUnorderedSet *myset = + shm.construct(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator()); + MyUnorderedMultiSet *mymset = + shm.construct(bip::anonymous_instance) + ( elements_size + , MyUnorderedSet::hasher() + , MyUnorderedSet::key_equal() + , shm.get_allocator()); + + //Insert elements and check sizes + myset->insert((&elements[0]), (&elements[elements_size])); + myset->insert((&elements[0]), (&elements[elements_size])); + mymset->insert((&elements[0]), (&elements[elements_size])); + mymset->insert((&elements[0]), (&elements[elements_size])); + + if(myset->size() != (unsigned int)elements_size) + return 1; + if(mymset->size() != (unsigned int)elements_size*2) + return 1; + + //Destroy elements and check sizes + myset->clear(); + mymset->clear(); + + if(!myset->empty()) + return 1; + if(!mymset->empty()) + return 1; + + //Destroy elements and check if memory has been deallocated + shm.destroy_ptr(myset); + shm.destroy_ptr(mymset); + + shm.shrink_to_fit_indexes(); + if(!shm.all_memory_deallocated()) + return 1; + + } + catch(...){ + //Remove shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + throw; + } + //Remove shared memory from the system + bip::shared_memory_object::remove(bip::test::get_process_id_name()); + return 0; +} + +#include diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 0e76115..206b0d0 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -44,7 +44,16 @@ int test_expand_bwd() if(!test::test_all_expand_bwd()) return 1; +/* + //First raw volatile ints + typedef test::expand_bwd_test_allocator + volatile_int_allocator_type; + typedef vector + volatile_int_vector; + if(!test::test_all_expand_bwd()) + return 1; +*/ //Now user defined wrapped int typedef test::expand_bwd_test_allocator int_holder_allocator_type; @@ -72,6 +81,9 @@ int main() typedef allocator ShmemAllocator; typedef vector MyVector; + //typedef allocator ShmemVolatileAllocator; + //typedef vector MyVolatileVector; + typedef allocator ShmemMoveAllocator; typedef vector MyMoveVector; @@ -81,6 +93,9 @@ int main() if(test::vector_test()) return 1; + //if(test::vector_test()) + //return 1; + if(test::vector_test()) return 1; diff --git a/test/windows_shared_memory_mapping_test.cpp b/test/windows_shared_memory_mapping_test.cpp index 6358e41..a5a20ab 100644 --- a/test/windows_shared_memory_mapping_test.cpp +++ b/test/windows_shared_memory_mapping_test.cpp @@ -23,98 +23,93 @@ using namespace boost::interprocess; int main () { - std::string process_name; - test::get_process_id_name(process_name); - try{ - const std::size_t FileSize = 99999*2; - //Create shared memory and file mapping - windows_shared_memory mapping(create_only, process_name.c_str(), read_write, FileSize); - + const char *names[2] = { test::get_process_id_name(), 0 }; + for(unsigned int i = 0; i < sizeof(names)/sizeof(names[0]); ++i) { + const std::size_t FileSize = 99999*2; //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_write); + windows_shared_memory mapping + (create_only, names[i], read_write, FileSize); - //Create two mapped regions, one half of the file each - mapped_region region (mapping - ,read_write - ,0 - ,FileSize/2 - ,0); + { - mapped_region region2(mapping - ,read_write - ,FileSize/2 - ,FileSize - FileSize/2 - ,0); + //Create two mapped regions, one half of the file each + mapped_region region (mapping + ,read_write + ,0 + ,FileSize/2 + ,0); - //Fill two regions with a pattern - unsigned char *filler = static_cast(region.get_address()); - for(std::size_t i = 0 - ;i < FileSize/2 - ;++i){ - *filler++ = static_cast(i); - } + mapped_region region2(mapping + ,read_write + ,FileSize/2 + ,FileSize - FileSize/2 + ,0); - filler = static_cast(region2.get_address()); - for(std::size_t i = FileSize/2 - ;i < FileSize - ;++i){ - *filler++ = static_cast(i); - } - } + //Fill two regions with a pattern + unsigned char *filler = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + *filler++ = static_cast(i); + } - //See if the pattern is correct in the file using two mapped regions - { - //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_write); - mapped_region region(mapping, read_write, 0, FileSize/2, 0); - mapped_region region2(mapping, read_write, FileSize/2, 0/*FileSize - FileSize/2*/, 0); - - unsigned char *checker = (unsigned char*)region.get_address(); - //Check pattern - for(std::size_t i = 0 - ;i < FileSize/2 - ;++i){ - if(*checker++ != static_cast(i)){ - return 1; + filler = static_cast(region2.get_address()); + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + *filler++ = static_cast(i); } } - //Check second half - checker = (unsigned char *)region2.get_address(); + //See if the pattern is correct in the file using two mapped regions + { + mapped_region region (mapping, read_only, 0, FileSize/2, 0); + mapped_region region2(mapping, read_only, FileSize/2, FileSize - FileSize/2, 0); - //Check pattern - for(std::size_t i = FileSize/2 - ;i < FileSize - ;++i){ - if(*checker++ != static_cast(i)){ - return 1; + unsigned char *checker = (unsigned char*)region.get_address(); + //Check pattern + for(std::size_t i = 0 + ;i < FileSize/2 + ;++i){ + if(*checker++ != static_cast(i)){ + return 1; + } + } + + //Check second half + checker = (unsigned char *)region2.get_address(); + + //Check pattern + for(std::size_t i = FileSize/2 + ;i < FileSize + ;++i){ + if(*checker++ != static_cast(i)){ + return 1; + } } } - } - //Now check the pattern mapping a single read only mapped_region - { - //Create a file mapping - windows_shared_memory mapping(open_only, process_name.c_str(), read_only); + //Now check the pattern mapping a single read only mapped_region + { + //Create a single regions, mapping all the file + mapped_region region (mapping, read_only); - //Create a single regions, mapping all the file - mapped_region region (mapping - ,read_only); - - //Check pattern - unsigned char *pattern = static_cast(region.get_address()); - for(std::size_t i = 0 - ;i < FileSize - ;++i, ++pattern){ - if(*pattern != static_cast(i)){ - return 1; + //Check pattern + unsigned char *pattern = static_cast(region.get_address()); + for(std::size_t i = 0 + ;i < FileSize + ;++i, ++pattern){ + if(*pattern != static_cast(i)){ + return 1; + } } } } } catch(std::exception &exc){ + //shared_memory_object::remove(test::get_process_id_name()); std::cout << "Unhandled exception: " << exc.what() << std::endl; return 1; } diff --git a/test/windows_shared_memory_test.cpp b/test/windows_shared_memory_test.cpp index 4250241..2f8512e 100644 --- a/test/windows_shared_memory_test.cpp +++ b/test/windows_shared_memory_test.cpp @@ -68,6 +68,7 @@ int main () std::cout << ex.what() << std::endl; return 1; } + return 0; } From ba80ed3c10b8ab5a320fa15b58b0cbf16d677d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 2 May 2008 11:07:08 +0000 Subject: [PATCH 16/77] Tickets #1883, #1862, #1709 [SVN r45019] --- include/boost/interprocess/allocators/allocator.hpp | 8 +++++--- .../interprocess/allocators/private_adaptive_pool.hpp | 7 +++++-- .../interprocess/allocators/private_node_allocator.hpp | 7 +++++-- test/node_pool_test.hpp | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index f5cbbb1..cfb4730 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -48,15 +48,17 @@ namespace interprocess { template class allocator { + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + /// @cond private: //Self type typedef allocator self_t; - //Segment manager - typedef SegmentManager segment_manager; - //Pointer to void typedef typename segment_manager::void_pointer aux_pointer_t; diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index 0e34ba4..dd26ef9 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -55,10 +55,13 @@ class private_adaptive_pool_base , SegmentManager > { + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + /// @cond private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef SegmentManager segment_manager; typedef private_adaptive_pool_base < Version, T, SegmentManager, NodesPerChunk , MaxFreeChunks, OverheadPercent> self_t; diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index 9db03a6..2d75584 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -62,10 +62,13 @@ class private_node_allocator_base , SegmentManager > { + public: + //Segment manager + typedef SegmentManager segment_manager; + typedef typename SegmentManager::void_pointer void_pointer; + /// @cond private: - typedef typename SegmentManager::void_pointer void_pointer; - typedef SegmentManager segment_manager; typedef private_node_allocator_base < Version, T, SegmentManager, NodesPerChunk> self_t; typedef detail::private_node_pool diff --git a/test/node_pool_test.hpp b/test/node_pool_test.hpp index 2e2b608..eae0038 100644 --- a/test/node_pool_test.hpp +++ b/test/node_pool_test.hpp @@ -136,7 +136,7 @@ bool test_all_node_pool() typedef boost::interprocess::test::test_node_pool test_node_pool_t; shared_memory_object::remove(test::get_process_id_name()); { - managed_shared_memory shm(create_only, test::get_process_id_name(), 16*1024); + managed_shared_memory shm(create_only, test::get_process_id_name(), 4*1024*sizeof(void*)); typedef deleter deleter_t; typedef unique_ptr unique_ptr_t; From 2ff7425fd9406b9e5ab0fbf774e814b523ac0367 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 8 May 2008 21:42:56 +0000 Subject: [PATCH 17/77] Replace some non-ASCII characters in the interprocess library headers. [SVN r45231] --- include/boost/interprocess/containers/flat_map.hpp | 4 ++-- include/boost/interprocess/containers/flat_set.hpp | 4 ++-- include/boost/interprocess/containers/map.hpp | 4 ++-- include/boost/interprocess/containers/set.hpp | 4 ++-- include/boost/interprocess/errors.hpp | 2 +- .../boost/interprocess/smart_ptr/unique_ptr.hpp | 14 +++++++------- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 0478e2c..8901471 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -210,7 +210,7 @@ class flat_map { return value_compare(force(m_flat_tree.key_comp())); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -853,7 +853,7 @@ class flat_multimap { return value_compare(force(m_flat_tree.key_comp())); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index d98677a..b5db427 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -157,7 +157,7 @@ class flat_set { return m_flat_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -665,7 +665,7 @@ class flat_multiset { return m_flat_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index b8d45f3..575c633 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -206,7 +206,7 @@ class map { return value_compare(m_tree.key_comp()); } //! Effects: Returns a copy of the Allocator that - //! was passed to the objects constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -856,7 +856,7 @@ class multimap { return value_compare(m_tree.key_comp()); } //! Effects: Returns a copy of the Allocator that - //! was passed to the objects constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index bc4b364..cb0443b 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -183,7 +183,7 @@ class set { return m_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const @@ -672,7 +672,7 @@ class multiset { return m_tree.key_comp(); } //! Effects: Returns a copy of the Allocator that - //! was passed to the object’s constructor. + //! was passed to the object's constructor. //! //! Complexity: Constant. allocator_type get_allocator() const diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index ec17f0b..4f157a7 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -11,7 +11,7 @@ ////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2002 Beman Dawes -// Copyright (c) 2001 Dietmar Kühl +// 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) diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index 0cade7b..f988028 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -138,11 +138,11 @@ class unique_ptr //! //!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. + //!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 - //!std::forward. —end note ] + //!std::forward. -end note ] //! //!Postconditions: get() == value u.get() had before the construction. //!get_deleter() returns a reference to the internally stored deleter which @@ -168,8 +168,8 @@ class unique_ptr //! //!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. + //!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. //! @@ -221,7 +221,7 @@ class unique_ptr //!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 + //!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 @@ -250,7 +250,7 @@ class unique_ptr //!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 + //!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. //! @@ -356,7 +356,7 @@ class unique_ptr //!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 swap’d (unqualified). + //!Effects: The stored pointers of this and u are exchanged. The stored deleters are swap'd (unqualified). //! //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE From c3b9801811b832ed53618e19603836eb15fa72cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 12 May 2008 19:38:37 +0000 Subject: [PATCH 18/77] Replaced non-ascii characters, ticket 1736 [SVN r45306] --- doc/Jamfile.v2 | 2 +- example/Jamfile.v2 | 2 +- test/Jamfile.v2 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9cb17de..9474715 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost.Interprocess library documentation Jamfile --------------------------------- # -# Copyright Ion Gaztañaga 2005-2007. Use, modification and +# Copyright Ion Gaztanaga 2005-2007. 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) diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 09309d4..eb26876 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost Interprocess Library Example Jamfile -# (C) Copyright Ion Gaztañaga 2006. +# (C) Copyright Ion Gaztanaga 2006. # Use, modification and distribution are 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) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8b3e8ec..a070a7e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost Interprocess Library Test Jamfile -# (C) Copyright Ion Gaztañaga 2006. +# (C) Copyright Ion Gaztanaga 2006. # Use, modification and distribution are 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) From c35c6680b211822909bad243980163a97690bdb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:13:10 +0000 Subject: [PATCH 19/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45692] --- doc/interprocess.qbk | 28 +- example/doc_managed_copy_on_write.cpp | 67 +++ proj/to-do.txt | 6 + proj/vc7ide/Interprocess.sln | 16 + proj/vc7ide/doc_managed_copy_on_write.vcproj | 134 ++++++ proj/vc7ide/intersegment_ptr_test.vcproj | 133 ++++++ test/cached_adaptive_pool_test.cpp | 1 + test/cached_node_allocator_test.cpp | 1 + test/file_mapping_test.cpp | 7 + test/intersegment_ptr_test.cpp | 404 +++++++++++++++++++ test/managed_mapped_file_test.cpp | 36 ++ test/managed_shared_memory_test.cpp | 35 ++ test/managed_windows_shared_memory_test.cpp | 63 ++- test/mapped_file_test.cpp | 5 + test/node_allocator_test.cpp | 1 + test/node_pool_test.hpp | 36 +- test/private_adaptive_pool_test.cpp | 1 + test/private_node_allocator_test.cpp | 1 + test/shared_memory_mapping_test.cpp | 7 + test/shared_memory_test.cpp | 5 + test/user_buffer_test.cpp | 12 + test/vector_test.hpp | 4 +- 22 files changed, 966 insertions(+), 37 deletions(-) create mode 100644 example/doc_managed_copy_on_write.cpp create mode 100644 proj/vc7ide/doc_managed_copy_on_write.vcproj create mode 100644 proj/vc7ide/intersegment_ptr_test.vcproj create mode 100644 test/intersegment_ptr_test.cpp diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 0b6096c..3c4870f 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -3096,6 +3096,8 @@ To use a managed shared memory, you must include the following header: // managed_shared_memory segment (open_only, "MySharedMemory");//Shared memory object name[c++] +[c++] + //1. If the segment was previously created // equivalent to "open_only". //2. Otherwise, equivalent to "open_only" (size is ignored) @@ -3258,6 +3260,21 @@ The following features are common to all managed memory segment classes, but we will use managed shared memory in our examples. We can do the same with memory mapped files or other managed memory segment classes. +[section:copy_on_write Opening managed shared memory and mapped files with Copy On Write mode] + +When mapping a memory segment based on shared memory or files, there is an option to +open them using `open_copy_on_write` option. This option is similar to `open_only` but +every change the programmer does with this managed segment is kept private to this process +and is not translated to the underlying device (shared memory or file). + +The underlying shared memory or file is opened as read-only so several processes can +share an initial managed segment and make private changes to it. Here's an example: + +[import ../example/doc_managed_copy_on_write.cpp] +[doc_managed_copy_on_write] + +[endsect] + [section:allocate_deallocate Allocating fragments of a managed memory segment] If a basic raw-byte allocation is needed from a managed memory @@ -3888,7 +3905,7 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * If the parameter `command` only contains the value `expand_bwd` (with optional additional `nothrow_allocation`), the allocator will try to increase the size of the memory block referenced by pointer `reuse_ptr` only moving the start of the - block to a returned new position new_ptr. If it's not possible, it will try to + block to a returned new position `new_ptr`. If it's not possible, it will try to move the start of the block as much as possible as long as this results in `size(new_ptr) >= limit_size`. Success is reported only if this results in `limit_size <= size(new_ptr)`. @@ -3896,7 +3913,7 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * If the parameter `command` only contains the value `allocate_new` (with optional additional `nothrow_allocation`), the allocator will try to allocate memory for `preferred_size` objects. If it's not possible it will try to allocate memory for - at least limit_size` objects. + at least `limit_size` objects. * If the parameter `command` only contains a combination of `expand_fwd` and `allocate_new`, (with optional additional `nothrow_allocation`) the allocator will @@ -3951,8 +3968,8 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * If the user chooses `char` as template argument and a backwards expansion is performed, although properly aligned, the returned buffer might not be suitable because the distance between the new beginning and the old beginning - might not multiple of the type the user wants to construct, because due to internal - restriction the expansion can be slightly bigger than the requested. [*When + might not multiple of the type the user wants to construct, since due to internal + restrictions the expansion can be slightly bigger than the requested bytes. [*When performing backwards expansion, if you have already constructed objects in the old buffer, make sure to specify correctly the type.] @@ -6456,6 +6473,9 @@ warranty. [section:release_notes_boost_1_36_00 Boost 1.36 Release] * Added anonymous shared memory for UNIX systems. +* Fixed erroneous `void` return types from `flat_map::erase()` functions. +* Fixed missing move semantics on managed memory classes. +* Added copy_on_write option for shared memory and mapped file managed classes. [endsect] diff --git a/example/doc_managed_copy_on_write.cpp b/example/doc_managed_copy_on_write.cpp new file mode 100644 index 0000000..5acda74 --- /dev/null +++ b/example/doc_managed_copy_on_write.cpp @@ -0,0 +1,67 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_managed_copy_on_write +#include +#include //std::fstream +#include //std::remove + +int main() +{ + using namespace boost::interprocess; + + //Try to erase any previous managed segment with the same name + std::remove("MyManagedFile"); + std::remove("MyManagedFile2"); + + try{ + //Create an named integer in a managed mapped file + managed_mapped_file managed_file(create_only, "MyManagedFile", 65536); + managed_file.construct("MyInt")(0u); + + //Now create a copy on write version + managed_mapped_file managed_file_cow(open_copy_on_write, "MyManagedFile"); + + //Erase the int and create a new one + if(!managed_file_cow.destroy("MyInt")) + throw int(0); + managed_file_cow.construct("MyInt2"); + + //Check changes + if(managed_file_cow.find("MyInt").first && !managed_file_cow.find("MyInt2").first) + throw int(0); + + //Check the original is intact + if(!managed_file.find("MyInt").first && managed_file.find("MyInt2").first) + throw int(0); + + { //Dump the modified copy on write segment to a file + std::fstream file("MyManagedFile2", std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); + if(!file) + throw int(0); + file.write((const char *)managed_file_cow.get_address(), managed_file_cow.get_size()); + } + + //Now open the modified file and test changes + managed_mapped_file managed_file_cow2(open_only, "MyManagedFile2"); + if(managed_file_cow2.find("MyInt").first && !managed_file_cow2.find("MyInt2").first) + throw int(0); + } + catch(...){ + std::remove("MyManagedFile"); + std::remove("MyManagedFile2"); + throw; + } + std::remove("MyManagedFile"); + std::remove("MyManagedFile2"); + return 0; +} +//] +#include diff --git a/proj/to-do.txt b/proj/to-do.txt index dc977b4..c03de84 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -52,3 +52,9 @@ -> barrier_test fails on MacOS X on PowerPC. -> void allocator instantiations fail. + +-> Read-only managed classes. They should avoid internal locking and map memory as read-only + +-> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ + +-> add contiguous_elements option to burst allocation diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index eed8eda..e1a02a9 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -443,6 +443,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_lock_test", "file_lock ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intersegment_ptr_test", "intersegment_ptr_test.vcproj", "{5E81CD01-4FA2-2A96-84FE-DA631CA20962}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_copy_on_write", "doc_managed_copy_on_write.vcproj", "{8E0C437E-3613-FD46-F3AE-876A0731CA85}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -895,6 +903,14 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.Build.0 = Release|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.ActiveCfg = Debug|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.Build.0 = Debug|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.ActiveCfg = Release|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.Build.0 = Release|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.ActiveCfg = Debug|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.Build.0 = Debug|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.ActiveCfg = Release|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/doc_managed_copy_on_write.vcproj b/proj/vc7ide/doc_managed_copy_on_write.vcproj new file mode 100644 index 0000000..0264fbe --- /dev/null +++ b/proj/vc7ide/doc_managed_copy_on_write.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/intersegment_ptr_test.vcproj b/proj/vc7ide/intersegment_ptr_test.vcproj new file mode 100644 index 0000000..e01e3bb --- /dev/null +++ b/proj/vc7ide/intersegment_ptr_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/cached_adaptive_pool_test.cpp b/test/cached_adaptive_pool_test.cpp index 0a0574e..5d5a8c7 100644 --- a/test/cached_adaptive_pool_test.cpp +++ b/test/cached_adaptive_pool_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" diff --git a/test/cached_node_allocator_test.cpp b/test/cached_node_allocator_test.cpp index 597c90d..0900a4c 100644 --- a/test/cached_node_allocator_test.cpp +++ b/test/cached_node_allocator_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 4c4495e..0efee1c 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -122,6 +122,13 @@ int main () } } } + { + //Now test move semantics + file_mapping mapping(test::get_process_id_name(), read_only); + file_mapping move_ctor(move(mapping)); + file_mapping move_assign; + move_assign = move(move_ctor); + } } catch(std::exception &exc){ std::remove(test::get_process_id_name()); diff --git a/test/intersegment_ptr_test.cpp b/test/intersegment_ptr_test.cpp new file mode 100644 index 0000000..1f2d98a --- /dev/null +++ b/test/intersegment_ptr_test.cpp @@ -0,0 +1,404 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 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. +// +////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include //mapped_region +#include //anonymous_shared_memory +#include //managed_multi_shared_memory +#include //std::size_t + + +using namespace boost::interprocess; + +bool test_types_and_convertions() +{ + typedef intersegment_ptr pint_t; + typedef intersegment_ptr pcint_t; + typedef intersegment_ptr pvint_t; + typedef intersegment_ptr pcvint_t; + + if(!detail::is_same::value) + return false; + if(!detail::is_same::value) + return false; + if(!detail::is_same::value) + return false; + if(!detail::is_same::value) + return false; + int dummy_int = 9; + + { pint_t pint(&dummy_int); pcint_t pcint(pint); + if(pcint.get() != &dummy_int) return false; } + { pint_t pint(&dummy_int); pvint_t pvint(pint); + if(pvint.get() != &dummy_int) return false; } + { pint_t pint(&dummy_int); pcvint_t pcvint(pint); + if(pcvint.get() != &dummy_int) return false; } + { pcint_t pcint(&dummy_int); pcvint_t pcvint(pcint); + if(pcvint.get() != &dummy_int) return false; } + { pvint_t pvint(&dummy_int); pcvint_t pcvint(pvint); + if(pcvint.get() != &dummy_int) return false; } + + pint_t pint(0); + pcint_t pcint(0); + pvint_t pvint(0); + pcvint_t pcvint(0); + + pint = &dummy_int; + pcint = &dummy_int; + pvint = &dummy_int; + pcvint = &dummy_int; + + { pcint = pint; if(pcint.get() != &dummy_int) return false; } + { pvint = pint; if(pvint.get() != &dummy_int) return false; } + { pcvint = pint; if(pcvint.get() != &dummy_int) return false; } + { pcvint = pcint; if(pcvint.get() != &dummy_int) return false; } + { pcvint = pvint; if(pcvint.get() != &dummy_int) return false; } + + if(!pint) + return false; + + pint = 0; + if(pint) + return false; + + return true; +} + +bool test_arithmetic() +{ + typedef intersegment_ptr pint_t; + const int NumValues = 5; + int values[NumValues]; + + //Initialize p + pint_t p = values; + if(p.get() != values) + return false; + + //Initialize p + NumValues + pint_t pe = &values[NumValues]; + if(pe == p) + return false; + if(pe.get() != &values[NumValues]) + return false; + + //ptr - ptr + if((pe - p) != NumValues) + return false; + //ptr - integer + if((pe - NumValues) != p) + return false; + //ptr + integer + if((p + NumValues) != pe) + return false; + //integer + ptr + if((NumValues + p) != pe) + return false; + //indexing + if(pint_t(&p[NumValues]) != pe) + return false; + if(pint_t(&pe[-NumValues]) != p) + return false; + + //ptr -= integer + pint_t p0 = pe; + p0-= NumValues; + if(p != p0) + return false; + //ptr += integer + pint_t penew = p0; + penew += NumValues; + if(penew != pe) + return false; + + //++ptr + penew = p0; + for(int j = 0; j != NumValues; ++j, ++penew); + if(penew != pe) + return false; + //--ptr + p0 = pe; + for(int j = 0; j != NumValues; ++j, --p0); + if(p != p0) + return false; + //ptr++ + penew = p0; + for(int j = 0; j != NumValues; ++j){ + pint_t p = penew; + if(p != penew++) + return false; + } + //ptr-- + p0 = pe; + for(int j = 0; j != NumValues; ++j){ + pint_t p = p0; + if(p != p0--) + return false; + } + + return true; +} + +bool test_comparison() +{ + typedef intersegment_ptr pint_t; + const int NumValues = 5; + int values[NumValues]; + + //Initialize p + pint_t p = values; + if(p.get() != values) + return false; + + //Initialize p + NumValues + pint_t pe = &values[NumValues]; + if(pe == p) + return false; + if(pe.get() != &values[NumValues]) + return false; + + //operators + if(p == pe) + return false; + if(p != p) + return false; + if(!(p < pe)) + return false; + if(!(p <= pe)) + return false; + if(!(pe > p)) + return false; + if(!(pe >= p)) + return false; + + return true; +} + +struct segment_data +{ + int int0; + int int1; + intersegment_ptr ptr0; + int int2; + int int3; +}; + +bool test_basic_comparisons() +{ + //Create aligned sections + const std::size_t PageSize = mapped_region::get_page_size(); + mapped_region reg_0_0(anonymous_shared_memory(PageSize)); + mapped_region reg_0_1(anonymous_shared_memory(PageSize)); + mapped_region reg_1_0(anonymous_shared_memory(PageSize)); + mapped_region reg_1_1(anonymous_shared_memory(PageSize)); + + if(sizeof(segment_data) > mapped_region::get_page_size()) + return false; + + segment_data &seg_0_0 = *((segment_data *)reg_0_0.get_address()); + segment_data &seg_0_1 = *((segment_data *)reg_0_1.get_address()); + segment_data &seg_1_0 = *((segment_data *)reg_1_0.get_address()); + segment_data &seg_1_1 = *((segment_data *)reg_1_1.get_address()); + + //Some dummy multi_segment_services + multi_segment_services *services0 = (multi_segment_services *)0; + multi_segment_services *services1 = (multi_segment_services *)1; + + const intersegment_ptr::segment_group_id group_0_id = + intersegment_ptr::new_segment_group(services0); + const intersegment_ptr::segment_group_id group_1_id = + intersegment_ptr::new_segment_group(services1); + + { + + //Now register the segments in the segment data-base + intersegment_ptr::insert_mapping(group_0_id, &seg_0_0, PageSize); + intersegment_ptr::insert_mapping(group_0_id, &seg_0_1, PageSize); + intersegment_ptr::insert_mapping(group_1_id, &seg_1_0, PageSize); + intersegment_ptr::insert_mapping(group_1_id, &seg_1_1, PageSize); + } + + //Now do some testing... + { + //Same segment + seg_0_0.ptr0 = &seg_0_0.int0; + seg_0_1.ptr0 = &seg_0_1.int0; + + if(seg_0_0.ptr0.get() != &seg_0_0.int0) + return false; + if(seg_0_1.ptr0.get() != &seg_0_1.int0) + return false; + + //Try it again to make use of the already established relative addressing + seg_0_0.ptr0 = &seg_0_0.int1; + seg_0_1.ptr0 = &seg_0_1.int1; + + if(seg_0_0.ptr0.get() != &seg_0_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_1.int1) + return false; + + //Set to null and try again + seg_0_0.ptr0 = 0; + seg_0_1.ptr0 = 0; + + seg_0_0.ptr0 = &seg_0_0.int1; + seg_0_1.ptr0 = &seg_0_1.int1; + + if(seg_0_0.ptr0.get() != &seg_0_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_1.int1) + return false; + + //Set to null and try again + int stack_int; + seg_0_0.ptr0 = &stack_int; + seg_0_1.ptr0 = &stack_int; + + if(seg_0_0.ptr0.get() != &stack_int) + return false; + if(seg_0_1.ptr0.get() != &stack_int) + return false; + } + + { + //Now use stack variables + intersegment_ptr stack_0 = &seg_0_0.int2; + intersegment_ptr stack_1 = &seg_1_1.int2; + + if(stack_0.get() != &seg_0_0.int2) + return false; + if(stack_1.get() != &seg_1_1.int2) + return false; + + //Now reuse stack variables knowing that there are on stack + stack_0 = &seg_0_0.int3; + stack_1 = &seg_1_1.int3; + + if(stack_0.get() != &seg_0_0.int3) + return false; + if(stack_1.get() != &seg_1_1.int3) + return false; + + //Now set to null and try it again + stack_0 = 0; + stack_1 = 0; + + stack_0 = &seg_0_0.int3; + stack_1 = &seg_1_1.int3; + + if(stack_0.get() != &seg_0_0.int3) + return false; + if(stack_1.get() != &seg_1_1.int3) + return false; + } + { + //Different segments in the same group + seg_0_0.ptr0 = &seg_0_1.int0; + seg_0_1.ptr0 = &seg_0_0.int0; + + if(seg_0_0.ptr0.get() != &seg_0_1.int0) + return false; + if(seg_0_1.ptr0.get() != &seg_0_0.int0) + return false; + + //Try it again to make use of the already established segmented addressing + seg_0_0.ptr0 = &seg_0_1.int1; + seg_0_1.ptr0 = &seg_0_0.int1; + + if(seg_0_0.ptr0.get() != &seg_0_1.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_0.int1) + return false; + + //Set to null and try it again + seg_0_0.ptr0 = 0; + seg_0_1.ptr0 = 0; + + seg_0_0.ptr0 = &seg_0_1.int1; + seg_0_1.ptr0 = &seg_0_0.int1; + + if(seg_0_0.ptr0.get() != &seg_0_1.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_0_0.int1) + return false; + } + + { + //Different groups + seg_0_0.ptr0 = &seg_1_0.int0; + seg_0_1.ptr0 = &seg_1_1.int0; + + if(seg_0_0.ptr0.get() != &seg_1_0.int0) + return false; + if(seg_0_1.ptr0.get() != &seg_1_1.int0) + return false; + + //Try it again + seg_0_0.ptr0 = &seg_1_0.int1; + seg_0_1.ptr0 = &seg_1_1.int1; + + if(seg_0_0.ptr0.get() != &seg_1_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_1_1.int1) + return false; + + //Set null and try it again + seg_0_0.ptr0 = 0; + seg_0_1.ptr0 = 0; + + seg_0_0.ptr0 = &seg_1_0.int1; + seg_0_1.ptr0 = &seg_1_1.int1; + + if(seg_0_0.ptr0.get() != &seg_1_0.int1) + return false; + if(seg_0_1.ptr0.get() != &seg_1_1.int1) + return false; + } + + { + //Erase mappings + intersegment_ptr::delete_group(group_0_id); + intersegment_ptr::delete_group(group_1_id); + } + return true; +} + +bool test_multi_segment_shared_memory() +{ + { + shared_memory_object::remove("kk0"); + managed_multi_shared_memory mshm(create_only, "kk", 4096); + } + + shared_memory_object::remove("kk0"); + return true; +} + +int main() +{ + if(!test_types_and_convertions()) + return 1; + if(!test_arithmetic()) + return 1; + if(!test_comparison()) + return 1; + if(!test_basic_comparisons()) + return 1; + + if(!test_multi_segment_shared_memory()) + return 1; + return 0; +} + +#include diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index c33b97e..c4c6cbc 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -88,6 +88,35 @@ int main () return -1; } + { + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_copy_on_write, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find("MyVector").first; + if(!mfile_vect) + return -1; + + //Erase vector + mfile.destroy_ptr(mfile_vect); + + //Make sure vector is erased + mfile_vect = mfile.find("MyVector").first; + if(mfile_vect) + return -1; + } + //Now check vector is still in the file + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_copy_on_write, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find("MyVector").first; + if(!mfile_vect) + return -1; + } + } { std::size_t old_free_memory; { @@ -162,6 +191,13 @@ int main () if(next_file_size <= final_file_size) return -1; } + { + //Now test move semantics + managed_mapped_file original(open_only, FileName); + managed_mapped_file move_ctor(move(original)); + managed_mapped_file move_assign; + move_assign = move(move_ctor); + } } std::remove(FileName); diff --git a/test/managed_shared_memory_test.cpp b/test/managed_shared_memory_test.cpp index 9d7d94c..57cc678 100644 --- a/test/managed_shared_memory_test.cpp +++ b/test/managed_shared_memory_test.cpp @@ -84,7 +84,35 @@ int main () if(!shmem_vect) return -1; } + { + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_copy_on_write, ShmemName); + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + + //Erase vector + shmem.destroy_ptr(shmem_vect); + + //Make sure vector is erased + shmem_vect = shmem.find("MyVector").first; + if(shmem_vect) + return -1; + } + //Now check vector is still in the shmem + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_copy_on_write, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } + } { std::size_t old_free_memory; { @@ -159,6 +187,13 @@ int main () if(next_shmem_size <= final_shmem_size) return -1; } + { + //Now test move semantics + managed_shared_memory original(open_only, ShmemName); + managed_shared_memory move_ctor(move(original)); + managed_shared_memory move_assign; + move_assign = move(move_ctor); + } } shared_memory_object::remove(ShmemName); diff --git a/test/managed_windows_shared_memory_test.cpp b/test/managed_windows_shared_memory_test.cpp index 52b4497..61dbd35 100644 --- a/test/managed_windows_shared_memory_test.cpp +++ b/test/managed_windows_shared_memory_test.cpp @@ -72,20 +72,59 @@ int main () //Construct a vector in the shared memory w_shm_vect = w_shm.construct ("MyVector") (myallocator); - //Map preexisting segment again in memory - managed_windows_shared_memory w_shm_new(open_only, MemName); + { + //Map preexisting segment again in memory + managed_windows_shared_memory w_shm_new(open_only, MemName); - //Check vector is still there - w_shm_vect = w_shm_new.find("MyVector").first; - if(!w_shm_vect) - return -1; + //Check vector is still there + w_shm_vect = w_shm_new.find("MyVector").first; + if(!w_shm_vect) + return -1; - if(w_shm_new.get_size() != w_shm.get_size()) - return 1; - //Destroy and check it is not present - w_shm_new.destroy_ptr(w_shm_vect); - if(0 != w_shm_new.find("MyVector").first) - return 1; + if(w_shm_new.get_size() != w_shm.get_size()) + return 1; + + { + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_copy_on_write, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + + //Erase vector + shmem.destroy_ptr(shmem_vect); + + //Make sure vector is erased + shmem_vect = shmem.find("MyVector").first; + if(shmem_vect) + return -1; + } + //Now check vector is still in the s + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_copy_on_write, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } + } + + //Destroy and check it is not present + w_shm_new.destroy_ptr(w_shm_vect); + if(0 != w_shm_new.find("MyVector").first) + return 1; + + //Now test move semantics + managed_windows_shared_memory original(open_only, MemName); + managed_windows_shared_memory move_ctor(move(original)); + managed_windows_shared_memory move_assign; + move_assign = move(move_ctor); + } } return 0; diff --git a/test/mapped_file_test.cpp b/test/mapped_file_test.cpp index 233e907..99ef3fd 100644 --- a/test/mapped_file_test.cpp +++ b/test/mapped_file_test.cpp @@ -74,6 +74,11 @@ int main () //Overwrite all memory std::memset(file1.get_user_address(), 0, file1.get_user_size()); + + //Now test move semantics + mapped_file move_ctor(move(file1)); + mapped_file move_assign; + move_assign = move(move_ctor); } std::remove(FileName); return 0; diff --git a/test/node_allocator_test.cpp b/test/node_allocator_test.cpp index dbe7b5d..8c7682b 100644 --- a/test/node_allocator_test.cpp +++ b/test/node_allocator_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" diff --git a/test/node_pool_test.hpp b/test/node_pool_test.hpp index eae0038..d6b8145 100644 --- a/test/node_pool_test.hpp +++ b/test/node_pool_test.hpp @@ -25,7 +25,7 @@ template struct test_node_pool { static bool allocate_then_deallocate(NodePool &pool); - static bool deallocate_free_chunks(NodePool &pool); + static bool deallocate_free_blocks(NodePool &pool); }; template @@ -60,7 +60,7 @@ bool test_node_pool::allocate_then_deallocate(NodePool &pool) return false; } - pool.deallocate_free_chunks(); + pool.deallocate_free_blocks(); if(0 != pool.num_free_nodes()){ return false; @@ -70,11 +70,11 @@ bool test_node_pool::allocate_then_deallocate(NodePool &pool) } template -bool test_node_pool::deallocate_free_chunks(NodePool &pool) +bool test_node_pool::deallocate_free_blocks(NodePool &pool) { - const std::size_t max_chunks = 10; - const std::size_t max_nodes = max_chunks*pool.get_real_num_node(); - const std::size_t nodes_per_chunk = pool.get_real_num_node(); + const std::size_t max_blocks = 10; + const std::size_t max_nodes = max_blocks*pool.get_real_num_node(); + const std::size_t nodes_per_block = pool.get_real_num_node(); std::vector nodes; @@ -93,25 +93,25 @@ bool test_node_pool::deallocate_free_chunks(NodePool &pool) return false; } - //Now deallocate one of each chunk per iteration - for(std::size_t node_i = 0; node_i < nodes_per_chunk; ++node_i){ - //Deallocate a node per chunk - for(std::size_t i = 0; i < max_chunks; ++i){ - pool.deallocate_node(nodes[i*nodes_per_chunk + node_i]); + //Now deallocate one of each block per iteration + for(std::size_t node_i = 0; node_i < nodes_per_block; ++node_i){ + //Deallocate a node per block + for(std::size_t i = 0; i < max_blocks; ++i){ + pool.deallocate_node(nodes[i*nodes_per_block + node_i]); } //Check that the free count is correct - if(max_chunks*(node_i+1) != pool.num_free_nodes()){ + if(max_blocks*(node_i+1) != pool.num_free_nodes()){ return false; } - //Now try to deallocate free chunks - pool.deallocate_free_chunks(); + //Now try to deallocate free blocks + pool.deallocate_free_blocks(); - //Until we don't deallocate the last node of every chunk + //Until we don't deallocate the last node of every block //no node should be deallocated - if(node_i != (nodes_per_chunk - 1)){ - if(max_chunks*(node_i+1) != pool.num_free_nodes()){ + if(node_i != (nodes_per_block - 1)){ + if(max_blocks*(node_i+1) != pool.num_free_nodes()){ return false; } } @@ -149,7 +149,7 @@ bool test_all_node_pool() //Now call each test if(!test_node_pool_t::allocate_then_deallocate(*p)) return false; - if(!test_node_pool_t::deallocate_free_chunks(*p)) + if(!test_node_pool_t::deallocate_free_blocks(*p)) return false; } shared_memory_object::remove(test::get_process_id_name()); diff --git a/test/private_adaptive_pool_test.cpp b/test/private_adaptive_pool_test.cpp index a914e83..2237b80 100644 --- a/test/private_adaptive_pool_test.cpp +++ b/test/private_adaptive_pool_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" diff --git a/test/private_node_allocator_test.cpp b/test/private_node_allocator_test.cpp index 4190c6a..692fd3c 100644 --- a/test/private_node_allocator_test.cpp +++ b/test/private_node_allocator_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "print_container.hpp" #include "dummy_test_allocator.hpp" diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 036adb7..eba27c1 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -136,6 +136,13 @@ int main () } } } + { + //Now test move semantics + shared_memory_object mapping(open_only, test::get_process_id_name(), read_write); + shared_memory_object move_ctor(move(mapping)); + shared_memory_object move_assign; + move_assign = move(move_ctor); + } } catch(std::exception &exc){ shared_memory_object::remove(test::get_process_id_name()); diff --git a/test/shared_memory_test.cpp b/test/shared_memory_test.cpp index f336409..1299911 100644 --- a/test/shared_memory_test.cpp +++ b/test/shared_memory_test.cpp @@ -74,6 +74,11 @@ int main () //Overwrite all memory std::memset(shm1.get_user_address(), 0, shm1.get_user_size()); + + //Now test move semantics + shared_memory move_ctor(move(shm1)); + shared_memory move_assign; + move_assign = move(move_ctor); } } catch(std::exception &ex){ diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index 232b253..8b97058 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -62,6 +62,18 @@ int main () //Named new capable heap mem allocator wmanaged_heap_memory heap_buffer(memsize); + //Test move semantics + { + wmanaged_external_buffer user_default; + wmanaged_external_buffer temp_external(move(user_buffer)); + user_default = move(temp_external); + user_buffer = move(user_default); + wmanaged_heap_memory heap_default; + wmanaged_heap_memory temp_heap(move(heap_buffer)); + heap_default = move(temp_heap); + heap_buffer = move(heap_default); + } + //Initialize memory user_buffer.reserve_named_objects(100); heap_buffer.reserve_named_objects(100); diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 3d76790..114017a 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -15,9 +15,6 @@ #include #include -#include -#include -#include #include #include #include @@ -25,6 +22,7 @@ #include "check_equal_containers.hpp" #include "movable_int.hpp" #include +#include #include "get_process_id_name.hpp" namespace boost{ From 92a38675bacd85f2509a7784512de758e04f9845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:25:35 +0000 Subject: [PATCH 20/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45694] --- .../interprocess/detail/intersegment_ptr.hpp | 1054 +++++++++++++++++ 1 file changed, 1054 insertions(+) create mode 100644 include/boost/interprocess/detail/intersegment_ptr.hpp diff --git a/include/boost/interprocess/detail/intersegment_ptr.hpp b/include/boost/interprocess/detail/intersegment_ptr.hpp new file mode 100644 index 0000000..6b885b0 --- /dev/null +++ b/include/boost/interprocess/detail/intersegment_ptr.hpp @@ -0,0 +1,1054 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include //vector +#include //set +#include +#include +#include +#include +#include //BOOST_STATIC_ASSERT +#include //CHAR_BIT +#include +#include //assert +#include + +//!\file +//! +namespace boost { + +//Predeclarations +template +struct has_trivial_constructor; + +template +struct has_trivial_destructor; + +namespace interprocess { + +template +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::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 (void*)((((std::size_t)this) & mask) - (beg << align_bits)); + } + + void relative_set_begin_from_base(void *addr) + { + assert(addr < (void*)this); + std::size_t off = (char*)this - (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 +struct flat_map_intersegment + : public intersegment_base +{ + typedef flat_map_intersegment self_t; + + void set_from_pointer(const volatile void *ptr) + { this->set_from_pointer((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 (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 = (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 (char*)this->get_pointer() - (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 = (void*)ptr; + return; + } + if(mode == is_relative){ + char *beg_addr = (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 = (char*)ptr - (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 = (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 = (void*)ptr; + } + else if(ptr_info.id == this_info.id){ + this->set_mode(is_relative); + members.relative.off = ((char*)ptr - (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); + 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((char*)this->get_pointer()+bytes); + } + + //!Decrements internal + //!offset + void dec_offset(std::ptrdiff_t bytes) + { + this->set_from_pointer((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 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_groups_t; + + typedef boost::interprocess::flat_map + > 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 lock(s_map); + //------------------------------------------------------------------ + base = 0; + if(s_map.m_ptr_to_segment_info.empty()){ + segment = segment_info_t(); + offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + 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 = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + } + //Go to the previous one + --it; + char * segment_base = detail::char_ptr_cast(it->first); + std::size_t segment_size = it->second.size; + + if(segment_base <= detail::char_ptr_cast(ptr) && + (segment_base + segment_size) >= detail::char_ptr_cast(ptr)){ + segment = it->second; + offset = detail::char_ptr_cast(ptr) - segment_base; + base = segment_base; + } + else{ + segment = segment_info_t(); + offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + } + } + + //!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 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 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 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 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); + assert(erased); + return true; + } + } + + static segment_group_id new_segment_group(multi_segment_services *services) + { + { //------------------------------------------------------------------ + boost::interprocess::scoped_lock lock(s_map); + //------------------------------------------------------------------ + typedef typename segment_groups_t::iterator iterator; + std::pair 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 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 +typename flat_map_intersegment::mappings_t + flat_map_intersegment::s_map; + +//!Static segment group container associated with +//!flat_map_intersegment<> +template +typename flat_map_intersegment::segment_groups_t + flat_map_intersegment::s_groups; + +//!A smart pointer that can point to a pointee that resides in another memory +//!memory mapped or shared memory segment. +template +class intersegment_ptr : public flat_map_intersegment +{ + typedef flat_map_intersegment PT; + typedef intersegment_ptr 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::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 + 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 + intersegment_ptr(const intersegment_ptr &ptr) + { pointer p(ptr.get()); (void)p; base_t::set_from_other(ptr); } + + //!Emulates static_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::static_cast_tag) + { base_t::set_from_pointer(static_cast(r.get())); } +/* + { + if(r.is_null()){ + base_t::set_from_pointer(0); + } + else{ + //Some dirty tricks to safe segment operations. + //Calculate pointer adjustment and adjust offset. + pointer ptr = reinterpret_cast(this); + std::ptrdiff_t difference = detail::char_ptr_cast(static_cast(ptr)) - + detail::char_ptr_cast(ptr); + base_t::set_from_other(r); + base_t::inc_offset(difference*sizeof(T)); + } + }*/ + + //!Emulates const_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::const_cast_tag) + { base_t::set_from_pointer(const_cast(r.get())); } + + //!Emulates dynamic_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::dynamic_cast_tag) + { base_t::set_from_pointer(dynamic_cast(r.get())); } + + //!Emulates reinterpret_cast operator. + //!Never throws. + template + intersegment_ptr(const intersegment_ptr &r, detail::reinterpret_cast_tag) + { base_t::set_from_pointer(reinterpret_cast(r.get())); } + + //!Obtains raw pointer from offset. + //!Never throws. + pointer get()const + { return (pointer)base_t::get_pointer(); } + + //!Pointer-like -> operator. It can return 0 pointer. + //!Never throws. + pointer operator->() const + { return self_t::get(); } + + //!Dereferencing operator, if it is a null intersegment_ptr behavior + //!is undefined. Never throws. + reference operator* () const + { return *(self_t::get()); } + + //!Indexing operator. + //!Never throws. + reference operator[](std::ptrdiff_t idx) const + { return self_t::get()[idx]; } + + //!Assignment from pointer (saves extra conversion). + //!Never throws. + intersegment_ptr& operator= (pointer from) + { base_t::set_from_pointer(from); return *this; } + + //!Assignment from other intersegment_ptr. + //!Never throws. + intersegment_ptr& operator= (const intersegment_ptr &ptr) + { base_t::set_from_other(ptr); return *this; } + + //!Assignment from related intersegment_ptr. If pointers of pointee types + //!are assignable, intersegment_ptrs will be assignable. Never throws. + template + intersegment_ptr& operator= (const intersegment_ptr & ptr) + { + pointer p(ptr.get()); (void)p; + base_t::set_from_other(ptr); return *this; + } + + //!intersegment_ptr + std::ptrdiff_t. + //!Never throws. + intersegment_ptr operator+ (std::ptrdiff_t idx) const + { + intersegment_ptr result (*this); + result.inc_offset(idx*sizeof(T)); + return result; + } + + //!intersegment_ptr - std::ptrdiff_t. + //!Never throws. + intersegment_ptr operator- (std::ptrdiff_t idx) const + { + intersegment_ptr result (*this); + result.dec_offset(idx*sizeof(T)); + return result; + } + + //!intersegment_ptr += std::ptrdiff_t. + //!Never throws. + intersegment_ptr &operator+= (std::ptrdiff_t offset) + { base_t::inc_offset(offset*sizeof(T)); return *this; } + + //!intersegment_ptr -= std::ptrdiff_t. + //!Never throws. + intersegment_ptr &operator-= (std::ptrdiff_t offset) + { base_t::dec_offset(offset*sizeof(T)); return *this; } + + //!++intersegment_ptr. + //!Never throws. + intersegment_ptr& operator++ (void) + { base_t::inc_offset(sizeof(T)); return *this; } + + //!intersegment_ptr++. + //!Never throws. + intersegment_ptr operator++ (int) + { intersegment_ptr temp(*this); ++*this; return temp; } + + //!--intersegment_ptr. + //!Never throws. + intersegment_ptr& operator-- (void) + { base_t::dec_offset(sizeof(T)); return *this; } + + //!intersegment_ptr--. + //!Never throws. + intersegment_ptr operator-- (int) + { intersegment_ptr temp(*this); --*this; return temp; } + + //!Safe bool conversion operator. + //!Never throws. + operator unspecified_bool_type() const + { return base_t::is_null()? 0 : &self_t::unspecified_bool_type_func; } + + //!Not operator. Not needed in theory, but improves portability. + //!Never throws. + bool operator! () const + { return base_t::is_null(); } + + //!Swaps two intersegment_ptr-s. More efficient than std::swap. + //!Never throws. + void swap(intersegment_ptr &other) + { base_t::swap(other); } + + //!Calculates the distance between two intersegment_ptr-s. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment. Otherwise undefined + template + ptrdiff_t _diff(const intersegment_ptr &other) const + { return base_t::diff(other); } + + //!Returns true if both point to the + //!same object + template + bool _equal(const intersegment_ptr&other) const + { return base_t::equal(other); } + + //!Returns true if *this is less than other. + //!This only works with two basic_intersegment_ptr pointing + //!to the same segment group. Otherwise undefined. Never throws + template + bool _less(const intersegment_ptr &other) const + { return base_t::less(other); } +}; + +//!Compares the equality of two intersegment_ptr-s. +//!Never throws. +template inline +bool operator ==(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) == + typename intersegment_ptr::pointer(0); + (void)e; + return left._equal(right); +} + +//!Returns true if *this is less than other. +//!This only works with two basic_intersegment_ptr pointing +//!to the same segment group. Otherwise undefined. Never throws +template inline +bool operator <(const intersegment_ptr &left, + const intersegment_ptr &right) +{ + //Make sure both pointers can be compared + bool e = typename intersegment_ptr::pointer(0) < + typename intersegment_ptr::pointer(0); + (void)e; + return left._less(right); +} + +template inline +bool operator!= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 ==pt2); } + +//!intersegment_ptr <= intersegment_ptr. +//!Never throws. +template inline +bool operator<= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 > pt2); } + +//!intersegment_ptr > intersegment_ptr. +//!Never throws. +template inline +bool operator> (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return (pt2 < pt1); } + +//!intersegment_ptr >= intersegment_ptr. +//!Never throws. +template inline +bool operator>= (const intersegment_ptr &pt1, + const intersegment_ptr &pt2) +{ return !(pt1 < pt2); } + +//!operator<< +template inline +std::basic_ostream & operator<< + (std::basic_ostream & os, const intersegment_ptr & p) +{ return os << p.get(); } + +//!operator>> +template inline +std::basic_istream & operator>> + (std::basic_istream & os, intersegment_ptr & p) +{ U * tmp; return os >> tmp; p = tmp; } + +//!std::ptrdiff_t + intersegment_ptr. +//!The result is another pointer of the same segment +template inline +intersegment_ptr operator+ + (std::ptrdiff_t diff, const intersegment_ptr& right) +{ return right + diff; } + +//!intersegment_ptr - intersegment_ptr. +//!This only works with two intersegment_ptr-s that point to the +//!same segment +template inline +std::ptrdiff_t operator- (const intersegment_ptr &pt, + const intersegment_ptr &pt2) +{ return pt._diff(pt2)/sizeof(T); } + +//! swap specialization +template inline +void swap (boost::interprocess::intersegment_ptr &pt, + boost::interprocess::intersegment_ptr &pt2) +{ pt.swap(pt2); } + +//!get_pointer() enables boost::mem_fn to recognize intersegment_ptr. +//!Never throws. +template inline +T * get_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } + +//!Simulation of static_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr static_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::static_cast_tag()); } + +//!Simulation of const_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr const_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::const_cast_tag()); } + +//!Simulation of dynamic_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr dynamic_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::dynamic_cast_tag()); } + +//!Simulation of reinterpret_cast between pointers. +//!Never throws. +template inline +boost::interprocess::intersegment_ptr reinterpret_pointer_cast(const boost::interprocess::intersegment_ptr &r) +{ return boost::interprocess::intersegment_ptr(r, boost::interprocess::detail::reinterpret_cast_tag()); } + +//!Trait class to detect if an smart pointer has +//!multi-segment addressing capabilities. +template +struct is_multisegment_ptr + > +{ + 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 inline +T * get_pointer(boost::interprocess::intersegment_ptr const & p) +{ return p.get(); } +#endif + +//!has_trivial_constructor<> == true_type specialization +//!for optimizations +template +struct has_trivial_constructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +//!has_trivial_destructor<> == true_type specialization +//!for optimizations +template +struct has_trivial_destructor + < boost::interprocess::intersegment_ptr > + : public true_type{}; + +} //namespace boost { + +#include + +#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 ((char*)this) + this->relative_pointee_offset(); + } + else{ + group_manager *m = get_segment_group_manager(addr); + char *base = (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((char*)ptr - (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 + From da38f57a8ef0ce66cd6a4d44787768b3af542df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:29:32 +0000 Subject: [PATCH 21/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45695] --- .../boost/interprocess/windows_shared_memory.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index 912411a..9317509 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -83,7 +83,7 @@ class windows_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE windows_shared_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else windows_shared_memory(windows_shared_memory &&moved) @@ -95,7 +95,7 @@ class windows_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE windows_shared_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { windows_shared_memory tmp(moved); this->swap(tmp); @@ -235,6 +235,18 @@ inline void windows_shared_memory::priv_close() } } +///@cond + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { From efbc77925997f180472f5bca1c7f0d80047057d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:34:14 +0000 Subject: [PATCH 22/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45697] --- .../interprocess/managed_external_buffer.hpp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index be18e4d..8faea6d 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -46,6 +46,12 @@ class basic_managed_external_buffer /// @endcond public: + + //!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) @@ -71,7 +77,7 @@ class basic_managed_external_buffer //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_external_buffer - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_external_buffer @@ -82,7 +88,7 @@ class basic_managed_external_buffer //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_external_buffer &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_external_buffer &operator= @@ -100,6 +106,26 @@ class basic_managed_external_buffer }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + + } //namespace interprocess { } //namespace boost { From 3a7c09de5cedfc3ab422342a0550d5936dfc55cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:34:43 +0000 Subject: [PATCH 23/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45698] --- include/boost/interprocess/creation_tags.hpp | 22 ++++++-- include/boost/interprocess/errors.hpp | 4 +- include/boost/interprocess/file_mapping.hpp | 19 ++++++- .../boost/interprocess/interprocess_fwd.hpp | 12 ++--- .../interprocess/managed_heap_memory.hpp | 26 +++++++-- .../interprocess/managed_mapped_file.hpp | 53 +++++++++++++++---- .../interprocess/managed_shared_memory.hpp | 50 +++++++++++++---- .../managed_windows_shared_memory.hpp | 46 +++++++++++++--- include/boost/interprocess/mapped_region.hpp | 10 +++- .../boost/interprocess/segment_manager.hpp | 12 ++--- .../interprocess/shared_memory_object.hpp | 18 ++++++- 11 files changed, 219 insertions(+), 53 deletions(-) diff --git a/include/boost/interprocess/creation_tags.hpp b/include/boost/interprocess/creation_tags.hpp index 190c6bd..61d537a 100644 --- a/include/boost/interprocess/creation_tags.hpp +++ b/include/boost/interprocess/creation_tags.hpp @@ -25,21 +25,37 @@ struct create_only_t {}; //!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(); +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(); +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(); +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 { diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index 4f157a7..ecf3698 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -10,8 +10,8 @@ // ////////////////////////////////////////////////////////////////////////////// // -// Copyright (c) 2002 Beman Dawes -// Copyright (c) 2001 Dietmar Kuehl +// 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) diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index a55ff03..8ddebef 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include //std::string #include //std::remove #include @@ -55,10 +56,12 @@ class file_mapping //!After the call, "moved" does not represent any shared memory object. //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_mapping(detail::moved_object &moved) + file_mapping(detail::moved_object moved) + : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved.get()); } #else file_mapping(file_mapping &&moved) + : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved); } #endif @@ -67,7 +70,7 @@ class file_mapping //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE file_mapping &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { file_mapping tmp(moved); this->swap(tmp); @@ -165,6 +168,18 @@ inline void file_mapping::priv_close() } } +///@cond + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index acb1b3e..0681782 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -120,26 +120,26 @@ class sharable_lock; template class allocator; -template +template class node_allocator; -template +template class private_node_allocator; -template +template class cached_node_allocator; -template class adaptive_pool; -template class private_adaptive_pool; -template class cached_adaptive_pool; diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp index 36e97bd..4ed9869 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -50,7 +50,8 @@ class basic_managed_heap_memory public: //functions - //!Constructor. Never throws. + //!Default constructor. Does nothing. + //!Useful in combination with move semantics basic_managed_heap_memory(){} //!Destructor. Liberates the heap memory holding the managed data. @@ -72,7 +73,7 @@ class basic_managed_heap_memory //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_heap_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_heap_memory(basic_managed_heap_memory &&moved) @@ -82,7 +83,7 @@ class basic_managed_heap_memory //!Moves the ownership of "moved"'s managed memory to *this. Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_heap_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_heap_memory &operator= @@ -139,6 +140,25 @@ class basic_managed_heap_memory /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index cdd6267..eda6b90 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -23,14 +23,11 @@ #include #include -//!\file -//!Describes a named shared memory object allocation user class. - namespace boost { namespace interprocess { -//!A basic shared memory named object creation class. Initializes the -//!shared memory segment. Inherits all basic functionality from +//!A basic mapped file named object creation class. Initializes the +//!mapped file. Inherits all basic functionality from //!basic_managed_memory_impl template < @@ -61,7 +58,12 @@ class basic_managed_mapped_file public: //functions - //!Creates shared memory and creates and places the segment manager. + //!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) @@ -69,7 +71,7 @@ class basic_managed_mapped_file create_open_func_t(get_this_pointer(), detail::DoCreate)) {} - //!Creates shared memory and creates and places the segment manager if + //!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. @@ -81,8 +83,8 @@ class basic_managed_mapped_file detail::DoOpenOrCreate)) {} - //!Connects to a created shared memory and it's the segment manager. - //!Never throws. + //!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, @@ -90,11 +92,21 @@ class basic_managed_mapped_file 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)) + {} + //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_mapped_file - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_mapped_file(basic_managed_mapped_file &&moved) @@ -105,7 +117,7 @@ class basic_managed_mapped_file //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_mapped_file &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved) @@ -161,6 +173,25 @@ class basic_managed_mapped_file /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index 551a7d3..d66b2be 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -23,9 +23,6 @@ #include #include -//!\file -//!Describes a named shared memory object allocation user class. - namespace boost { namespace interprocess { @@ -58,8 +55,6 @@ class basic_managed_shared_memory typedef detail::create_open_func create_open_func_t; - basic_managed_shared_memory(); - basic_managed_shared_memory *get_this_pointer() { return this; } /// @endcond @@ -75,6 +70,11 @@ class basic_managed_shared_memory ~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, @@ -97,10 +97,21 @@ class basic_managed_shared_memory detail::DoOpenOrCreate)) {} - //!Connects to a created shared memory and it's the segment manager. - //!Never throws. + //!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. + //!This can throw. basic_managed_shared_memory (open_only_t open_only, const char* name, - const void *addr = 0) + const void *addr = 0) : base_t() , base2_t(open_only, name, read_write, addr, create_open_func_t(get_this_pointer(), @@ -111,7 +122,7 @@ class basic_managed_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_shared_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_shared_memory(basic_managed_shared_memory &&moved) @@ -122,7 +133,7 @@ class basic_managed_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_shared_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved) @@ -159,6 +170,25 @@ class basic_managed_shared_memory } }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index b4acdf0..1623225 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -23,9 +23,6 @@ #include #include -//!\file -//!Describes a named shared memory object allocation user class. - namespace boost { namespace interprocess { @@ -63,6 +60,12 @@ class basic_managed_windows_shared_memory /// @endcond public: //functions + + //!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 @@ -85,8 +88,8 @@ class basic_managed_windows_shared_memory detail::DoOpenOrCreate)) {} - //!Connects to a created shared memory and it's the segment manager. - //!Never throws. + //!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, @@ -94,11 +97,21 @@ class basic_managed_windows_shared_memory 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)) + {} + //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_windows_shared_memory - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else basic_managed_windows_shared_memory(basic_managed_windows_shared_memory &&moved) @@ -109,7 +122,7 @@ class basic_managed_windows_shared_memory //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_managed_windows_shared_memory &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); return *this; } #else basic_managed_windows_shared_memory &operator= @@ -138,6 +151,25 @@ class basic_managed_windows_shared_memory /// @endcond }; +///@cond + +//!Trait class to detect if a type is +//!movable +template + < + class CharType, + class AllocationAlgorithm, + template class IndexType + > +struct is_movable +> +{ + static const bool value = true; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 0e45ab4..d7527cd 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -444,7 +444,7 @@ inline mapped_region::mapped_region break; case copy_on_write: - prot |= PROT_READ; + prot |= (PROT_WRITE | PROT_READ); flags |= MAP_PRIVATE; break; @@ -553,6 +553,14 @@ struct null_mapped_region_function bool operator()(void *, std::size_t , bool) const { return true; } }; + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; /// @endcond } //namespace interprocess { diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index c8ee79e..51a0e0e 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -1118,7 +1118,7 @@ class segment_manager //Initialize the node value_eraser to erase inserted node //if something goes wrong - detail::value_eraser value_eraser(index, it); + value_eraser v_eraser(index, it); //Avoid constructions if constructor is trivial //Build scoped ptr to avoid leaks with constructor exception @@ -1130,8 +1130,8 @@ class segment_manager //All constructors successful, we don't want to release memory mem.release(); - //Release node value_eraser since construction was successful - value_eraser.release(); + //Release node v_eraser since construction was successful + v_eraser.release(); return ptr; } @@ -1204,7 +1204,7 @@ class segment_manager } //Initialize the node value_eraser to erase inserted node //if something goes wrong - detail::value_eraser value_eraser(index, it); + value_eraser v_eraser(index, it); //Allocates buffer for name + data, this can throw (it hurts) void *buffer_ptr; @@ -1260,8 +1260,8 @@ class segment_manager //All constructors successful, we don't want to release memory mem.release(); - //Release node value_eraser since construction was successful - value_eraser.release(); + //Release node v_eraser since construction was successful + v_eraser.release(); return ptr; } diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index 9d2eda3..ffae736 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -76,10 +76,12 @@ class shared_memory_object //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE shared_memory_object - (detail::moved_object &moved) + (const detail::moved_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 @@ -88,7 +90,7 @@ class shared_memory_object //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE shared_memory_object &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { shared_memory_object tmp(moved); this->swap(tmp); @@ -341,6 +343,18 @@ inline void shared_memory_object::priv_close() #endif +///@cond + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { From 3368fce1d9fcc079f3726af949df0d679a08dd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:35:01 +0000 Subject: [PATCH 24/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45699] --- include/boost/interprocess/smart_ptr/unique_ptr.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index f988028..70fc9e2 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -181,7 +181,7 @@ class unique_ptr //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - unique_ptr(const detail::moved_object >& u, + unique_ptr(detail::moved_object > u, typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && @@ -231,7 +231,7 @@ class unique_ptr //! //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - unique_ptr& operator=(const detail::moved_object& u) + unique_ptr& operator=(detail::moved_object u) { reset(u.get().release()); ptr_.second() = move(u.get().get_deleter()); @@ -262,7 +262,7 @@ class unique_ptr //!Throws: nothing. template #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - unique_ptr& operator=(const detail::moved_object >& mu) + unique_ptr& operator=(detail::moved_object > mu) { reset(mu.get().release()); ptr_.second() = move(mu.get().get_deleter()); @@ -356,8 +356,8 @@ class unique_ptr //!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 swap'd (unqualified). - //! + //!Effects: The stored pointers of this and u are exchanged. + //! The stored deleters are swapped (unqualified). //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void swap(unique_ptr& u) From 2624000860927864dcf28f2343f1bf37f95a3cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:36:29 +0000 Subject: [PATCH 25/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45700] --- include/boost/interprocess/indexes/map_index.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/indexes/map_index.hpp b/include/boost/interprocess/indexes/map_index.hpp index 024c647..78974af 100644 --- a/include/boost/interprocess/indexes/map_index.hpp +++ b/include/boost/interprocess/indexes/map_index.hpp @@ -77,7 +77,7 @@ class map_index //!This tries to free previously allocate //!unused memory. void shrink_to_fit() - { base_type::get_stored_allocator().deallocate_free_chunks(); } + { base_type::get_stored_allocator().deallocate_free_blocks(); } }; /// @cond From 26139ae6a3d2a27614de50112b088699fec4c1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:37:10 +0000 Subject: [PATCH 26/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45701] --- .../interprocess/allocators/adaptive_pool.hpp | 200 ++++-------------- .../interprocess/allocators/allocator.hpp | 10 +- .../allocators/cached_adaptive_pool.hpp | 68 +++--- .../allocators/cached_node_allocator.hpp | 36 ++-- .../allocators/node_allocator.hpp | 52 ++--- .../allocators/private_adaptive_pool.hpp | 100 ++++----- .../allocators/private_node_allocator.hpp | 76 +++---- 7 files changed, 206 insertions(+), 336 deletions(-) diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index 01b2b06..7b2ab87 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -40,18 +40,18 @@ namespace interprocess { /// @cond namespace detail{ -/* + template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , 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, NodesPerChunk, MaxFreeChunks, OverheadPercent> + < Version, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> , Version , T , SegmentManager @@ -61,127 +61,7 @@ class adaptive_pool_base typedef typename SegmentManager::void_pointer void_pointer; typedef SegmentManager segment_manager; typedef adaptive_pool_base - self_t; - static const std::size_t SizeOfT = sizeof(detail::if_c::value, int, T>::type); - typedef detail::shared_adaptive_node_pool - < SegmentManager, SizeOfT, NodesPerChunk, MaxFreeChunks, OverheadPercent> node_pool_t; - typedef typename detail:: - pointer_to_other::type node_pool_ptr; - - BOOST_STATIC_ASSERT((Version <=2)); - - public: - //------- - typedef typename detail:: - pointer_to_other::type pointer; - typedef typename detail:: - pointer_to_other::type const_pointer; - typedef T value_type; - typedef typename detail::add_reference - ::type reference; - typedef typename detail::add_reference - ::type const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; - - //!Obtains adaptive_pool_base from - //!adaptive_pool_base - template - struct rebind - { - typedef adaptive_pool_base other; - }; - - /// @cond - private: - //!Not assignable from related adaptive_pool_base - template - adaptive_pool_base& operator= - (const adaptive_pool_base&); - - //!Not assignable from other adaptive_pool_base - adaptive_pool_base& operator=(const adaptive_pool_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 - adaptive_pool_base(segment_manager *segment_mngr) - : mp_node_pool(detail::get_or_create_node_pool(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()) - { - mp_node_pool->inc_ref_count(); - } - - //!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 - adaptive_pool_base - (const adaptive_pool_base &other) - : mp_node_pool(detail::get_or_create_node_pool(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(detail::get_pointer(mp_node_pool)); } - - //!Returns a pointer to the node pool. - //!Never throws - node_pool_t* get_node_pool() const - { return detail::get_pointer(mp_node_pool); } - - //!Returns the segment manager. - //!Never throws - segment_manager* get_segment_manager()const - { return 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: - node_pool_ptr mp_node_pool; - /// @endcond -}; -*/ - -template < unsigned int Version - , class T - , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks - , unsigned char OverheadPercent - > -class adaptive_pool_base - : public node_pool_allocation_impl - < adaptive_pool_base - < Version, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> - , Version - , T - , SegmentManager - > -{ - public: - typedef typename SegmentManager::void_pointer void_pointer; - typedef SegmentManager segment_manager; - typedef adaptive_pool_base - self_t; + self_t; /// @cond @@ -189,7 +69,7 @@ class adaptive_pool_base struct node_pool { typedef detail::shared_adaptive_node_pool - < SegmentManager, sizeof(T), NodesPerChunk, MaxFreeChunks, OverheadPercent> type; + < SegmentManager, sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> type; static type *get(void *p) { return static_cast(p); } @@ -225,7 +105,7 @@ class adaptive_pool_base template struct rebind { - typedef adaptive_pool_base other; + typedef adaptive_pool_base other; }; /// @cond @@ -265,7 +145,7 @@ class adaptive_pool_base //!Can throw boost::interprocess::bad_alloc template adaptive_pool_base - (const adaptive_pool_base &other) + (const adaptive_pool_base &other) : mp_node_pool(detail::get_or_create_node_pool::type>(other.get_segment_manager())) { } //!Destructor, removes node_pool_t from memory @@ -310,8 +190,8 @@ bool operator!=(const adaptive_pool_base &alloc1, template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 - , std::size_t MaxFreeChunks = 2 + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 , unsigned char OverheadPercent = 5 > class adaptive_pool_v1 @@ -319,19 +199,19 @@ class adaptive_pool_v1 < 1 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > { public: typedef detail::adaptive_pool_base - < 1, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; template struct rebind { - typedef adaptive_pool_v1 other; + typedef adaptive_pool_v1 other; }; adaptive_pool_v1(SegmentManager *segment_mngr) @@ -340,7 +220,7 @@ class adaptive_pool_v1 template adaptive_pool_v1 - (const adaptive_pool_v1 &other) + (const adaptive_pool_v1 &other) : base_t(other) {} }; @@ -356,17 +236,17 @@ class adaptive_pool_v1 //! //!This node allocator shares a segregated storage between all instances //!of adaptive_pool with equal sizeof(T) placed in the same segment -//!group. NodesPerChunk is the number of nodes allocated at once when the allocator -//!needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks -//!that the adaptive node pool will hold. The rest of the totally free chunks will be +//!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 NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class adaptive_pool @@ -375,8 +255,8 @@ class adaptive_pool < 2 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > /// @endcond @@ -384,14 +264,14 @@ class adaptive_pool #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::adaptive_pool_base - < 2, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: typedef detail::version_type version; template struct rebind { - typedef adaptive_pool other; + typedef adaptive_pool other; }; adaptive_pool(SegmentManager *segment_mngr) @@ -400,7 +280,7 @@ class adaptive_pool template adaptive_pool - (const adaptive_pool &other) + (const adaptive_pool &other) : base_t(other) {} @@ -423,7 +303,7 @@ class adaptive_pool template struct rebind { - typedef adaptive_pool other; + typedef adaptive_pool other; }; private: @@ -452,7 +332,7 @@ class adaptive_pool //!Can throw boost::interprocess::bad_alloc template adaptive_pool - (const adaptive_pool &other); + (const adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -478,9 +358,9 @@ class adaptive_pool //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -513,7 +393,7 @@ class adaptive_pool size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -522,11 +402,11 @@ class adaptive_pool multiallocation_iterator 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 chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -539,7 +419,7 @@ class adaptive_pool //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -552,7 +432,7 @@ class adaptive_pool //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -566,15 +446,15 @@ class adaptive_pool //!Equality test for same type //!of adaptive_pool -template inline -bool operator==(const adaptive_pool &alloc1, - const adaptive_pool &alloc2); +template inline +bool operator==(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); //!Inequality test for same type //!of adaptive_pool -template inline -bool operator!=(const adaptive_pool &alloc1, - const adaptive_pool &alloc2); +template inline +bool operator!=(const adaptive_pool &alloc1, + const adaptive_pool &alloc2); #endif diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index cfb4730..a6f1eee 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -183,7 +183,7 @@ class allocator (command, limit_size, preferred_size, received_size, detail::get_pointer(reuse)); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -196,7 +196,7 @@ class allocator } //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) { @@ -204,7 +204,7 @@ class allocator (mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -219,7 +219,7 @@ class allocator pointer allocate_one() { return this->allocate(1); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -234,7 +234,7 @@ class allocator void deallocate_one(const pointer &p) { return this->deallocate(p, 1); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index 0b31f0a..4247ef6 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -38,8 +38,8 @@ namespace detail { template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 - , std::size_t MaxFreeChunks = 2 + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 , unsigned char OverheadPercent = 5 > class cached_adaptive_pool_v1 @@ -48,8 +48,8 @@ class cached_adaptive_pool_v1 , detail::shared_adaptive_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 1> @@ -60,8 +60,8 @@ class cached_adaptive_pool_v1 , detail::shared_adaptive_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 1> base_t; @@ -70,7 +70,7 @@ class cached_adaptive_pool_v1 struct rebind { typedef cached_adaptive_pool_v1 - other; + other; }; cached_adaptive_pool_v1(SegmentManager *segment_mngr, @@ -81,7 +81,7 @@ class cached_adaptive_pool_v1 template cached_adaptive_pool_v1 (const cached_adaptive_pool_v1 - &other) + &other) : base_t(other) {} }; @@ -100,17 +100,17 @@ class cached_adaptive_pool_v1 //!memory segment. But also caches some nodes privately to //!avoid some synchronization overhead. //! -//!NodesPerChunk is the minimum number of nodes of nodes allocated at once when -//!the allocator needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks -//!that the adaptive node pool will hold. The rest of the totally free chunks will be +//!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 NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class cached_adaptive_pool @@ -120,8 +120,8 @@ class cached_adaptive_pool , detail::shared_adaptive_node_pool < SegmentManager , sizeof(typename detail::if_c::value, int, T>::type) - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 2> @@ -135,8 +135,8 @@ class cached_adaptive_pool , detail::shared_adaptive_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > , 2> base_t; @@ -148,7 +148,7 @@ class cached_adaptive_pool struct rebind { typedef cached_adaptive_pool - other; + other; }; cached_adaptive_pool(SegmentManager *segment_mngr, @@ -158,7 +158,7 @@ class cached_adaptive_pool template cached_adaptive_pool - (const cached_adaptive_pool &other) + (const cached_adaptive_pool &other) : base_t(other) {} @@ -181,7 +181,7 @@ class cached_adaptive_pool template struct rebind { - typedef cached_adaptive_pool other; + typedef cached_adaptive_pool other; }; private: @@ -210,7 +210,7 @@ class cached_adaptive_pool //!Can throw boost::interprocess::bad_alloc template cached_adaptive_pool - (const cached_adaptive_pool &other); + (const cached_adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -236,9 +236,9 @@ class cached_adaptive_pool //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -271,7 +271,7 @@ class cached_adaptive_pool size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -280,11 +280,11 @@ class cached_adaptive_pool multiallocation_iterator 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 chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -297,7 +297,7 @@ class cached_adaptive_pool //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -310,7 +310,7 @@ class cached_adaptive_pool //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -331,15 +331,15 @@ class cached_adaptive_pool //!Equality test for same type //!of cached_adaptive_pool -template inline -bool operator==(const cached_adaptive_pool &alloc1, - const cached_adaptive_pool &alloc2); +template inline +bool operator==(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); //!Inequality test for same type //!of cached_adaptive_pool -template inline -bool operator!=(const cached_adaptive_pool &alloc1, - const cached_adaptive_pool &alloc2); +template inline +bool operator!=(const cached_adaptive_pool &alloc1, + const cached_adaptive_pool &alloc2); #endif diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 6d470de..b220aab 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -39,7 +39,7 @@ namespace detail { template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 + , std::size_t NodesPerBlock = 64 > class cached_node_allocator_v1 : public detail::cached_allocator_impl @@ -47,7 +47,7 @@ class cached_node_allocator_v1 , detail::shared_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk + , NodesPerBlock > , 1> { @@ -57,7 +57,7 @@ class cached_node_allocator_v1 , detail::shared_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk + , NodesPerBlock > , 1> base_t; @@ -65,7 +65,7 @@ class cached_node_allocator_v1 struct rebind { typedef cached_node_allocator_v1 - other; + other; }; cached_node_allocator_v1(SegmentManager *segment_mngr, @@ -76,7 +76,7 @@ class cached_node_allocator_v1 template cached_node_allocator_v1 (const cached_node_allocator_v1 - &other) + &other) : base_t(other) {} }; @@ -87,7 +87,7 @@ class cached_node_allocator_v1 template < class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class cached_node_allocator /// @cond @@ -96,7 +96,7 @@ class cached_node_allocator , detail::shared_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk + , NodesPerBlock > , 2> /// @endcond @@ -109,7 +109,7 @@ class cached_node_allocator , detail::shared_node_pool < SegmentManager , sizeof(T) - , NodesPerChunk + , NodesPerBlock > , 2> base_t; @@ -119,7 +119,7 @@ class cached_node_allocator template struct rebind { - typedef cached_node_allocator other; + typedef cached_node_allocator other; }; cached_node_allocator(SegmentManager *segment_mngr, @@ -129,7 +129,7 @@ class cached_node_allocator template cached_node_allocator - (const cached_node_allocator &other) + (const cached_node_allocator &other) : base_t(other) {} @@ -181,7 +181,7 @@ class cached_node_allocator //!Can throw boost::interprocess::bad_alloc template cached_node_allocator - (const cached_node_allocator &other); + (const cached_node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -207,9 +207,9 @@ class cached_node_allocator //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -242,7 +242,7 @@ class cached_node_allocator size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -251,11 +251,11 @@ class cached_node_allocator multiallocation_iterator 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 chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -268,7 +268,7 @@ class cached_node_allocator //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -281,7 +281,7 @@ class cached_node_allocator //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index fabc3af..9a6c8b5 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -43,12 +43,12 @@ namespace detail{ template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class node_allocator_base : public node_pool_allocation_impl < node_allocator_base - < Version, T, SegmentManager, NodesPerChunk> + < Version, T, SegmentManager, NodesPerBlock> , Version , T , SegmentManager @@ -58,7 +58,7 @@ class node_allocator_base typedef typename SegmentManager::void_pointer void_pointer; typedef SegmentManager segment_manager; typedef node_allocator_base - self_t; + self_t; /// @cond @@ -66,7 +66,7 @@ class node_allocator_base struct node_pool { typedef detail::shared_node_pool - < SegmentManager, sizeof(T), NodesPerChunk> type; + < SegmentManager, sizeof(T), NodesPerBlock> type; static type *get(void *p) { return static_cast(p); } @@ -102,7 +102,7 @@ class node_allocator_base template struct rebind { - typedef node_allocator_base other; + typedef node_allocator_base other; }; /// @cond @@ -136,7 +136,7 @@ class node_allocator_base //!Can throw boost::interprocess::bad_alloc template node_allocator_base - (const node_allocator_base &other) + (const node_allocator_base &other) : mp_node_pool(detail::get_or_create_node_pool::type>(other.get_segment_manager())) { } //!Assignment from other node_allocator_base @@ -189,24 +189,24 @@ bool operator!=(const node_allocator_base &alloc1, template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 + , std::size_t NodesPerBlock = 64 > class node_allocator_v1 : public node_allocator_base < 1 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > { public: typedef detail::node_allocator_base - < 1, T, SegmentManager, NodesPerChunk> base_t; + < 1, T, SegmentManager, NodesPerBlock> base_t; template struct rebind { - typedef node_allocator_v1 other; + typedef node_allocator_v1 other; }; node_allocator_v1(SegmentManager *segment_mngr) @@ -215,7 +215,7 @@ class node_allocator_v1 template node_allocator_v1 - (const node_allocator_v1 &other) + (const node_allocator_v1 &other) : base_t(other) {} }; @@ -230,11 +230,11 @@ class node_allocator_v1 //!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. NodesPerChunk is the number of nodes allocated at once when the allocator +//!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 NodesPerChunk + , std::size_t NodesPerBlock > class node_allocator /// @cond @@ -242,21 +242,21 @@ class node_allocator < 2 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > /// @endcond { #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::node_allocator_base - < 2, T, SegmentManager, NodesPerChunk> base_t; + < 2, T, SegmentManager, NodesPerBlock> base_t; public: typedef detail::version_type version; template struct rebind { - typedef node_allocator other; + typedef node_allocator other; }; node_allocator(SegmentManager *segment_mngr) @@ -265,7 +265,7 @@ class node_allocator template node_allocator - (const node_allocator &other) + (const node_allocator &other) : base_t(other) {} @@ -288,7 +288,7 @@ class node_allocator template struct rebind { - typedef node_allocator other; + typedef node_allocator other; }; private: @@ -317,7 +317,7 @@ class node_allocator //!Can throw boost::interprocess::bad_alloc template node_allocator - (const node_allocator &other); + (const node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -343,9 +343,9 @@ class node_allocator //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -378,7 +378,7 @@ class node_allocator size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -387,11 +387,11 @@ class node_allocator multiallocation_iterator 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 chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -404,7 +404,7 @@ class node_allocator //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -417,7 +417,7 @@ class node_allocator //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index dd26ef9..b7c63da 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -42,14 +42,14 @@ namespace detail { template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , 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, NodesPerChunk - , MaxFreeChunks, OverheadPercent> + < private_adaptive_pool_base < Version, T, SegmentManager, NodesPerBlock + , MaxFreeBlocks, OverheadPercent> , Version , T , SegmentManager @@ -63,13 +63,13 @@ class private_adaptive_pool_base /// @cond private: typedef private_adaptive_pool_base - < Version, T, SegmentManager, NodesPerChunk - , MaxFreeChunks, OverheadPercent> self_t; + < Version, T, SegmentManager, NodesPerBlock + , MaxFreeBlocks, OverheadPercent> self_t; typedef detail::private_adaptive_node_pool node_pool_t; @@ -103,7 +103,7 @@ class private_adaptive_pool_base struct rebind { typedef private_adaptive_pool_base - other; + other; }; /// @cond @@ -114,8 +114,8 @@ class private_adaptive_pool_base typedef detail::private_adaptive_node_pool type; @@ -148,7 +148,7 @@ class private_adaptive_pool_base template private_adaptive_pool_base (const private_adaptive_pool_base - &other) + &other) : m_node_pool(other.get_segment_manager()) {} @@ -176,21 +176,21 @@ class private_adaptive_pool_base }; //!Equality test for same type of private_adaptive_pool_base -template inline -bool operator==(const private_adaptive_pool_base &alloc1, - const private_adaptive_pool_base &alloc2) +template inline +bool operator==(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) { return &alloc1 == &alloc2; } //!Inequality test for same type of private_adaptive_pool_base -template inline -bool operator!=(const private_adaptive_pool_base &alloc1, - const private_adaptive_pool_base &alloc2) +template inline +bool operator!=(const private_adaptive_pool_base &alloc1, + const private_adaptive_pool_base &alloc2) { return &alloc1 != &alloc2; } template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 - , std::size_t MaxFreeChunks = 2 + , std::size_t NodesPerBlock = 64 + , std::size_t MaxFreeBlocks = 2 , unsigned char OverheadPercent = 5 > class private_adaptive_pool_v1 @@ -198,19 +198,19 @@ class private_adaptive_pool_v1 < 1 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > { public: typedef detail::private_adaptive_pool_base - < 1, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; template struct rebind { - typedef private_adaptive_pool_v1 other; + typedef private_adaptive_pool_v1 other; }; private_adaptive_pool_v1(SegmentManager *segment_mngr) @@ -219,7 +219,7 @@ class private_adaptive_pool_v1 template private_adaptive_pool_v1 - (const private_adaptive_pool_v1 &other) + (const private_adaptive_pool_v1 &other) : base_t(other) {} }; @@ -234,17 +234,17 @@ class private_adaptive_pool_v1 //!placing the allocator in shared memory, memory mapped-files, etc... //!This allocator has its own node pool. //! -//!NodesPerChunk is the minimum number of nodes of nodes allocated at once when -//!the allocator needs runs out of nodes. MaxFreeChunks is the maximum number of totally free chunks -//!that the adaptive node pool will hold. The rest of the totally free chunks will be +//!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 NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class private_adaptive_pool @@ -253,8 +253,8 @@ class private_adaptive_pool < 2 , T , SegmentManager - , NodesPerChunk - , MaxFreeChunks + , NodesPerBlock + , MaxFreeBlocks , OverheadPercent > /// @endcond @@ -262,7 +262,7 @@ class private_adaptive_pool #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::private_adaptive_pool_base - < 2, T, SegmentManager, NodesPerChunk, MaxFreeChunks, OverheadPercent> base_t; + < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: typedef detail::version_type version; @@ -270,7 +270,7 @@ class private_adaptive_pool struct rebind { typedef private_adaptive_pool - other; + other; }; private_adaptive_pool(SegmentManager *segment_mngr) @@ -279,7 +279,7 @@ class private_adaptive_pool template private_adaptive_pool - (const private_adaptive_pool &other) + (const private_adaptive_pool &other) : base_t(other) {} @@ -303,7 +303,7 @@ class private_adaptive_pool struct rebind { typedef private_adaptive_pool - other; + other; }; private: @@ -332,7 +332,7 @@ class private_adaptive_pool //!Can throw boost::interprocess::bad_alloc template private_adaptive_pool - (const private_adaptive_pool &other); + (const private_adaptive_pool &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -358,9 +358,9 @@ class private_adaptive_pool //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -393,7 +393,7 @@ class private_adaptive_pool size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -402,11 +402,11 @@ class private_adaptive_pool multiallocation_iterator 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 chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -419,7 +419,7 @@ class private_adaptive_pool //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -432,7 +432,7 @@ class private_adaptive_pool //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -446,15 +446,15 @@ class private_adaptive_pool //!Equality test for same type //!of private_adaptive_pool -template inline -bool operator==(const private_adaptive_pool &alloc1, - const private_adaptive_pool &alloc2); +template inline +bool operator==(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); //!Inequality test for same type //!of private_adaptive_pool -template inline -bool operator!=(const private_adaptive_pool &alloc1, - const private_adaptive_pool &alloc2); +template inline +bool operator!=(const private_adaptive_pool &alloc1, + const private_adaptive_pool &alloc2); #endif diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index 2d75584..284fea2 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -8,16 +8,6 @@ // ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -// -// (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 @@ -52,11 +42,11 @@ namespace detail { template < unsigned int Version , class T , class SegmentManager - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class private_node_allocator_base : public node_pool_allocation_impl - < private_node_allocator_base < Version, T, SegmentManager, NodesPerChunk> + < private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock> , Version , T , SegmentManager @@ -70,11 +60,11 @@ class private_node_allocator_base /// @cond private: typedef private_node_allocator_base - < Version, T, SegmentManager, NodesPerChunk> self_t; + < Version, T, SegmentManager, NodesPerBlock> self_t; typedef detail::private_node_pool node_pool_t; BOOST_STATIC_ASSERT((Version <=2)); @@ -107,7 +97,7 @@ class private_node_allocator_base struct rebind { typedef private_node_allocator_base - other; + other; }; /// @cond @@ -117,7 +107,7 @@ class private_node_allocator_base typedef detail::private_node_pool type; static type *get(void *p) @@ -149,7 +139,7 @@ class private_node_allocator_base template private_node_allocator_base (const private_node_allocator_base - &other) + &other) : m_node_pool(other.get_segment_manager()) {} @@ -190,24 +180,24 @@ bool operator!=(const private_node_allocator_base &alloc1, template < class T , class SegmentManager - , std::size_t NodesPerChunk = 64 + , std::size_t NodesPerBlock = 64 > class private_node_allocator_v1 : public private_node_allocator_base < 1 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > { public: typedef detail::private_node_allocator_base - < 1, T, SegmentManager, NodesPerChunk> base_t; + < 1, T, SegmentManager, NodesPerBlock> base_t; template struct rebind { - typedef private_node_allocator_v1 other; + typedef private_node_allocator_v1 other; }; private_node_allocator_v1(SegmentManager *segment_mngr) @@ -216,7 +206,7 @@ class private_node_allocator_v1 template private_node_allocator_v1 - (const private_node_allocator_v1 &other) + (const private_node_allocator_v1 &other) : base_t(other) {} }; @@ -229,11 +219,11 @@ class private_node_allocator_v1 //!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. NodesPerChunk is the number of nodes allocated +//!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 NodesPerChunk + , std::size_t NodesPerBlock > class private_node_allocator /// @cond @@ -241,14 +231,14 @@ class private_node_allocator < 2 , T , SegmentManager - , NodesPerChunk + , NodesPerBlock > /// @endcond { #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED typedef detail::private_node_allocator_base - < 2, T, SegmentManager, NodesPerChunk> base_t; + < 2, T, SegmentManager, NodesPerBlock> base_t; public: typedef detail::version_type version; @@ -256,7 +246,7 @@ class private_node_allocator struct rebind { typedef private_node_allocator - other; + other; }; private_node_allocator(SegmentManager *segment_mngr) @@ -265,7 +255,7 @@ class private_node_allocator template private_node_allocator - (const private_node_allocator &other) + (const private_node_allocator &other) : base_t(other) {} @@ -289,7 +279,7 @@ class private_node_allocator struct rebind { typedef private_node_allocator - other; + other; }; private: @@ -318,7 +308,7 @@ class private_node_allocator //!Can throw boost::interprocess::bad_alloc template private_node_allocator - (const private_node_allocator &other); + (const private_node_allocator &other); //!Destructor, removes node_pool_t from memory //!if its reference count reaches to zero. Never throws @@ -344,9 +334,9 @@ class private_node_allocator //!Never throws void deallocate(const pointer &ptr, size_type count); - //!Deallocates all free chunks + //!Deallocates all free blocks //!of the pool - void deallocate_free_chunks(); + void deallocate_free_blocks(); //!Swaps allocators. Does not throw. If each allocator is placed in a //!different memory segment, the result is undefined. @@ -379,7 +369,7 @@ class private_node_allocator size_type preferred_size, size_type &received_size, const pointer &reuse = 0); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -388,11 +378,11 @@ class private_node_allocator multiallocation_iterator 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 chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -405,7 +395,7 @@ class private_node_allocator //!Throws boost::interprocess::bad_alloc if there is no enough memory pointer allocate_one(); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -418,7 +408,7 @@ class private_node_allocator //!with other functions different from allocate_one(). Never throws void deallocate_one(const pointer &p); - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -432,15 +422,15 @@ class private_node_allocator //!Equality test for same type //!of private_node_allocator -template inline -bool operator==(const private_node_allocator &alloc1, - const private_node_allocator &alloc2); +template inline +bool operator==(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); //!Inequality test for same type //!of private_node_allocator -template inline -bool operator!=(const private_node_allocator &alloc1, - const private_node_allocator &alloc2); +template inline +bool operator!=(const private_node_allocator &alloc1, + const private_node_allocator &alloc2); #endif From ffba3d772ae8ab3fee1729948593a2bb273f6bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:39:21 +0000 Subject: [PATCH 27/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45702] --- .../allocators/detail/adaptive_node_pool.hpp | 362 ++++++++++-------- .../allocators/detail/allocator_common.hpp | 65 +++- .../allocators/detail/node_pool.hpp | 106 ++--- .../containers/detail/node_alloc_holder.hpp | 2 +- .../interprocess/containers/flat_map.hpp | 16 +- .../boost/interprocess/containers/vector.hpp | 14 +- .../interprocess/detail/file_wrapper.hpp | 4 +- 7 files changed, 318 insertions(+), 251 deletions(-) diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 0495f41..c5ef2a4 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -71,18 +71,18 @@ class private_adaptive_node_pool_impl std::size_t hdr_offset; }; - struct chunk_info_t + struct block_info_t : public hdr_offset_holder, public multiset_hook_t { - //An intrusive list of free node from this chunk + //An intrusive list of free node from this block free_nodes_t free_nodes; - friend bool operator <(const chunk_info_t &l, const chunk_info_t &r) + 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 chunks are deallocated. + //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(); @@ -90,11 +90,11 @@ class private_adaptive_node_pool_impl } }; typedef typename bi::make_multiset - >::type chunk_multiset_t; - typedef typename chunk_multiset_t::iterator chunk_iterator; + >::type block_multiset_t; + typedef typename block_multiset_t::iterator block_iterator; static const std::size_t MaxAlign = alignment_of::value; - static const std::size_t HdrSize = ((sizeof(chunk_info_t)-1)/MaxAlign+1)*MaxAlign; + 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) @@ -102,15 +102,15 @@ class private_adaptive_node_pool_impl //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_subchunk = (dividend - 1)/divisor + 1; + std::size_t elements_per_subblock = (dividend - 1)/divisor + 1; std::size_t candidate_power_of_2 = - upper_power_of_2(elements_per_subchunk*real_node_size + HdrOffsetSize); + upper_power_of_2(elements_per_subblock*real_node_size + HdrOffsetSize); bool overhead_satisfied = false; - //Now calculate the wors-case overhead for a subchunk - const std::size_t max_subchunk_overhead = HdrSize + PayloadPerAllocation; + //Now calculate the wors-case overhead for a subblock + const std::size_t max_subblock_overhead = HdrSize + PayloadPerAllocation; while(!overhead_satisfied){ - elements_per_subchunk = (candidate_power_of_2 - max_subchunk_overhead)/real_node_size; - const std::size_t overhead_size = candidate_power_of_2 - elements_per_subchunk*real_node_size; + 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; } @@ -121,30 +121,30 @@ class private_adaptive_node_pool_impl return candidate_power_of_2; } - static void calculate_num_subchunks - (std::size_t alignment, std::size_t real_node_size, std::size_t elements_per_chunk - ,std::size_t &num_subchunks, std::size_t &real_num_node, std::size_t overhead_percent) + 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_subchunk = (alignment - HdrOffsetSize)/real_node_size; - std::size_t possible_num_subchunk = (elements_per_chunk - 1)/elements_per_subchunk + 1; - std::size_t hdr_subchunk_elements = (alignment - HdrSize - PayloadPerAllocation)/real_node_size; - while(((possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements) < elements_per_chunk){ - ++possible_num_subchunk; + 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_subchunk = (alignment - HdrOffsetSize)/real_node_size; + elements_per_subblock = (alignment - HdrOffsetSize)/real_node_size; bool overhead_satisfied = false; while(!overhead_satisfied){ - const std::size_t total_data = (elements_per_subchunk*(possible_num_subchunk-1) + hdr_subchunk_elements)*real_node_size; - const std::size_t total_size = alignment*possible_num_subchunk; + 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_subchunk; + ++possible_num_subblock; } } - num_subchunks = possible_num_subchunk; - real_num_node = (possible_num_subchunk-1)*elements_per_subchunk + hdr_subchunk_elements; + num_subblocks = possible_num_subblock; + real_num_node = (possible_num_subblock-1)*elements_per_subblock + hdr_subblock_elements; } public: @@ -154,27 +154,27 @@ class private_adaptive_node_pool_impl //!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_chunk, std::size_t max_free_chunks + , std::size_t nodes_per_block, std::size_t max_free_blocks , unsigned char overhead_percent ) - : m_max_free_chunks(max_free_chunks) + : m_max_free_blocks(max_free_blocks) , m_real_node_size(lcm(node_size, std::size_t(alignment_of::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_chunk_alignment(calculate_alignment(overhead_percent, m_real_node_size)) - //This is the real number of nodes per chunk - , m_num_subchunks(0) + , 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_chunk_multiset() - , m_totally_free_chunks(0) + , m_block_multiset() + , m_totally_free_blocks(0) { - calculate_num_subchunks(m_real_chunk_alignment, m_real_node_size, nodes_per_chunk, m_num_subchunks, m_real_num_node, overhead_percent); + 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 chunks. Never throws + //!Destructor. Deallocates all allocated blocks. Never throws ~private_adaptive_node_pool_impl() { priv_clear(); } @@ -190,8 +190,8 @@ class private_adaptive_node_pool_impl { priv_invariants(); //If there are no free nodes we allocate a new block - if (m_chunk_multiset.empty()){ - priv_alloc_chunk(1); + 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(); @@ -200,11 +200,11 @@ class private_adaptive_node_pool_impl //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - this->priv_reinsert_nodes_in_chunk + this->priv_reinsert_nodes_in_block (multiallocation_iterator::create_simple_range(pElem)); - //Update free chunk count - if(m_totally_free_chunks > m_max_free_chunks){ - this->priv_deallocate_free_chunks(m_max_free_chunks); + //Update free block count + if(m_totally_free_blocks > m_max_free_blocks){ + this->priv_deallocate_free_blocks(m_max_free_blocks); } priv_invariants(); } @@ -215,17 +215,32 @@ class private_adaptive_node_pool_impl { try{ priv_invariants(); - for(std::size_t i = 0; i != n; ++i){ - //If there are no free nodes we allocate all needed chunks - if (m_chunk_multiset.empty()){ - priv_alloc_chunk(((n - i) - 1)/m_real_num_node + 1); + std::size_t i = 0; + 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); } - nodes.push_front(priv_take_first_node()); + 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(); + nodes.push_back(new_node); + } + + if(free_nodes.empty()){ + m_block_multiset.erase(m_block_multiset.begin()); + } + i += num_elems; } } catch(...){ this->deallocate_nodes(nodes, nodes.size()); - this->priv_deallocate_free_chunks(m_max_free_chunks); throw; } priv_invariants(); @@ -259,20 +274,20 @@ class private_adaptive_node_pool_impl //!Deallocates the nodes pointed by the multiallocation iterator. Never throws void deallocate_nodes(multiallocation_iterator it) { - this->priv_reinsert_nodes_in_chunk(it); - if(m_totally_free_chunks > m_max_free_chunks){ - this->priv_deallocate_free_chunks(m_max_free_chunks); + this->priv_reinsert_nodes_in_block(it); + if(m_totally_free_blocks > m_max_free_blocks){ + this->priv_deallocate_free_blocks(m_max_free_blocks); } } - void deallocate_free_chunks() - { this->priv_deallocate_free_chunks(0); } + void deallocate_free_blocks() + { this->priv_deallocate_free_blocks(0); } std::size_t num_free_nodes() { - typedef typename chunk_multiset_t::const_iterator citerator; + typedef typename block_multiset_t::const_iterator citerator; std::size_t count = 0; - citerator it (m_chunk_multiset.begin()), itend(m_chunk_multiset.end()); + citerator it (m_block_multiset.begin()), itend(m_block_multiset.end()); for(; it != itend; ++it){ count += it->free_nodes.size(); } @@ -281,76 +296,80 @@ class private_adaptive_node_pool_impl void swap(private_adaptive_node_pool_impl &other) { - assert(m_max_free_chunks == other.m_max_free_chunks); + assert(m_max_free_blocks == other.m_max_free_blocks); assert(m_real_node_size == other.m_real_node_size); - assert(m_real_chunk_alignment == other.m_real_chunk_alignment); + 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_chunks, other.m_totally_free_chunks); - m_chunk_multiset.swap(other.m_chunk_multiset); + 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_chunks(std::size_t max_free_chunks) + 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 chunks. If so, deallocate as much + //and check if we have free blocks. If so, deallocate as much //as we can to stay below the limit - for( chunk_iterator itend = m_chunk_multiset.end() - ; m_totally_free_chunks > max_free_chunks - ; --m_totally_free_chunks + for( block_iterator itend = m_block_multiset.end() + ; m_totally_free_blocks > max_free_blocks + ; --m_totally_free_blocks ){ - assert(!m_chunk_multiset.empty()); - chunk_iterator it = itend; + 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_chunk_multiset.erase_and_dispose - (it, chunk_destroyer(this)); + m_block_multiset.erase_and_dispose + (it, block_destroyer(this)); } } - void priv_reinsert_nodes_in_chunk(multiallocation_iterator it) + void priv_reinsert_nodes_in_block(multiallocation_iterator it) { multiallocation_iterator itend; - chunk_iterator chunk_it(m_chunk_multiset.end()); + block_iterator block_it(m_block_multiset.end()); while(it != itend){ void *pElem = &*it; ++it; priv_invariants(); - chunk_info_t *chunk_info = this->priv_chunk_from_node(pElem); - assert(chunk_info->free_nodes.size() < m_real_num_node); + 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(pElem); - chunk_info->free_nodes.push_front(*to_deallocate); + block_info->free_nodes.push_front(*to_deallocate); - chunk_iterator this_chunk(chunk_multiset_t::s_iterator_to(*chunk_info)); - chunk_iterator next_chunk(this_chunk); - ++next_chunk; + 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 chunk - std::size_t this_chunk_free_nodes = this_chunk->free_nodes.size(); + //Cache the free nodes from the block + std::size_t this_block_free_nodes = this_block->free_nodes.size(); - if(this_chunk_free_nodes == 1){ - m_chunk_multiset.insert(m_chunk_multiset.begin(), *chunk_info); + if(this_block_free_nodes == 1){ + m_block_multiset.insert(m_block_multiset.begin(), *block_info); } else{ - chunk_iterator next_chunk(this_chunk); - ++next_chunk; - if(next_chunk != chunk_it){ - std::size_t next_free_nodes = next_chunk->free_nodes.size(); - if(this_chunk_free_nodes > next_free_nodes){ - //Now move the chunk to the new position - m_chunk_multiset.erase(this_chunk); - m_chunk_multiset.insert(*chunk_info); + 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 chunk count - if(this_chunk_free_nodes == m_real_num_node){ - ++m_totally_free_chunks; + //Update free block count + if(this_block_free_nodes == m_real_num_node){ + ++m_totally_free_blocks; } priv_invariants(); } @@ -358,40 +377,40 @@ class private_adaptive_node_pool_impl node_t *priv_take_first_node() { - assert(m_chunk_multiset.begin() != m_chunk_multiset.end()); + 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_chunk_multiset.begin()->free_nodes; + 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_chunk_multiset.erase(m_chunk_multiset.begin()); + m_block_multiset.erase(m_block_multiset.begin()); } else if(free_nodes_count == m_real_num_node){ - --m_totally_free_chunks; + --m_totally_free_blocks; } priv_invariants(); return first_node; } - class chunk_destroyer; - friend class chunk_destroyer; + class block_destroyer; + friend class block_destroyer; - class chunk_destroyer + class block_destroyer { public: - chunk_destroyer(const private_adaptive_node_pool_impl *impl) + block_destroyer(const private_adaptive_node_pool_impl *impl) : mp_impl(impl) {} - void operator()(typename chunk_multiset_t::pointer to_deallocate) + 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_subchunk_from_chunk((chunk_info_t*)detail::get_pointer(to_deallocate)); + hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block((block_info_t*)detail::get_pointer(to_deallocate)); mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder); } const private_adaptive_node_pool_impl *mp_impl; @@ -403,12 +422,12 @@ class private_adaptive_node_pool_impl #ifdef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS #undef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS { - //We iterate through the chunk list to free the memory - chunk_iterator it(m_chunk_multiset.begin()), - itend(m_chunk_multiset.end()), to_deallocate; + //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){ - chunk_iterator prev(it); + block_iterator prev(it); --prev; std::size_t sp = prev->free_nodes.size(), si = it->free_nodes.size(); @@ -419,35 +438,35 @@ class private_adaptive_node_pool_impl { //Check that the total free nodes are correct - it = m_chunk_multiset.begin(); - itend = m_chunk_multiset.end(); + 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_chunks*m_real_num_node); + assert(total_free_nodes >= m_totally_free_blocks*m_real_num_node); } { - //Check that the total totally free chunks are correct - it = m_chunk_multiset.begin(); - itend = m_chunk_multiset.end(); - std::size_t total_free_chunks = 0; + //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_chunks += (it->free_nodes.size() == m_real_num_node); + total_free_blocks += (it->free_nodes.size() == m_real_num_node); } - assert(total_free_chunks == m_totally_free_chunks); + assert(total_free_blocks == m_totally_free_blocks); } { //Check that header offsets are correct - it = m_chunk_multiset.begin(); + it = m_block_multiset.begin(); for(; it != itend; ++it){ - hdr_offset_holder *hdr_off_holder = priv_first_subchunk_from_chunk(&*it); - for(std::size_t i = 0, max = m_num_subchunks; i < max; ++i){ + 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((char*)&*it- (char*)hdr_off_holder)); - assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); - assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); - hdr_off_holder = (hdr_offset_holder *)((char*)hdr_off_holder + m_real_chunk_alignment); + 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 = (hdr_offset_holder *)((char*)hdr_off_holder + m_real_block_alignment); } } } @@ -460,72 +479,72 @@ class private_adaptive_node_pool_impl void priv_clear() { #ifndef NDEBUG - chunk_iterator it = m_chunk_multiset.begin(); - chunk_iterator itend = m_chunk_multiset.end(); + 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 assert(it->free_nodes.size() == m_real_num_node); ++num_free_nodes; } - assert(num_free_nodes == m_totally_free_chunks); + assert(num_free_nodes == m_totally_free_blocks); #endif priv_invariants(); - m_chunk_multiset.clear_and_dispose - (chunk_destroyer(this)); - m_totally_free_chunks = 0; + m_block_multiset.clear_and_dispose + (block_destroyer(this)); + m_totally_free_blocks = 0; } - chunk_info_t *priv_chunk_from_node(void *node) const + block_info_t *priv_block_from_node(void *node) const { hdr_offset_holder *hdr_off_holder = - (hdr_offset_holder*)((std::size_t)node & std::size_t(~(m_real_chunk_alignment - 1))); - assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); - assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); - chunk_info_t *chunk = (chunk_info_t *)(((char*)hdr_off_holder) + hdr_off_holder->hdr_offset); - assert(chunk->hdr_offset == 0); - return chunk; + (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 = (block_info_t *)(((char*)hdr_off_holder) + hdr_off_holder->hdr_offset); + assert(block->hdr_offset == 0); + return block; } - hdr_offset_holder *priv_first_subchunk_from_chunk(chunk_info_t *chunk) const + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const { hdr_offset_holder *hdr_off_holder = (hdr_offset_holder*) - (((char*)chunk) - (m_num_subchunks-1)*m_real_chunk_alignment); - assert(hdr_off_holder->hdr_offset == std::size_t((char*)chunk - (char*)hdr_off_holder)); - assert(0 == ((std::size_t)hdr_off_holder & (m_real_chunk_alignment - 1))); - assert(0 == (hdr_off_holder->hdr_offset & (m_real_chunk_alignment - 1))); + (((char*)block) - (m_num_subblocks-1)*m_real_block_alignment); + assert(hdr_off_holder->hdr_offset == std::size_t((char*)block - (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 chunks of nodes. Can throw boost::interprocess::bad_alloc - void priv_alloc_chunk(std::size_t n) + //!Allocates a several blocks of nodes. Can throw boost::interprocess::bad_alloc + void priv_alloc_block(std::size_t n) { - std::size_t real_chunk_size = m_real_chunk_alignment*m_num_subchunks - SegmentManagerBase::PayloadPerAllocation; - std::size_t elements_per_subchunk = (m_real_chunk_alignment - HdrOffsetSize)/m_real_node_size; - std::size_t hdr_subchunk_elements = (m_real_chunk_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size; + 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 = detail::char_ptr_cast - (mp_segment_mngr_base->allocate_aligned(real_chunk_size, m_real_chunk_alignment)); + (mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment)); if(!mem_address) throw std::bad_alloc(); - ++m_totally_free_chunks; + ++m_totally_free_blocks; - //First initialize header information on the last subchunk - char *hdr_addr = mem_address + m_real_chunk_alignment*(m_num_subchunks-1); - chunk_info_t *c_info = new(hdr_addr)chunk_info_t; + //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(&static_cast(c_info)->hdr_offset) == static_cast(c_info)); typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin(); - for( std::size_t subchunk = 0, maxsubchunk = m_num_subchunks - 1 - ; subchunk < maxsubchunk - ; ++subchunk, mem_address += m_real_chunk_alignment){ + 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_subchunk; ++i){ + 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; } @@ -534,13 +553,13 @@ class private_adaptive_node_pool_impl 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_subchunk_elements; ++i){ + 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 chunk after the free node list is full - m_chunk_multiset.insert(m_chunk_multiset.end(), *c_info); + //Insert the block after the free node list is full + m_block_multiset.insert(m_block_multiset.end(), *c_info); } } @@ -548,25 +567,25 @@ class private_adaptive_node_pool_impl typedef typename pointer_to_other ::type segment_mngr_base_ptr_t; - const std::size_t m_max_free_chunks; + 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_chunk_alignment; - std::size_t m_num_subchunks; - //This is the real number of nodes per chunk + 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 - chunk_multiset_t m_chunk_multiset; //Intrusive chunk list - std::size_t m_totally_free_chunks; //Free chunks + 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 NodesPerChunk - , std::size_t MaxFreeChunks + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks , unsigned char OverheadPercent > class private_adaptive_node_pool @@ -583,11 +602,14 @@ class private_adaptive_node_pool public: typedef SegmentManager segment_manager; - static const std::size_t nodes_per_chunk = NodesPerChunk; + 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, NodesPerChunk, MaxFreeChunks, OverheadPercent) + : base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent) {} //!Returns the segment manager. Never throws @@ -598,22 +620,22 @@ class private_adaptive_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 chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time template< class SegmentManager , std::size_t NodeSize - , std::size_t NodesPerChunk - , std::size_t MaxFreeChunks + , 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 - + > { typedef detail::shared_pool_impl < private_adaptive_node_pool - + > base_t; public: shared_adaptive_node_pool(SegmentManager *segment_mgnr) diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index bd64f3c..f5ccddd 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -294,7 +294,7 @@ class array_allocation_impl (command, limit_size, preferred_size, received_size, detail::get_pointer(reuse)); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -307,7 +307,7 @@ class array_allocation_impl } //!Allocates n_elements elements, each one of size elem_sizes[i]in a - //!contiguous chunk + //!contiguous block //!of memory. The elements must be deallocated multiallocation_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) { @@ -315,7 +315,7 @@ class array_allocation_impl (this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T))); } - //!Allocates many elements of size elem_size in a contiguous chunk + //!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 @@ -439,7 +439,7 @@ class node_pool_allocation_impl return pointer(static_cast(pool->allocate_node())); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -462,7 +462,7 @@ class node_pool_allocation_impl pool->deallocate_node(detail::get_pointer(p)); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -471,9 +471,14 @@ class node_pool_allocation_impl void deallocate_individual(multiallocation_iterator it) { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } - //!Deallocates all free chunks of the pool + //!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_chunks(); } + { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); } }; template @@ -576,7 +581,7 @@ class cached_allocator_impl pointer allocate_one() { return pointer(static_cast(this->m_cache.cached_allocation())); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -591,7 +596,7 @@ class cached_allocator_impl void deallocate_one(const pointer &p) { this->m_cache.cached_deallocation(detail::get_pointer(p)); } - //!Allocates many elements of size == 1 in a contiguous chunk + //!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 @@ -600,9 +605,9 @@ class cached_allocator_impl void deallocate_individual(multiallocation_iterator it) { m_cache.cached_deallocation(it.base()); } - //!Deallocates all free chunks of the pool - void deallocate_free_chunks() - { m_cache.get_node_pool()->deallocate_free_chunks(); } + //!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. @@ -616,6 +621,10 @@ class cached_allocator_impl 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 m_cache; @@ -639,7 +648,7 @@ bool operator!=(const cached_allocator_impl &alloc1, //!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 chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time template class shared_pool_impl : public private_node_allocator_t @@ -661,7 +670,7 @@ class shared_pool_impl : private_node_allocator_t(segment_mngr) {} - //!Destructor. Deallocates all allocated chunks. Never throws + //!Destructor. Deallocates all allocated blocks. Never throws ~shared_pool_impl() {} @@ -730,24 +739,24 @@ class shared_pool_impl private_node_allocator_t::deallocate_nodes(it); } - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::deallocate_free_chunks(); + 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_chunks() + void purge_blocks() { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::purge_chunks(); + private_node_allocator_t::purge_blocks(); } //!Increments internal reference count and returns new count. Never throws @@ -769,6 +778,24 @@ class shared_pool_impl return --m_header.m_usecount; } + //!Deprecated, use deallocate_free_blocks. + void deallocate_free_chunks() + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + //!Deprecated, use purge_blocks. + void purge_chunks() + { + //----------------------- + boost::interprocess::scoped_lock 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 diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index 3418d9f..3e573d2 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -60,30 +60,30 @@ class private_node_pool_impl typedef typename bi::make_slist < node_t, bi::base_hook , bi::linear - , bi::constant_time_size >::type chunkslist_t; + , bi::constant_time_size >::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_chunk) - : m_nodes_per_chunk(nodes_per_chunk) + 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::value))) //General purpose allocator , mp_segment_mngr_base(segment_mngr_base) - , m_chunklist() + , m_blocklist() , m_freelist() //Debug node count , m_allocated(0) {} - //!Destructor. Deallocates all allocated chunks. Never throws + //!Destructor. Deallocates all allocated blocks. Never throws ~private_node_pool_impl() - { this->purge_chunks(); } + { this->purge_blocks(); } std::size_t get_real_num_node() const - { return m_nodes_per_chunk; } + { return m_nodes_per_block; } //!Returns the segment manager. Never throws segment_manager_base_type* get_segment_manager_base()const @@ -94,7 +94,7 @@ class private_node_pool_impl { //If there are no free nodes we allocate a new block if (m_freelist.empty()) - priv_alloc_chunk(); + priv_alloc_block(); //We take the first free node node_t *n = (node_t*)&m_freelist.front(); m_freelist.pop_front(); @@ -173,36 +173,36 @@ class private_node_pool_impl } } - //!Deallocates all the free chunks of memory. Never throws - void deallocate_free_chunks() + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() { typedef typename free_nodes_t::iterator nodelist_iterator; - typename chunkslist_t::iterator bit(m_chunklist.before_begin()), - it(m_chunklist.begin()), - itend(m_chunklist.end()); + 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_chunk, alignment_of::value); + (m_real_node_size*m_nodes_per_block, alignment_of::value); while(it != itend){ - //Collect all the nodes from the chunk pointed by it + //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_chunk_from_hook(&*it, blocksize); + 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_chunk + //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_chunk){ + if(free_nodes.size() == m_nodes_per_block){ //Unlink the nodes free_nodes.clear(); - it = m_chunklist.erase_after(bit); + it = m_blocklist.erase_after(bit); mp_segment_mngr_base->deallocate((void*)addr); } //Otherwise, insert them in the backup list, since the @@ -240,19 +240,19 @@ class private_node_pool_impl //!Deallocates all used memory. Precondition: all nodes allocated from this pool should //!already be deallocated. Otherwise, undefined behaviour. Never throws - void purge_chunks() + 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_chunk, alignment_of::value); - typename chunkslist_t::iterator - it(m_chunklist.begin()), itend(m_chunklist.end()), aux; + (m_real_node_size*m_nodes_per_block, alignment_of::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_chunklist.empty()){ - void *addr = get_chunk_from_hook(&m_chunklist.front(), blocksize); - m_chunklist.pop_front(); + 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 @@ -262,7 +262,7 @@ class private_node_pool_impl void swap(private_node_pool_impl &other) { std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); - m_chunklist.swap(other.m_chunklist); + m_blocklist.swap(other.m_blocklist); m_freelist.swap(other.m_freelist); std::swap(m_allocated, other.m_allocated); } @@ -305,36 +305,44 @@ class private_node_pool_impl const char * end_; }; - //!Allocates a chunk of nodes. Can throw boost::interprocess::bad_alloc - void priv_alloc_chunk() + //!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_chunk, alignment_of::value); + detail::get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of::value); char *pNode = detail::char_ptr_cast (mp_segment_mngr_base->allocate(blocksize + sizeof(node_t))); if(!pNode) throw bad_alloc(); char *pBlock = pNode; - m_chunklist.push_front(get_chunk_hook(pBlock, blocksize)); + 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_chunk; ++i, pNode += m_real_node_size){ + 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 chunk hook placed in the end of the chunk - static inline node_t & get_chunk_hook (void *chunk, std::size_t blocksize) + //!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 *static_cast( - static_cast((detail::char_ptr_cast(chunk) + blocksize))); + static_cast((detail::char_ptr_cast(block) + blocksize))); } - //!Returns the starting address of the chunk reference to the chunk hook placed in the end of the chunk - inline void *get_chunk_from_hook (node_t *hook, std::size_t 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 static_cast((detail::char_ptr_cast(hook) - blocksize)); } @@ -343,10 +351,10 @@ class private_node_pool_impl typedef typename pointer_to_other ::type segment_mngr_base_ptr_t; - const std::size_t m_nodes_per_chunk; + 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 - chunkslist_t m_chunklist; //Intrusive container of chunks + 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 }; @@ -355,8 +363,8 @@ class private_node_pool_impl //!Pooled shared memory allocator using single segregated storage. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time -template< class SegmentManager, std::size_t NodeSize, std::size_t NodesPerChunk > +//!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 @@ -370,11 +378,13 @@ class private_node_pool public: typedef SegmentManager segment_manager; - static const std::size_t nodes_per_chunk = NodesPerChunk; + 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, NodesPerChunk) + : base_t(segment_mngr, NodeSize, NodesPerBlock) {} //!Returns the segment manager. Never throws @@ -386,24 +396,24 @@ class private_node_pool //!Pooled shared memory allocator using single segregated storage. Includes //!a reference count but the class does not delete itself, this is //!responsibility of user classes. Node size (NodeSize) and the number of -//!nodes allocated per chunk (NodesPerChunk) are known at compile time +//!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 chunk (NodesPerChunk) are known at compile time +//!nodes allocated per block (NodesPerBlock) are known at compile time template< class SegmentManager , std::size_t NodeSize - , std::size_t NodesPerChunk + , std::size_t NodesPerBlock > class shared_node_pool : public detail::shared_pool_impl < private_node_pool - + > { typedef detail::shared_pool_impl < private_node_pool - + > base_t; public: shared_node_pool(SegmentManager *segment_mgnr) diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 2f9f73a..9f839ba 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -275,7 +275,7 @@ struct node_alloc_holder { typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; - //Try to allocate memory in a single chunk + //Try to allocate memory in a single block multiallocation_iterator itbeg = this->node_alloc().allocate_individual(n), itend, itold; int constructed = 0; diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 8901471..9f713fa 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -479,8 +479,8 @@ class flat_map //! //! Note: Invalidates elements with keys //! not less than the erased element. - void erase(const_iterator position) - { m_flat_tree.erase(force(position)); } + iterator erase(const_iterator position) + { return force(m_flat_tree.erase(force(position))); } //! Effects: Erases all elements in the container with key equivalent to x. //! @@ -499,8 +499,8 @@ class flat_map //! //! Complexity: Logarithmic search time plus erasure time //! linear to the elements with bigger keys. - void erase(const_iterator first, const_iterator last) - { m_flat_tree.erase(force(first), force(last)); } + iterator erase(const_iterator first, const_iterator last) + { return force(m_flat_tree.erase(force(first), force(last))); } //! Effects: erase(a.begin(),a.end()). //! @@ -1060,8 +1060,8 @@ class flat_multimap //! //! Note: Invalidates elements with keys //! not less than the erased element. - void erase(const_iterator position) - { m_flat_tree.erase(force(position)); } + iterator erase(const_iterator position) + { return force(m_flat_tree.erase(force(position))); } //! Effects: Erases all elements in the container with key equivalent to x. //! @@ -1080,8 +1080,8 @@ class flat_multimap //! //! Complexity: Logarithmic search time plus erasure time //! linear to the elements with bigger keys. - void erase(const_iterator first, const_iterator last) - { m_flat_tree.erase(force(first), force(last)); } + iterator erase(const_iterator first, const_iterator last) + { return force(m_flat_tree.erase(force(first), force(last))); } //! Effects: erase(a.begin(),a.end()). //! diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 561c87d..1b6aabc 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -1148,8 +1148,15 @@ class vector : private detail::vector_alloc_holder } else{ size_type received_size; - this->alloc().allocation_command(shrink_in_place, this->size(), this->capacity() - ,received_size, this->members_.m_start); + 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 + } } } } @@ -1786,9 +1793,10 @@ class vector : private detail::vector_alloc_holder 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_expand_fwd = num_expand_bwd = num_alloc = 0, num_shrink = 0; } #endif /// @endcond }; diff --git a/include/boost/interprocess/detail/file_wrapper.hpp b/include/boost/interprocess/detail/file_wrapper.hpp index e172f19..ca2d3e6 100644 --- a/include/boost/interprocess/detail/file_wrapper.hpp +++ b/include/boost/interprocess/detail/file_wrapper.hpp @@ -51,7 +51,7 @@ class file_wrapper //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE file_wrapper - (detail::moved_object &moved) + (detail::moved_object moved) { this->swap(moved.get()); } #else file_wrapper(file_wrapper &&moved) @@ -63,7 +63,7 @@ class file_wrapper //!Does not throw #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE file_wrapper &operator= - (detail::moved_object &moved) + (detail::moved_object moved) { file_wrapper tmp(moved); this->swap(tmp); From 044c20b4773becc9a7ca5c0d8f318b2457eadf74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 22:44:34 +0000 Subject: [PATCH 28/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45703] --- .../boost/interprocess/mem_algo/rbtree_best_fit.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 639032e..5e1f8ef 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -812,7 +812,7 @@ void* rbtree_best_fit:: assert(prev_block->m_size >= BlockCtrlUnits); priv_mark_as_free_block(prev_block); - //Update the old previous block in the free chunks tree + //Update the old previous block in the free blocks tree //If the new size fulfills tree invariants do nothing, //otherwise erase() + insert() { @@ -1058,12 +1058,12 @@ bool rbtree_best_fit:: 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 chunks tree + //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 chunk might - //overwrite the tree hook of the old next chunk. So we first erase the + //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 = @@ -1292,7 +1292,7 @@ void rbtree_best_fit::priv_deallocate(vo 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 chunks tree + //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){ @@ -1338,4 +1338,3 @@ void rbtree_best_fit::priv_deallocate(vo #include #endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_RBTREE_BEST_FIT_HPP - From 3e4b2e1a7640213390a96e1150723e7103f1afcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 23:17:56 +0000 Subject: [PATCH 29/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45704] --- .../detail/managed_multi_shared_memory.hpp | 389 ++++++++++++++++++ .../detail/managed_open_or_create_impl.hpp | 58 ++- .../interprocess/detail/math_functions.hpp | 20 + .../detail/multi_segment_services.hpp | 46 +++ .../detail/segment_manager_helper.hpp | 18 - .../boost/interprocess/detail/utilities.hpp | 18 + 6 files changed, 519 insertions(+), 30 deletions(-) create mode 100644 include/boost/interprocess/detail/managed_multi_shared_memory.hpp create mode 100644 include/boost/interprocess/detail/multi_segment_services.hpp diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp new file mode 100644 index 0000000..cead8b5 --- /dev/null +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include //list +#include //mapped_region +#include +#include //managed_open_or_create_impl +#include +#include +#include +#include + +//!\file +//!Describes a named shared memory object allocation user class. + +namespace boost { + +namespace interprocess { + +//!A basic shared memory named object creation class. Initializes the +//!shared memory segment. Inherits all basic functionality from +//!basic_managed_memory_impl +template + < + class CharType, + class MemoryAlgorithm, + template class IndexType + > +class basic_managed_multi_shared_memory + : public detail::basic_managed_memory_impl + +{ + + typedef basic_managed_multi_shared_memory + self_t; + typedef typename MemoryAlgorithm::void_pointer void_pointer; + typedef typename detail:: + managed_open_or_create_impl 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 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 create_new_segment(std::size_t alloc_size) + { + //We should allocate an extra byte so that the + //[base_addr + alloc_size] byte belongs to this segment + alloc_size += 1; + + //If requested size is less than minimum, update that + alloc_size = (m_min_segment_size > alloc_size) ? + m_min_segment_size : alloc_size; + if(mp_frontend->priv_new_segment(create_open_func::DoCreate, + alloc_size, 0)){ + shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin(); + return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1); + } + return result_type(0, 0); + } + + virtual bool update_segments () + { return true; } + + virtual ~group_services(){} + + void set_group(segment_group_id group) + { m_group = group; } + + segment_group_id get_group() const + { return m_group; } + + void set_min_segment_size(std::size_t min_segment_size) + { m_min_segment_size = min_segment_size; } + + std::size_t get_min_segment_size() const + { return m_min_segment_size; } + + private: + + frontend_t * const mp_frontend; + segment_group_id m_group; + std::size_t m_min_segment_size; + }; + + //!Functor to execute atomically when opening or creating a shared memory + //!segment. + struct create_open_func + { + enum type_t { DoCreate, DoOpen, DoOpenOrCreate }; + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + create_open_func(self_t * const frontend, + type_t type, std::size_t segment_number) + : mp_frontend(frontend), m_type(type), m_segment_number(segment_number){} + + bool operator()(void *addr, std::size_t size, bool created) const + { + if(((m_type == DoOpen) && created) || + ((m_type == DoCreate) && !created)) + return false; + segment_group_id group = mp_frontend->m_group_services.get_group(); + bool mapped = false; + bool impl_done = false; + + //Associate this newly created segment as the + //segment id = 0 of this group + void_pointer::insert_mapping + ( group + , (char*)addr - managed_impl::ManagedOpenOrCreateUserOffset + , size + managed_impl::ManagedOpenOrCreateUserOffset); + //Check if this is the master segment + if(!m_segment_number){ + //Create or open the Interprocess machinery + if(impl_done = created ? + mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size)){ + return true; + } + } + else{ + return true; + } + + //This is the cleanup part + //--------------- + if(impl_done){ + mp_frontend->close_impl(); + } + if(mapped){ + bool ret = void_pointer::erase_last_mapping(group); + assert(ret);(void)ret; + } + return false; + } + self_t * const mp_frontend; + type_t m_type; + std::size_t m_segment_number; + }; + + //!Functor to execute atomically when closing a shared memory segment. + struct close_func + { + typedef typename + basic_managed_multi_shared_memory::void_pointer void_pointer; + + close_func(self_t * const frontend) + : mp_frontend(frontend){} + + void operator()(const mapped_region ®ion, bool last) const + { + if(last) mp_frontend->destroy_impl(); + else mp_frontend->close_impl(); + } + self_t * const mp_frontend; + }; + + typedef detail::basic_managed_memory_impl + 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 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 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(segment_id) << std::ends; + //This functor will be executed when constructing + create_open_func func(this, type, segment_id); + const char *name = formatter.vector().c_str(); + //This can throw. + managed_impl mshm; + + switch(type){ + case create_open_func::DoCreate: + { + managed_impl shm(create_only, name, size, read_write, addr, func); + mshm = move(shm); + } + break; + + case create_open_func::DoOpen: + { + managed_impl shm(open_only, name,read_write, addr, func); + mshm = move(shm); + } + break; + + case create_open_func::DoOpenOrCreate: + { + managed_impl shm(open_or_create, name, size, read_write, addr, func); + mshm = move(shm); + } + break; + + default: + return false; + break; + } + + //This can throw. + m_shmem_list.push_back(move(mshm)); + return true; + } + BOOST_CATCH(const std::bad_alloc&){ + } + BOOST_CATCH_END + return false; + } + + //!Frees resources. Never throws. + void priv_close() + { + if(!m_shmem_list.empty()){ + bool ret; + //Obtain group identifier + segment_group_id group = m_group_services.get_group(); + //Erase main segment and its resources + shmem_list_t::iterator itbeg = m_shmem_list.begin(), + itend = m_shmem_list.end(), + it = itbeg; + //(*itbeg)->close_with_func(close_func(this)); + //Delete group. All mappings are erased too. + ret = void_pointer::delete_group(group); + assert(ret); + m_shmem_list.clear(); + } + } + + private: + shmem_list_t m_shmem_list; + group_services m_group_services; + std::string m_root_name; +}; + +typedef basic_managed_multi_shared_memory + < char + , rbtree_best_fit > + , iset_index> + managed_multi_shared_memory; + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_MANAGED_MULTI_SHARED_MEMORY_HPP + diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index 068223e..9ce306c 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace boost { @@ -36,7 +37,6 @@ template class managed_open_or_create_impl { //Non-copyable - managed_open_or_create_impl(); managed_open_or_create_impl(const managed_open_or_create_impl &); managed_open_or_create_impl &operator=(const managed_open_or_create_impl &); @@ -56,6 +56,9 @@ class managed_open_or_create_impl < sizeof(boost::uint32_t) , detail::alignment_of::value>::value; + managed_open_or_create_impl() + {} + managed_open_or_create_impl(create_only_t, const char *name, std::size_t size, @@ -151,27 +154,27 @@ class managed_open_or_create_impl , construct_func); } + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl - (detail::moved_object &moved) + managed_open_or_create_impl(detail::moved_object moved) { this->swap(moved.get()); } #else - managed_open_or_create_impl - (managed_open_or_create_impl &&moved) + managed_open_or_create_impl(managed_open_or_create_impl &&moved) { this->swap(moved); } #endif + //!Move assignment. If *this owns a memory mapped region, it will be + //!destroyed and it will take ownership of "other"'s memory mapped region. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl &operator= - (detail::moved_object &moved) + managed_open_or_create_impl &operator=(detail::moved_object 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 &operator=(managed_open_or_create_impl &&moved) { managed_open_or_create_impl tmp(move(moved)); this->swap(tmp); @@ -276,17 +279,31 @@ class managed_open_or_create_impl (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){ + 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(dev, m_name.c_str(), size, file_like_t()); created = true; @@ -379,7 +396,7 @@ class managed_open_or_create_impl } } - mapped_region region(dev, read_write, 0, 0, addr); + mapped_region region(dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, 0, addr); boost::uint32_t *patomic_word = static_cast(region.get_address()); boost::uint32_t value = detail::atomic_read32(patomic_word); @@ -392,7 +409,9 @@ class managed_open_or_create_impl if(value != InitializedSegment) throw interprocess_exception(error_info(corrupted_error)); - construct_func((char*)region.get_address() + ManagedOpenOrCreateUserOffset, region.get_size(), false); + construct_func( (char*)region.get_address() + ManagedOpenOrCreateUserOffset + , region.get_size() - ManagedOpenOrCreateUserOffset + , false); //All ok, just move resources to the external mapped region m_mapped_region.swap(region); } @@ -413,6 +432,21 @@ inline void swap(managed_open_or_create_impl &x { x.swap(y); } } //namespace detail { + + +///@cond + +//!Trait class to detect if a type is +//!movable +template + +struct is_movable > +{ + enum { value = true }; +}; + +///@endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 362b1cd..3dba900 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -80,6 +80,26 @@ inline Integer upper_power_of_2(const Integer & A) return power_of_2; } +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(Size_t_Bits_Power_2); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + } // namespace detail } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/detail/multi_segment_services.hpp b/include/boost/interprocess/detail/multi_segment_services.hpp new file mode 100644 index 0000000..ac50b33 --- /dev/null +++ b/include/boost/interprocess/detail/multi_segment_services.hpp @@ -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 +#include + + +/*!\file + Describes a named shared memory allocation user class. +*/ + +namespace boost { + +namespace interprocess { + +class multi_segment_services +{ + public: + virtual std::pair create_new_segment(std::size_t mem) = 0; + virtual bool update_segments () = 0; + virtual ~multi_segment_services() = 0; +}; + +inline multi_segment_services::~multi_segment_services() +{} + + +}} //namespace boost { namespace interprocess { + +#include + +#endif //#ifdef BOOST_INTERPROCESS_MULTI_SEGMENT_SERVICES_HPP diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 58bbb56..08a6e79 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -215,24 +215,6 @@ inline void array_construct(void *mem, std::size_t num, detail::in_place_interfa BOOST_CATCH_END } -//Anti-exception node eraser -template -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 struct intrusive_compare_key { diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index a72e738..d188e9a 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -767,6 +767,24 @@ addressof(T& v) &const_cast(reinterpret_cast(v))); } +//Anti-exception node eraser +template +class value_eraser +{ + public: + value_eraser(Cont & cont, typename Cont::iterator it) + : m_cont(cont), m_index_it(it), m_erase(true){} + ~value_eraser() + { if(m_erase) m_cont.erase(m_index_it); } + + void release() { m_erase = false; } + + private: + Cont &m_cont; + typename Cont::iterator m_index_it; + bool m_erase; +}; + } //namespace interprocess { } //namespace boost { From 62fedf648f95b46ba156dacc3dd5470fc0efa627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 23 May 2008 23:20:33 +0000 Subject: [PATCH 30/77] #1912: some copy edits on boost.intrusive #1932: move semantics for shared objects #1635: Incomplete include guard in boost/intrusive [SVN r45705] --- .../mem_algo/detail/mem_algo_common.hpp | 8 +- .../mem_algo/detail/multi_simple_seq_fit.hpp | 61 ++ .../detail/multi_simple_seq_fit_impl.hpp | 973 ++++++++++++++++++ 3 files changed, 1038 insertions(+), 4 deletions(-) create mode 100644 include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp create mode 100644 include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index bc8b68d..bd6b89b 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -406,13 +406,13 @@ class memory_algorithm_common if(nbytes > UsableByPreviousChunk) nbytes -= UsableByPreviousChunk; - //We can find a aligned portion if we allocate a chunk that has alignment + //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 chunk, we must request a bit more memory + //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 chunk before the alignment. + //there is no space for a new block before the alignment. // // ____ Aligned here // | @@ -487,7 +487,7 @@ class memory_algorithm_common // | MBU +more | ACB | (3) | BCU | // ----------------------------------------------------- //This size will be the minimum size to be able to create a - //new chunk in the end. + //new block in the end. const std::size_t second_min_units = max_value(std::size_t(MinBlockUnits), ceil_units(nbytes) + AllocatedCtrlUnits ); diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp new file mode 100644 index 0000000..4f5751a --- /dev/null +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit.hpp @@ -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 +#include + +#include +#include +#include + +/*!\file + Describes sequential fit algorithm used to allocate objects in shared memory. +*/ + +namespace boost { + +namespace interprocess { + +/*!This class implements the simple sequential fit algorithm with a simply + linked list of free buffers.*/ +template +class multi_simple_seq_fit + : public detail::simple_seq_fit_impl +{ + typedef detail::simple_seq_fit_impl base_t; + public: + /*!Constructor. "size" is the total size of the 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 + +#endif //#ifndef BOOST_INTERPROCESS_MULTI_SIMPLE_SEQ_FIT_HPP + diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp new file mode 100644 index 0000000..2393d1e --- /dev/null +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp @@ -0,0 +1,973 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*!\file + Describes sequential fit algorithm used to allocate objects in shared memory. + This class is intended as a base class for single segment and multi-segment + implementations. +*/ + +namespace boost { + +namespace interprocess { + +namespace detail { + +/*!This class implements the simple sequential fit algorithm with a simply + linked list of free buffers. + This class is intended as a base class for single segment and multi-segment + implementations.*/ +template +class simple_seq_fit_impl +{ + //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::type block_ctrl_ptr; + + /*!Block control structure*/ + struct block_ctrl + { + /*!Offset pointer to the next block.*/ + block_ctrl_ptr m_next; + /*!This block's memory size (including block_ctrl + header) in BasicSize units*/ + std::size_t m_size; + + std::size_t get_user_bytes() const + { return this->m_size*Alignment - BlockCtrlBytes; } + + std::size_t get_total_bytes() const + { return this->m_size*Alignment; } + + static block_ctrl *get_block_from_addr(void *addr) + { + return reinterpret_cast + (detail::char_ptr_cast(addr) - BlockCtrlBytes); + } + + void *get_addr() const + { + return reinterpret_cast + (detail::char_ptr_cast(this) + BlockCtrlBytes); + } + + }; + + /*!Shared interprocess_mutex to protect memory allocate/deallocate*/ + typedef typename MutexFamily::mutex_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 + 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 indicating the base address and size of + the new segment. If the new segment can't be allocated, allocate + it will return 0.*/ + void* multi_allocate(std::size_t nbytes); + + private: + /*!Real allocation algorithm with min allocation option*/ + std::pair priv_allocate(allocation_type command + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr = 0); + /*!Returns next block if it's free. + Returns 0 if next block is not free.*/ + block_ctrl *priv_next_block_if_free(block_ctrl *ptr); + + /*!Returns previous block's if it's free. + Returns 0 if previous block is not free.*/ + std::pairpriv_prev_block_if_free(block_ctrl *ptr); + + /*!Real expand function implementation*/ + bool priv_expand(void *ptr + ,std::size_t min_size, std::size_t preferred_size + ,std::size_t &received_size); + + /*!Real expand to both sides implementation*/ + void* priv_expand_both_sides(allocation_type command + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr + ,bool only_preferred_backwards); + + /*!Real shrink function implementation*/ + bool priv_shrink(void *ptr + ,std::size_t max_size, std::size_t preferred_size + ,std::size_t &received_size); + + //!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::value }; + enum { BlockCtrlBytes = detail::ct_rounded_size::value }; + enum { BlockCtrlSize = BlockCtrlBytes/Alignment }; + enum { MinBlockSize = BlockCtrlSize + Alignment }; + + public: + enum { PayloadPerAllocation = BlockCtrlBytes }; +}; + +template +inline simple_seq_fit_impl:: + simple_seq_fit_impl(std::size_t size, std::size_t extra_hdr_bytes) +{ + //Initialize sizes and counters + m_header.m_allocated = 0; + m_header.m_size = size; + + //Initialize pointers + std::size_t block1_off = detail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment); + m_header.m_root.m_next = reinterpret_cast + (detail::char_ptr_cast(this) + block1_off); + m_header.m_root.m_next->m_size = (size - block1_off)/Alignment; + m_header.m_root.m_next->m_next = &m_header.m_root; +} + +template +inline simple_seq_fit_impl::~simple_seq_fit_impl() +{ + //There is a memory leak! +// assert(m_header.m_allocated == 0); +// assert(m_header.m_root.m_next->m_next == block_ctrl_ptr(&m_header.m_root)); +} + +template +inline void simple_seq_fit_impl::grow(std::size_t extra_size) +{ + //Old highest address block's end offset + std::size_t old_end = m_header.m_size/Alignment*Alignment; + + //Update managed buffer's size + m_header.m_size += extra_size; + + //We need at least MinBlockSize blocks to create a new block + if((m_header.m_size - old_end) < MinBlockSize){ + return; + } + + //We'll create a new free block with extra_size bytes + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(this) + old_end); + + new_block->m_next = 0; + new_block->m_size = (m_header.m_size - old_end)/Alignment; + m_header.m_allocated += new_block->m_size*Alignment; + this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes); +} + +template +inline void simple_seq_fit_impl::priv_add_segment(void *addr, std::size_t size) +{ + //Check size + assert(!(size < MinBlockSize)); + if(size < MinBlockSize) + return; + //Construct big block using the new segment + block_ctrl *new_block = static_cast(addr); + new_block->m_size = size/Alignment; + new_block->m_next = 0; + //Simulate this block was previously allocated + m_header.m_allocated += new_block->m_size*Alignment; + //Return block and insert it in the free block list + this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes); +} + +template +inline std::size_t simple_seq_fit_impl::get_size() const + { return m_header.m_size; } + +template +inline std::size_t simple_seq_fit_impl:: + get_min_size (std::size_t extra_hdr_bytes) +{ + return detail::get_rounded_size(sizeof(simple_seq_fit_impl)+extra_hdr_bytes + ,Alignment) + + MinBlockSize; +} + +template +inline bool simple_seq_fit_impl:: + all_memory_deallocated() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return m_header.m_allocated == 0 && + detail::get_pointer(m_header.m_root.m_next->m_next) == &m_header.m_root; +} + +template +inline void simple_seq_fit_impl::clear_free_memory() +{ + //----------------------- + boost::interprocess::scoped_lock 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( detail::char_ptr_cast(block) + BlockCtrlBytes + , 0 + , block->m_size*Alignment - BlockCtrlBytes); + block = detail::get_pointer(block->m_next); + } + while(block != &m_header.m_root); +} + +template +inline bool simple_seq_fit_impl:: + check_sanity() +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + block_ctrl *block = detail::get_pointer(m_header.m_root.m_next); + + std::size_t free_memory = 0; + + //Iterate through all blocks obtaining their size + do{ + //Free blocks's next must be always valid + block_ctrl *next = detail::get_pointer(block->m_next); + if(!next){ + return false; + } + free_memory += block->m_size*Alignment; + block = next; + } + while(block != &m_header.m_root); + + //Check allocated bytes are less than size + if(m_header.m_allocated > m_header.m_size){ + return false; + } + + //Check free bytes are less than size + if(free_memory > m_header.m_size){ + return false; + } + return true; +} + +template +inline void* simple_seq_fit_impl:: + allocate(std::size_t nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + std::size_t ignore; + return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; +} + +template +inline void* simple_seq_fit_impl:: + allocate_aligned(std::size_t nbytes, std::size_t alignment) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return priv_allocate_aligned(nbytes, alignment); +} + +template +inline std::pair simple_seq_fit_impl:: + allocation_command (allocation_type command, std::size_t min_size, + std::size_t preferred_size,std::size_t &received_size, + void *reuse_ptr, std::size_t backwards_multiple) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + (void)backwards_multiple; + command &= ~expand_bwd; + if(!command) + return std::pair(0, false); + return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr); +} + +template +inline std::size_t simple_seq_fit_impl:: + size(void *ptr) const +{ + //We need no synchronization since this block is not going + //to be modified + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + return block->m_size*Alignment - BlockCtrlBytes; +} + +template +inline void* simple_seq_fit_impl:: + multi_allocate(std::size_t nbytes) +{ + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + //Multisegment pointer. Let's try first the normal allocation + //since it's faster. + std::size_t ignore; + void *addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + if(!addr){ + //If this fails we will try the allocation through the segment + //creator. + std::size_t group, id; + //Obtain the segment group of this segment + void_pointer::get_group_and_id(this, group, id); + if(group == 0){ + //Ooops, group 0 is not valid. + return 0; + } + //Now obtain the polymorphic functor that creates + //new segments and try to allocate again. + boost::interprocess::multi_segment_services *p_services = + static_cast + (void_pointer::find_group_data(group)); + assert(p_services); + std::pair ret = + p_services->create_new_segment(MinBlockSize > nbytes ? MinBlockSize : nbytes); + if(ret.first){ + priv_add_segment(ret.first, ret.second); + addr = this->priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + } + } + return addr; +} + +template +void* simple_seq_fit_impl:: + priv_expand_both_sides(allocation_type command + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr + ,bool only_preferred_backwards) +{ + typedef std::pair prev_block_t; + block_ctrl *reuse = block_ctrl::get_block_from_addr(reuse_ptr); + received_size = 0; + + if(this->size(reuse_ptr) > min_size){ + received_size = this->size(reuse_ptr); + return reuse_ptr; + } + + if(command & expand_fwd){ + if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) + return reuse_ptr; + } + else{ + received_size = this->size(reuse_ptr); + } + if(command & expand_bwd){ + std::size_t extra_forward = !received_size ? 0 : received_size + BlockCtrlBytes; + prev_block_t prev_pair = priv_prev_block_if_free(reuse); + block_ctrl *prev = prev_pair.second; + if(!prev){ + return 0; + } + + std::size_t needs_backwards = + detail::get_rounded_size(preferred_size - extra_forward, Alignment); + + if(!only_preferred_backwards){ + needs_backwards = + max_value(detail::get_rounded_size(min_size - extra_forward, Alignment) + ,min_value(prev->get_user_bytes(), needs_backwards)); + } + + //Check if previous block has enough size + if((prev->get_user_bytes()) >= needs_backwards){ + //Now take all next space. This will succeed + if(!priv_expand(reuse_ptr, received_size, received_size, received_size)){ + assert(0); + } + + //We need a minimum size to split the previous one + if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){ + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(reuse) - needs_backwards - BlockCtrlBytes); + new_block->m_next = 0; + new_block->m_size = + BlockCtrlSize + (needs_backwards + extra_forward)/Alignment; + prev->m_size = + (prev->get_total_bytes() - needs_backwards)/Alignment - BlockCtrlSize; + received_size = needs_backwards + extra_forward; + m_header.m_allocated += needs_backwards + BlockCtrlBytes; + return new_block->get_addr(); + } + else{ + //Just merge the whole previous block + block_ctrl *prev_2_block = prev_pair.first; + //Update received size and allocation + received_size = extra_forward + prev->get_user_bytes(); + m_header.m_allocated += prev->get_total_bytes(); + //Now unlink it from previous block + prev_2_block->m_next = prev->m_next; + prev->m_size = reuse->m_size + prev->m_size; + prev->m_next = 0; + return prev->get_addr(); + } + } + } + return 0; +} + +template +std::pair simple_seq_fit_impl:: + priv_allocate(allocation_type command + ,std::size_t limit_size + ,std::size_t preferred_size + ,std::size_t &received_size + ,void *reuse_ptr) +{ + if(command & shrink_in_place){ + bool success = + this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size); + return std::pair ((success ? reuse_ptr : 0), true); + } + typedef std::pair return_type; + received_size = 0; + + if(limit_size > preferred_size) + return return_type(0, false); + + //Number of units to request (including block_ctrl header) + std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlSize; + + //Get the root and the first memory block + block_ctrl *prev = &m_header.m_root; + block_ctrl *block = detail::get_pointer(prev->m_next); + block_ctrl *root = &m_header.m_root; + block_ctrl *biggest_block = 0; + block_ctrl *prev_biggest_block = 0; + std::size_t biggest_size = limit_size; + + //Expand in place + //reuse_ptr, limit_size, preferred_size, received_size + // + if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + void *ret = priv_expand_both_sides + (command, limit_size, preferred_size, received_size, reuse_ptr, true); + if(ret) + return return_type(ret, true); + } + + if(command & allocate_new){ + received_size = 0; + while(block != root){ + //Update biggest block pointers + if(block->m_size > biggest_size){ + prev_biggest_block = prev; + biggest_size = block->m_size; + biggest_block = block; + } + void *addr = this->priv_check_and_allocate(nunits, prev, block, received_size); + if(addr) return return_type(addr, false); + //Bad luck, let's check next block + prev = block; + block = detail::get_pointer(block->m_next); + } + + //Bad luck finding preferred_size, now if we have any biggest_block + //try with this block + if(biggest_block){ + received_size = biggest_block->m_size*Alignment - BlockCtrlSize; + nunits = detail::get_rounded_size(limit_size, Alignment)/Alignment + BlockCtrlSize; + void *ret = this->priv_check_and_allocate + (nunits, prev_biggest_block, biggest_block, received_size); + if(ret) + return return_type(ret, false); + } + } + //Now try to expand both sides with min size + if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + return return_type(priv_expand_both_sides + (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); + } + return return_type(0, false); +} + +template +inline typename simple_seq_fit_impl::block_ctrl * + simple_seq_fit_impl:: + priv_next_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + //Take the address where the next block should go + block_ctrl *next_block = reinterpret_cast + (detail::char_ptr_cast(ptr) + ptr->m_size*Alignment); + + //Check if the adjacent block is in the managed segment + std::size_t distance = (detail::char_ptr_cast(next_block) - detail::char_ptr_cast(this))/Alignment; + if(distance >= (m_header.m_size/Alignment)){ + //"next_block" does not exist so we can't expand "block" + return 0; + } + + if(!next_block->m_next) + return 0; + + return next_block; +} + +template +inline + std::pair::block_ctrl * + ,typename simple_seq_fit_impl::block_ctrl *> + simple_seq_fit_impl:: + priv_prev_block_if_free + (typename simple_seq_fit_impl::block_ctrl *ptr) +{ + typedef std::pair prev_pair_t; + //Take the address where the previous block should go + block_ctrl *root = &m_header.m_root; + block_ctrl *prev_2_block = root; + block_ctrl *prev_block = detail::get_pointer(root->m_next); + while((detail::char_ptr_cast(prev_block) + prev_block->m_size*Alignment) + != (detail::char_ptr_cast(ptr)) + && prev_block != root){ + prev_2_block = prev_block; + prev_block = detail::get_pointer(prev_block->m_next); + } + + if(prev_block == root || !prev_block->m_next) + return prev_pair_t(0, 0); + + //Check if the previous block is in the managed segment + std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment; + if(distance >= (m_header.m_size/Alignment)){ + //"previous_block" does not exist so we can't expand "block" + return prev_pair_t(0, 0); + } + return prev_pair_t(prev_2_block, prev_block); +} + + +template +inline bool simple_seq_fit_impl:: + priv_expand (void *ptr + ,std::size_t min_size + ,std::size_t preferred_size + ,std::size_t &received_size) +{ + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + std::size_t old_block_size = block->m_size; + + //All used blocks' next is marked with 0 so check it + assert(block->m_next == 0); + + //Put this to a safe value + received_size = old_block_size*Alignment - BlockCtrlBytes; + + //Now translate it to Alignment units + min_size = detail::get_rounded_size(min_size, Alignment)/Alignment; + preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment; + + //Some parameter checks + if(min_size > preferred_size) + return false; + + std::size_t data_size = old_block_size - BlockCtrlSize; + + if(data_size >= min_size) + return true; + + block_ctrl *next_block = priv_next_block_if_free(block); + if(!next_block){ + return false; + } + + //Is "block" + "next_block" big enough? + std::size_t merged_size = old_block_size + next_block->m_size; + + //Now we can expand this block further than before + received_size = merged_size*Alignment - BlockCtrlBytes; + + if(merged_size < (min_size + BlockCtrlSize)){ + return false; + } + + //We can fill expand. Merge both blocks, + block->m_next = next_block->m_next; + block->m_size = merged_size; + + //Find the previous free block of next_block + block_ctrl *prev = &m_header.m_root; + while(detail::get_pointer(prev->m_next) != next_block){ + prev = detail::get_pointer(prev->m_next); + } + + //Now insert merged block in the free list + //This allows reusing allocation logic in this function + m_header.m_allocated -= old_block_size*Alignment; + prev->m_next = block; + + //Now use check and allocate to do the allocation logic + preferred_size += BlockCtrlSize; + std::size_t nunits = preferred_size < merged_size ? preferred_size : merged_size; + + //This must success since nunits is less than merged_size! + if(!this->priv_check_and_allocate (nunits, prev, block, received_size)){ + //Something very ugly is happening here. This is a bug + //or there is memory corruption + assert(0); + return false; + } + return true; +} + +template +inline bool simple_seq_fit_impl:: + priv_shrink (void *ptr + ,std::size_t max_size + ,std::size_t preferred_size + ,std::size_t &received_size) +{ + //Obtain the real size of the block + block_ctrl *block = reinterpret_cast + (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + std::size_t block_size = block->m_size; + + //All used blocks' next is marked with 0 so check it + assert(block->m_next == 0); + + //Put this to a safe value + received_size = block_size*Alignment - BlockCtrlBytes; + + //Now translate it to Alignment units + max_size = max_size/Alignment; + preferred_size = detail::get_rounded_size(preferred_size, Alignment)/Alignment; + + //Some parameter checks + if(max_size < preferred_size) + return false; + + std::size_t data_size = block_size - BlockCtrlSize; + + if(data_size < preferred_size) + return false; + + if(data_size == preferred_size) + return true; + + //We must be able to create at least a new empty block + if((data_size - preferred_size) < BlockCtrlSize){ + return false; + } + + //Now we can just rewrite the size of the old buffer + block->m_size = preferred_size + BlockCtrlSize; + + //Update new size + received_size = preferred_size*Alignment; + + //We create the new block + block = reinterpret_cast + (detail::char_ptr_cast(block) + block->m_size*Alignment); + + //Write control data to simulate this new block was previously allocated + block->m_next = 0; + block->m_size = data_size - preferred_size; + + //Now deallocate the new block to insert it in the free list + this->priv_deallocate(detail::char_ptr_cast(block)+BlockCtrlBytes); + return true; +} + +template +inline void* simple_seq_fit_impl:: + priv_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 = (char*) + ((std::size_t)((char*)buffer + alignment - 1) & -alignment); + + char *pos = ((aligned_portion - (char*)buffer) >= (MinBlockSize*Alignment)) ? + aligned_portion : (aligned_portion + alignment); + + + block_ctrl *first = reinterpret_cast + (detail::char_ptr_cast(buffer) - BlockCtrlBytes); + + block_ctrl *second = reinterpret_cast + (detail::char_ptr_cast(pos) - BlockCtrlBytes); + + std::size_t old_size = first->m_size; + + first->m_size = ((char*)second - (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(detail::char_ptr_cast(first) + BlockCtrlBytes); + return detail::char_ptr_cast(second) + BlockCtrlBytes; +} + +template inline +void* simple_seq_fit_impl::priv_check_and_allocate + (std::size_t nunits + ,typename simple_seq_fit_impl::block_ctrl* prev + ,typename simple_seq_fit_impl::block_ctrl* block + ,std::size_t &received_size) +{ + std::size_t upper_nunits = nunits + BlockCtrlSize; + bool found = false; + + if (block->m_size > upper_nunits){ + //This block is bigger than needed, split it in + //two blocks, the first's size will be (block->m_size-units) + //the second's size (units) + std::size_t total_size = block->m_size; + block->m_size = nunits; + block_ctrl *new_block = reinterpret_cast + (detail::char_ptr_cast(block) + Alignment*nunits); + new_block->m_size = total_size - nunits; + new_block->m_next = block->m_next; + prev->m_next = new_block; + found = true; + } + else if (block->m_size >= nunits){ + //This block has exactly the right size with an extra + //unusable extra bytes. + prev->m_next = block->m_next; + found = true; + } + + if(found){ + //We need block_ctrl for deallocation stuff, so + //return memory user can overwrite + m_header.m_allocated += block->m_size*Alignment; + received_size = block->m_size*Alignment - BlockCtrlBytes; + //Mark the block as allocated + block->m_next = 0; + //Check alignment + assert(((detail::char_ptr_cast(block) - detail::char_ptr_cast(this)) + % Alignment) == 0 ); + return detail::char_ptr_cast(block)+BlockCtrlBytes; + } + return 0; +} + +template +void simple_seq_fit_impl::deallocate(void* addr) +{ + if(!addr) return; + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return this->priv_deallocate(addr); +} + +template +void simple_seq_fit_impl::priv_deallocate(void* addr) +{ + if(!addr) return; + + //Let's get free block list. List is always sorted + //by memory address to allow block merging. + //Pointer next always points to the first + //(lower address) block + block_ctrl_ptr prev = &m_header.m_root; + block_ctrl_ptr pos = m_header.m_root.m_next; + block_ctrl_ptr block = reinterpret_cast + (detail::char_ptr_cast(addr) - BlockCtrlBytes); + + //All used blocks' next is marked with 0 so check it + assert(block->m_next == 0); + + //Check if alignment and block size are right + assert((detail::char_ptr_cast(addr) - detail::char_ptr_cast(this)) + % Alignment == 0 ); + + std::size_t total_size = Alignment*block->m_size; + assert(m_header.m_allocated >= total_size); + + //Update used memory count + m_header.m_allocated -= total_size; + + //Let's find the previous and the next block of the block to deallocate + //This ordering comparison must be done with original pointers + //types since their mapping to raw pointers can be different + //in each process + while((detail::get_pointer(pos) != &m_header.m_root) && (block > pos)){ + prev = pos; + pos = pos->m_next; + } + + //Try to combine with upper block + if ((detail::char_ptr_cast(detail::get_pointer(block)) + + Alignment*block->m_size) == + detail::char_ptr_cast(detail::get_pointer(pos))){ + + block->m_size += pos->m_size; + block->m_next = pos->m_next; + } + else{ + block->m_next = pos; + } + + //Try to combine with lower block + if ((detail::char_ptr_cast(detail::get_pointer(prev)) + + Alignment*prev->m_size) == + detail::char_ptr_cast(detail::get_pointer(block))){ + prev->m_size += block->m_size; + prev->m_next = block->m_next; + } + else{ + prev->m_next = block; + } +} + +} //namespace detail { + +} //namespace interprocess { + +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MEM_ALGO_DETAIL_SIMPLE_SEQ_FIT_IMPL_HPP + From 00653b57fcf070058d48e7e4269cfd0148040509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 27 May 2008 16:39:25 +0000 Subject: [PATCH 31/77] Ticket #1951 [SVN r45814] --- .../interprocess/sync/named_condition.hpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index c1d3c31..f511554 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -146,23 +146,30 @@ class named_condition template void do_wait(Lock& lock) { - lock_inverter inverted_lock(lock); - //unlock internal first to avoid deadlock with near simultaneous waits - scoped_lock > external_unlock(inverted_lock); + //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex()); - this->condition()->wait(internal_lock); + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + + //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock internal_unlock; + internal_lock.swap(internal_unlock); + this->condition()->wait(internal_unlock); } template bool do_timed_wait(Lock& lock, const boost::posix_time::ptime &abs_time) { - //unlock internal first to avoid deadlock with near simultaneous waits - lock_inverter inverted_lock(lock); - scoped_lock > external_unlock(inverted_lock); + //lock internal before unlocking external to avoid race with a notifier + scoped_lock internal_lock(*this->mutex(), abs_time); if(!external_unlock) return false; - scoped_lock internal_lock(*this->mutex(), abs_time); - if(!internal_lock) return false; - return this->condition()->timed_wait(internal_lock, abs_time); + lock_inverter inverted_lock(lock); + scoped_lock > external_unlock(inverted_lock); + + //unlock internal first to avoid deadlock with near simultaneous waits + scoped_lock internal_unlock; + internal_lock.swap(internal_unlock); + return this->condition()->timed_wait(internal_unlock, abs_time); } #endif From 26c92da8dca1ce12df9d0f3cf7994290a736f1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 27 May 2008 17:05:22 +0000 Subject: [PATCH 32/77] Ticket #1921: interprocess shared_memory example needs patch (provided) [SVN r45816] --- example/doc_file_mapping.cpp | 1 - example/doc_message_queueA.cpp | 2 -- example/doc_shared_memory.cpp | 1 - example/doc_shared_memory2.cpp | 3 ++- include/boost/interprocess/detail/math_functions.hpp | 2 ++ 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/example/doc_file_mapping.cpp b/example/doc_file_mapping.cpp index 24d20ac..568f577 100644 --- a/example/doc_file_mapping.cpp +++ b/example/doc_file_mapping.cpp @@ -56,7 +56,6 @@ int main () std::cout << ex.what() << std::endl; return 1; } - std::remove("file.bin"); return 0; } //] diff --git a/example/doc_message_queueA.cpp b/example/doc_message_queueA.cpp index 784ff24..04c1838 100644 --- a/example/doc_message_queueA.cpp +++ b/example/doc_message_queueA.cpp @@ -35,11 +35,9 @@ int main () } } catch(interprocess_exception &ex){ - message_queue::remove("message_queue"); std::cout << ex.what() << std::endl; return 1; } - message_queue::remove("message_queue"); return 0; } diff --git a/example/doc_shared_memory.cpp b/example/doc_shared_memory.cpp index 4764c9f..3b5b7bc 100644 --- a/example/doc_shared_memory.cpp +++ b/example/doc_shared_memory.cpp @@ -38,7 +38,6 @@ int main () std::cout << ex.what() << std::endl; return 1; } - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_shared_memory2.cpp b/example/doc_shared_memory2.cpp index a8999bb..ad7b8ec 100644 --- a/example/doc_shared_memory2.cpp +++ b/example/doc_shared_memory2.cpp @@ -33,12 +33,13 @@ int main () } } std::cout << "Test successful!" << std::endl; + shared_memory_object::remove("shared_memory"); } catch(interprocess_exception &ex){ std::cout << "Unexpected exception: " << ex.what() << std::endl; + shared_memory_object::remove("shared_memory"); return 1; } - return 0; } //] diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 3dba900..8b80aa2 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -16,6 +16,8 @@ #ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP #define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP +#include + namespace boost { namespace interprocess { namespace detail { From 10f13ce7c74691036c000c6eb2af563e4c2ca8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 28 May 2008 16:08:31 +0000 Subject: [PATCH 33/77] Ticket #1960: detail/math_functions.hpp misses #include [SVN r45872] --- include/boost/interprocess/detail/math_functions.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 8b80aa2..9aaf686 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -17,6 +17,7 @@ #define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP #include +#include namespace boost { namespace interprocess { From a9310b2c7504c28c5585e43ae2271d91ef0d5744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 15 Jun 2008 18:47:11 +0000 Subject: [PATCH 34/77] Solved 'external_unlock' was not declared in this scope for gcc [SVN r46412] --- include/boost/interprocess/sync/named_condition.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index f511554..acdb6c2 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -162,7 +162,7 @@ class named_condition { //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex(), abs_time); - if(!external_unlock) return false; + if(!internal_lock) return false; lock_inverter inverted_lock(lock); scoped_lock > external_unlock(inverted_lock); From f8d2eae08c05306be7c0877a63d91964a10ed0b6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 17 Jun 2008 13:54:46 +0000 Subject: [PATCH 35/77] Add mime-type and eol-style properties as needed [SVN r46445] --- proj/conceptgcc/MakeAll | 70 +- proj/cygwin/MakeAll | 66 +- proj/linux/MakeAll | 64 +- proj/mingw/MakeAll | 70 +- proj/qnx/MakeAll | 66 +- proj/vc7ide/Interprocess.sln | 1838 +++++++++++++++++----------------- 6 files changed, 1087 insertions(+), 1087 deletions(-) diff --git a/proj/conceptgcc/MakeAll b/proj/conceptgcc/MakeAll index c941303..1770e5e 100644 --- a/proj/conceptgcc/MakeAll +++ b/proj/conceptgcc/MakeAll @@ -1,35 +1,35 @@ - -#ifndef CC -CC=i686-pc-cygwin-conceptg++.exe -#endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/conceptgcc/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSDOC_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSDOC_OUT := $(patsubst ../../example/%.cpp, ../../bin/conceptgcc/ex_%.out, $(INTERPROCESSDOC_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSDOC_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/conceptgcc - -../../bin/conceptgcc/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -../../bin/conceptgcc/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -clean: - rm -f *.o - rm -f ../../bin/conceptgcc/* + +#ifndef CC +CC=i686-pc-cygwin-conceptg++.exe +#endif + +BOOST_ROOT=../../../.. + +INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) +INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/conceptgcc/test_%.out, $(INTERPROCESSTEST_CPP)) + +INTERPROCESSDOC_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSDOC_OUT := $(patsubst ../../example/%.cpp, ../../bin/conceptgcc/ex_%.out, $(INTERPROCESSDOC_CPP)) + +LIBDIR:= ../../../../stage/lib + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSDOC_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/conceptgcc + +../../bin/conceptgcc/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +../../bin/conceptgcc/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +clean: + rm -f *.o + rm -f ../../bin/conceptgcc/* diff --git a/proj/cygwin/MakeAll b/proj/cygwin/MakeAll index 4073873..72e7b80 100644 --- a/proj/cygwin/MakeAll +++ b/proj/cygwin/MakeAll @@ -1,33 +1,33 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/cygwin/test_%.out, $(INTERPROCESSTEST_CPP)) - -#INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -#INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/cygwin/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSEXAMPLE_OUT) $(INTERPROCESSTEST_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/cygwin - -../../bin/cygwin/test_%.out: ../../test/%.cpp - $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -#../../bin/cygwin/ex_%.out: ../../example/%.cpp -# $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - - -clean: - rm -f *.o - rm -f ../../bin/cygwin/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/cygwin/test_%.out, $(INTERPROCESSTEST_CPP)) + +#INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +#INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/cygwin/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +LIBDIR:= ../../../../stage/lib + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSEXAMPLE_OUT) $(INTERPROCESSTEST_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/cygwin + +../../bin/cygwin/test_%.out: ../../test/%.cpp + $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +#../../bin/cygwin/ex_%.out: ../../example/%.cpp +# $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + + +clean: + rm -f *.o + rm -f ../../bin/cygwin/* diff --git a/proj/linux/MakeAll b/proj/linux/MakeAll index f0c361b..9f0962f 100644 --- a/proj/linux/MakeAll +++ b/proj/linux/MakeAll @@ -1,32 +1,32 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. -BOOST_LIBS=/usr/local/lib - - -INTERPROCESS_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESS_OUT := $(patsubst ../../test/%.cpp, ../../bin/linux/test_%.out, $(INTERPROCESS_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/linux/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -.PHONY: createdir clean - -all: createdir $(INTERPROCESS_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/linux - -../../bin/linux/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ - -../../bin/linux/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ - -clean: - rm -f *.o - rm -f ../../bin/linux/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. +BOOST_LIBS=/usr/local/lib + + +INTERPROCESS_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESS_OUT := $(patsubst ../../test/%.cpp, ../../bin/linux/test_%.out, $(INTERPROCESS_CPP)) + +INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/linux/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +.PHONY: createdir clean + +all: createdir $(INTERPROCESS_OUT) $(INTERPROCESSEXAMPLE_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/linux + +../../bin/linux/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ + +../../bin/linux/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ + +clean: + rm -f *.o + rm -f ../../bin/linux/* diff --git a/proj/mingw/MakeAll b/proj/mingw/MakeAll index 1903c1b..0b23825 100644 --- a/proj/mingw/MakeAll +++ b/proj/mingw/MakeAll @@ -1,35 +1,35 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/mingw/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/mingw/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/mingw - -../../bin/mingw/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -../../bin/mingw/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -clean: - rm -f *.o - rm -f ../../bin/mingw/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. + +INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) +INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/mingw/test_%.out, $(INTERPROCESSTEST_CPP)) + +INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/mingw/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +LIBDIR:= ../../../../stage/lib + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/mingw + +../../bin/mingw/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +../../bin/mingw/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ + +clean: + rm -f *.o + rm -f ../../bin/mingw/* diff --git a/proj/qnx/MakeAll b/proj/qnx/MakeAll index d941efd..b98dc49 100644 --- a/proj/qnx/MakeAll +++ b/proj/qnx/MakeAll @@ -1,33 +1,33 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/qnx/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/qnx/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/qnx - -../../bin/qnx/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ - -../../bin/qnx/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ - -clean: - rm -f *.o - rm -f ../../bin/qnx/* + +ifndef CC +CC=g++ +endif + +BOOST_ROOT=../../../.. + +INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) +INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) + +INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) +INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/qnx/test_%.out, $(INTERPROCESSTEST_CPP)) + +INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) +INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/qnx/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) + +.PHONY: createdir clean + +all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) + @cd . + +createdir: + @mkdir -p ../../bin/qnx + +../../bin/qnx/test_%.out: ../../test/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ + +../../bin/qnx/ex_%.out: ../../example/%.cpp + $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ + +clean: + rm -f *.o + rm -f ../../bin/qnx/* diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index e1a02a9..1539527 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -1,919 +1,919 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_mapping_test", "shared_memory_mappable_test.vcproj", "{5CE18C83-6025-36FE-A4F7-BA09176D3A11}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_test", "shared_memory_test.vcproj", "{5E2838CC-0916-8F4E-A4F7-93506BA0D310}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_ptr_test", "shared_ptr_test.vcproj", "{5371C383-6092-1238-A877-BAEB37867609}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_test", "string_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D4A792607}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upgradable_mutex_test", "upgradable_mutex.vcproj", "{4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_buffer_test", "user_buffer_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792603}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vectorstream_test", "vectorstream_test.vcproj", "{58CCE183-6032-12FE-A4F7-BA893A767601}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_test", "vector_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_condition_test", "named_condition_test.vcproj", "{58CC2563-6092-48FE-FAF7-BA046A792658}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexA", "doc_anonymous_mutexA.vcproj", "{58C1B183-9026-4E63-12F2-005412200054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexB", "doc_anonymous_mutexB.vcproj", "{58C1B183-9026-4E63-12F2-005202441254}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_mutex", "doc_named_mutex.vcproj", "{58C181B3-9516-463E-2F12-122155400054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionA", "doc_anonymous_conditionA.vcproj", "{5C1B8183-0296-4F83-1F22-001005220544}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionB", "doc_anonymous_conditionB.vcproj", "{58C1FE83-2906-E643-2F12-024410052254}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionA", "doc_named_conditionA.vcproj", "{58EB1CB3-1354-364E-12F2-154356612054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionB", "doc_named_conditionB.vcproj", "{58181CB3-5134-634E-12F2-155435622054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreA", "doc_anonymous_semaphoreA.vcproj", "{5CB81183-29FB-F843-24FF-022050100544}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreB", "doc_anonymous_semaphoreB.vcproj", "{58FBE8C3-9026-FAB2-E643-000522441254}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_upgradable_mutex_test", "named_upgradable_mutex.vcproj", "{48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexA", "doc_anonymous_upgradable_mutexA.vcproj", "{5C18831B-F162-FA96-E6C3-FA5122040054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexB", "doc_anonymous_upgradable_mutexB.vcproj", "{5C1B1043-1EFF-2793-4E63-245241283054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueA", "doc_message_queueA.vcproj", "{51B189C3-4E63-9026-12F2-12200AF54054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueB", "doc_message_queueB.vcproj", "{5C1B1813-12C2-0296-4E63-244549126520}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cont", "doc_cont.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792653}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contA", "doc_contA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contB", "doc_contB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792651}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory", "doc_shared_memory.vcproj", "{58CCE183-6032-12FE-4FC7-83A79F760B61}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_test", "unique_ptr_test.vcproj", "{571C3383-6092-A877-1238-B3786BAE7605}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_containers", "doc_move_containers.vcproj", "{58C1B183-0296-EA42-EF04-005120054104}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_index_allocation_test", "map_index_allocation_test.vcproj", "{588CCD13-2962-83FE-F4B7-92230DB73629}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_map_index_allocation_test", "flat_map_index_allocation_test.vcproj", "{51D8E9C3-2D65-48FE-3AA7-7922C0E36329}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iset_index_allocation_test", "iset_index_allocation_test.vcproj", "{58BD1CC3-6972-F3F7-84BE-0DB736035922}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iunordered_set_index_allocation_test", "iunordered_set_index_allocation_test.vcproj", "{5BD1C7C3-3F7F-6972-84BE-B731D9236035}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory2", "doc_shared_memory2.vcproj", "{58CE1D83-F31E-4FD7-6132-8A79F6307B61}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping2", "doc_file_mapping2.vcproj", "{5CE19883-F413-7EFD-6342-B79639F7B611}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping", "doc_file_mapping.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_map", "doc_map.vcproj", "{59CEC183-8192-8F6D-4FB7-BA260A79D352}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_test", "windows_shared_memory_test.vcproj", "{E385C28C-0691-4FA7-F48E-935BA0D06310}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_mapping_test", "windows_shared_memory_mapping_test.vcproj", "{518CE8C3-6512-FA75-46EF-B917A3A116D1}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_windows_shared_memory_test", "managed_windows_shared_memory.vcproj", "{5D18CE83-1926-7AE4-FE94-B606D9B23131}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_pool_test", "adaptive_pool_test.vcproj", "{58CE1D84-1962-4FE9-BA0D-A4F7973A4652}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_adaptive_pool_test", "cached_adaptive_pool_test.vcproj", "{5188E3CE-2964-F43E-FB87-B037AC692D59}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_adaptive_pool_test", "private_adaptive_pool_test.vcproj", "{5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_allocator", "doc_allocator.vcproj", "{581B1C83-4E12-9526-020F-012482540054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_node_allocator", "doc_node_allocator.vcproj", "{51B17C83-E172-5396-0FA2-825472008554}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_node_allocator", "doc_private_node_allocator.vcproj", "{2B75C833-17D2-4956-A23F-820854254175}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_node_allocator", "doc_cached_node_allocator.vcproj", "{283AD375-7D12-5866-23BF-854308651275}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_adaptive_pool", "doc_adaptive_pool.vcproj", "{57C832B1-17D2-9537-FA12-827220448554}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_adaptive_pool", "doc_cached_adaptive_pool.vcproj", "{536C8251-7E12-9537-A1E2-822073258554}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_adaptive_pool", "doc_private_adaptive_pool.vcproj", "{83258CB1-127E-9375-F872-8324A1054454}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_raw_allocation", "doc_managed_raw_allocation.vcproj", "{5198EFC3-2731-F34E-4FD8-1859AC94F761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_aligned_allocation", "doc_managed_aligned_allocation.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_interprocesslib", "interprocesslib.vcproj", "{FFAA56F1-32EC-4B22-B6BD-95A311A67C35}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory", "doc_windows_shared_memory.vcproj", "{5E17C9C3-1362-2E1E-C84F-8A76B6739F21}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory2", "doc_windows_shared_memory2.vcproj", "{5E1D6C83-31DE-4F6F-6132-87A9FB663041}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_node_pool_test", "adaptive_node_pool_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_pool_test", "node_pool_test.vcproj", "{8A519DC3-6092-A4FE-F748-BA91328D6522}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deque_test", "deque_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792655}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "barrier_test", "barrier_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792661}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bufferstream_test", "bufferstream_test.vcproj", "{58C183CE-6203-FE12-A237-BA8976695960}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_node_allocator_test", "cached_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792659}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_node_allocator_test", "private_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792620}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_allocator_test", "node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792622}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_mutex_test", "named_mutex_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792625}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_recursive_mutex_test", "named_recursive_mutex_test.vcproj", "{5C83CE18-4F48-A7FE-6092-B7920AD3A624}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_semaphore_test", "named_semaphore_test.vcproj", "{58CCE283-1609-48FE-A4F7-BA0D3A793523}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_heap_memory", "doc_managed_heap_memory.vcproj", "{58CCE183-6092-48FE-A4FC-BA0D3A792647}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "allocexcept_test", "allocexcept_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792662}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "condition_test", "condition_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792658}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_test", "data_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792657}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_bufferstream", "doc_bufferstream.vcproj", "{58C1B183-9026-4E12-00F2-001200540054}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_intrusive", "doc_intrusive.vcproj", "{5E18CC83-6092-48FE-A677-B832A0D3A650}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageA", "doc_ipc_messageA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageB", "doc_ipc_messageB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792648}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_mapped_file", "doc_managed_mapped_file.vcproj", "{58CCE183-5091-48FE-A4FC-BA0D3A792446}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocA", "doc_named_allocA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocB", "doc_named_allocB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792644}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_offset_ptr", "doc_offset_ptr.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792643}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_scoped_ptr", "doc_scoped_ptr.vcproj", "{58CC8E13-0962-8F4E-77A6-BD3A6832A042}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_vectorstream", "doc_vectorstream.vcproj", "{58C1B183-9260-4E8F-F200-000000000041}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_where_allocate", "doc_where_allocate.vcproj", "{58CCE183-6092-48FE-A677-BA0D3A832640}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_mapping_test", "file_mapping_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792638}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792637}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intrusive_ptr_test", "intrusive_ptr_test.vcproj", "{5821C383-6092-12FE-A877-BA0D33467633}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_ex.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_mapped_file_test", "managed_mapped_file_test.vcproj", "{5CCE1883-0926-F7A4-8FE4-BA0606D92331}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapped_file_test", "mapped_file_test.vcproj", "{5C6D9CE1-2609-F7A4-8FE4-BA0883602330}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_algorithm_test", "memory_algorithm_test.vcproj", "{58E18CC3-6092-8F4E-A3E7-A792230D3629}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_queue_test", "message_queue.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792628}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mutex_test", "mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A27}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "null_index_test", "null_index_test.vcproj", "{0000058C-0000-0000-0000-000000000021}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recursive_mutex_test", "recursive_mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A14}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "semaphore_test", "semaphore_test.vcproj", "{5CE28C83-48FE-1676-4FA7-B50D3A76A013}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_multiple_allocation", "doc_managed_multiple_allocation.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_allocation_command", "doc_managed_allocation_command.vcproj", "{5189DEA3-3261-F33E-47ED-83BC69F66061}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_construction_info", "doc_managed_construction_info.vcproj", "{5C82D1D3-3861-3AF1-03EF-89AED4716761}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr_explicit", "doc_shared_ptr_explicit.vcproj", "{4E887AC3-F8EA-6923-A744-C264A398C913}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unique_ptr", "doc_unique_ptr.vcproj", "{589C2EB3-8A57-1862-F4EA-A6B14C7329A3}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr", "doc_shared_ptr.vcproj", "{51CE89A3-6092-F4EA-48A7-B4B9AC326093}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_shared_memory_test", "managed_shared_memory.vcproj", "{58DF28E3-0926-F47A-E28A-B03A4D619631}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_grow", "doc_managed_grow.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "offset_ptr_test", "offset_ptr_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_shared_memory", "doc_anonymous_shared_memory.vcproj", "{6DE178C3-12FE-6032-4FC7-879B63B9F651}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anonymous_shared_memory_test", "anonymous_shared_memory_test.vcproj", "{58DE8A13-4FA7-6252-36FE-B3A0A6D92812}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unordered_map", "doc_unordered_map.vcproj", "{9C185DF3-B75F-1928-8F6D-735108AABE62}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_multi_index", "doc_multi_index.vcproj", "{918C5DF3-1928-B73F-F626-7358518CBE62}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_test", "unordered_test.vcproj", "{C3CE1183-09F2-A46A-4FE6-D06BA7923A02}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_index_test", "multi_index_test.vcproj", "{9285DFD3-1928-F662-CB73-73518CB53A62}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_lock_test", "file_lock_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792639}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intersegment_ptr_test", "intersegment_ptr_test.vcproj", "{5E81CD01-4FA2-2A96-84FE-DA631CA20962}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_copy_on_write", "doc_managed_copy_on_write.vcproj", "{8E0C437E-3613-FD46-F3AE-876A0731CA85}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.ActiveCfg = Debug|Win32 - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.Build.0 = Debug|Win32 - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.ActiveCfg = Release|Win32 - {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.Build.0 = Release|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.ActiveCfg = Debug|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.Build.0 = Debug|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.ActiveCfg = Release|Win32 - {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.Build.0 = Release|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Debug.ActiveCfg = Debug|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Debug.Build.0 = Debug|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Release.ActiveCfg = Release|Win32 - {5371C383-6092-1238-A877-BAEB37867609}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.ActiveCfg = Debug|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.Build.0 = Debug|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.ActiveCfg = Release|Win32 - {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.Build.0 = Release|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.Build.0 = Debug|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.ActiveCfg = Release|Win32 - {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.Build.0 = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.ActiveCfg = Debug|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.Build.0 = Debug|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.ActiveCfg = Release|Win32 - {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.Build.0 = Release|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Debug.Build.0 = Debug|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Release.ActiveCfg = Release|Win32 - {58C1B183-9026-4E63-12F2-005412200054}.Release.Build.0 = Release|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Debug.Build.0 = Debug|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Release.ActiveCfg = Release|Win32 - {58C1B183-9026-4E63-12F2-005202441254}.Release.Build.0 = Release|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Debug.ActiveCfg = Debug|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Debug.Build.0 = Debug|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Release.ActiveCfg = Release|Win32 - {58C181B3-9516-463E-2F12-122155400054}.Release.Build.0 = Release|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Debug.ActiveCfg = Debug|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Debug.Build.0 = Debug|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Release.ActiveCfg = Release|Win32 - {5C1B8183-0296-4F83-1F22-001005220544}.Release.Build.0 = Release|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Debug.ActiveCfg = Debug|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Debug.Build.0 = Debug|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Release.ActiveCfg = Release|Win32 - {58C1FE83-2906-E643-2F12-024410052254}.Release.Build.0 = Release|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Debug.ActiveCfg = Debug|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Debug.Build.0 = Debug|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Release.ActiveCfg = Release|Win32 - {58EB1CB3-1354-364E-12F2-154356612054}.Release.Build.0 = Release|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Debug.ActiveCfg = Debug|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Debug.Build.0 = Debug|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Release.ActiveCfg = Release|Win32 - {58181CB3-5134-634E-12F2-155435622054}.Release.Build.0 = Release|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Debug.ActiveCfg = Debug|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Debug.Build.0 = Debug|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Release.ActiveCfg = Release|Win32 - {5CB81183-29FB-F843-24FF-022050100544}.Release.Build.0 = Release|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.ActiveCfg = Debug|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.Build.0 = Debug|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Release.ActiveCfg = Release|Win32 - {58FBE8C3-9026-FAB2-E643-000522441254}.Release.Build.0 = Release|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.ActiveCfg = Debug|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.Build.0 = Debug|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.ActiveCfg = Release|Win32 - {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.Build.0 = Release|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.ActiveCfg = Debug|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.Build.0 = Debug|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.ActiveCfg = Release|Win32 - {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.Build.0 = Release|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.ActiveCfg = Debug|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.Build.0 = Debug|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Release.ActiveCfg = Release|Win32 - {5C1B1043-1EFF-2793-4E63-245241283054}.Release.Build.0 = Release|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.ActiveCfg = Debug|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.Build.0 = Debug|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Release.ActiveCfg = Release|Win32 - {51B189C3-4E63-9026-12F2-12200AF54054}.Release.Build.0 = Release|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Debug.ActiveCfg = Debug|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Debug.Build.0 = Debug|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Release.ActiveCfg = Release|Win32 - {5C1B1813-12C2-0296-4E63-244549126520}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.Build.0 = Release|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.Build.0 = Debug|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.ActiveCfg = Release|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.Build.0 = Release|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Debug.ActiveCfg = Debug|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Debug.Build.0 = Debug|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Release.ActiveCfg = Release|Win32 - {571C3383-6092-A877-1238-B3786BAE7605}.Release.Build.0 = Release|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Debug.Build.0 = Debug|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Release.ActiveCfg = Release|Win32 - {58C1B183-0296-EA42-EF04-005120054104}.Release.Build.0 = Release|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.ActiveCfg = Debug|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.Build.0 = Debug|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.ActiveCfg = Release|Win32 - {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.Build.0 = Release|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.ActiveCfg = Debug|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.Build.0 = Debug|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.ActiveCfg = Release|Win32 - {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.Build.0 = Release|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.ActiveCfg = Debug|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.Build.0 = Debug|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.ActiveCfg = Release|Win32 - {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.Build.0 = Release|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.ActiveCfg = Debug|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.Build.0 = Debug|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.ActiveCfg = Release|Win32 - {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.Build.0 = Release|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.ActiveCfg = Debug|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.Build.0 = Debug|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.ActiveCfg = Release|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.Build.0 = Release|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.ActiveCfg = Debug|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.Build.0 = Debug|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.ActiveCfg = Release|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.Build.0 = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.ActiveCfg = Debug|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.Build.0 = Debug|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.ActiveCfg = Release|Win32 - {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.Build.0 = Release|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.ActiveCfg = Debug|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.Build.0 = Debug|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.ActiveCfg = Release|Win32 - {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.Build.0 = Release|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.ActiveCfg = Debug|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.Build.0 = Debug|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.ActiveCfg = Release|Win32 - {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.Build.0 = Release|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.ActiveCfg = Debug|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.Build.0 = Debug|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.ActiveCfg = Release|Win32 - {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.Build.0 = Release|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.ActiveCfg = Debug|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.Build.0 = Debug|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.ActiveCfg = Release|Win32 - {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.Build.0 = Release|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.ActiveCfg = Debug|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.Build.0 = Debug|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.ActiveCfg = Release|Win32 - {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.Build.0 = Release|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.ActiveCfg = Debug|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.Build.0 = Debug|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.ActiveCfg = Release|Win32 - {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.Build.0 = Release|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Debug.ActiveCfg = Debug|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Debug.Build.0 = Debug|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Release.ActiveCfg = Release|Win32 - {581B1C83-4E12-9526-020F-012482540054}.Release.Build.0 = Release|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Debug.ActiveCfg = Debug|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Debug.Build.0 = Debug|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Release.ActiveCfg = Release|Win32 - {51B17C83-E172-5396-0FA2-825472008554}.Release.Build.0 = Release|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Debug.ActiveCfg = Debug|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Debug.Build.0 = Debug|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Release.ActiveCfg = Release|Win32 - {2B75C833-17D2-4956-A23F-820854254175}.Release.Build.0 = Release|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Debug.ActiveCfg = Debug|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Debug.Build.0 = Debug|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Release.ActiveCfg = Release|Win32 - {283AD375-7D12-5866-23BF-854308651275}.Release.Build.0 = Release|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Debug.ActiveCfg = Debug|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Debug.Build.0 = Debug|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Release.ActiveCfg = Release|Win32 - {57C832B1-17D2-9537-FA12-827220448554}.Release.Build.0 = Release|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Debug.ActiveCfg = Debug|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Debug.Build.0 = Debug|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Release.ActiveCfg = Release|Win32 - {536C8251-7E12-9537-A1E2-822073258554}.Release.Build.0 = Release|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Debug.ActiveCfg = Debug|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Debug.Build.0 = Debug|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Release.ActiveCfg = Release|Win32 - {83258CB1-127E-9375-F872-8324A1054454}.Release.Build.0 = Release|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.ActiveCfg = Debug|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.Build.0 = Debug|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.ActiveCfg = Release|Win32 - {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.Build.0 = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 - {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.ActiveCfg = Debug|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.Build.0 = Debug|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.ActiveCfg = Release|Win32 - {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.Build.0 = Release|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.ActiveCfg = Debug|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.Build.0 = Debug|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.ActiveCfg = Release|Win32 - {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.Build.0 = Release|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.ActiveCfg = Debug|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.Build.0 = Debug|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.ActiveCfg = Release|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.Build.0 = Release|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 - {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.ActiveCfg = Debug|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.Build.0 = Debug|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.ActiveCfg = Release|Win32 - {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.Build.0 = Release|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Debug.ActiveCfg = Debug|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Debug.Build.0 = Debug|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Release.ActiveCfg = Release|Win32 - {58C183CE-6203-FE12-A237-BA8976695960}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.Build.0 = Release|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.ActiveCfg = Debug|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.Build.0 = Debug|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.ActiveCfg = Release|Win32 - {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.Build.0 = Release|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.ActiveCfg = Debug|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.Build.0 = Debug|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.ActiveCfg = Release|Win32 - {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.Build.0 = Release|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Debug.Build.0 = Debug|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Release.ActiveCfg = Release|Win32 - {58C1B183-9026-4E12-00F2-001200540054}.Release.Build.0 = Release|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.ActiveCfg = Debug|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.Build.0 = Debug|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.ActiveCfg = Release|Win32 - {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.Build.0 = Release|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.Build.0 = Debug|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.ActiveCfg = Release|Win32 - {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.Build.0 = Release|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.ActiveCfg = Debug|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.Build.0 = Debug|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.ActiveCfg = Release|Win32 - {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.Build.0 = Release|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Debug.ActiveCfg = Debug|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Debug.Build.0 = Debug|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Release.ActiveCfg = Release|Win32 - {58C1B183-9260-4E8F-F200-000000000041}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Debug.ActiveCfg = Debug|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Debug.Build.0 = Debug|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Release.ActiveCfg = Release|Win32 - {5821C383-6092-12FE-A877-BA0D33467633}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.ActiveCfg = Debug|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.Build.0 = Debug|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.ActiveCfg = Release|Win32 - {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.Build.0 = Release|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.ActiveCfg = Debug|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.Build.0 = Debug|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.ActiveCfg = Release|Win32 - {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.Build.0 = Release|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.ActiveCfg = Debug|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.Build.0 = Debug|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.ActiveCfg = Release|Win32 - {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.Build.0 = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.ActiveCfg = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.Build.0 = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.ActiveCfg = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.Build.0 = Release|Win32 - {0000058C-0000-0000-0000-000000000021}.Debug.ActiveCfg = Debug|Win32 - {0000058C-0000-0000-0000-000000000021}.Debug.Build.0 = Debug|Win32 - {0000058C-0000-0000-0000-000000000021}.Release.ActiveCfg = Release|Win32 - {0000058C-0000-0000-0000-000000000021}.Release.Build.0 = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.ActiveCfg = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.Build.0 = Debug|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.ActiveCfg = Release|Win32 - {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.Build.0 = Release|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.ActiveCfg = Debug|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.Build.0 = Debug|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.ActiveCfg = Release|Win32 - {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.Build.0 = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.ActiveCfg = Debug|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.Build.0 = Debug|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.ActiveCfg = Release|Win32 - {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.Build.0 = Release|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.ActiveCfg = Debug|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.Build.0 = Debug|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.ActiveCfg = Release|Win32 - {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.Build.0 = Release|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.ActiveCfg = Debug|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.Build.0 = Debug|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.ActiveCfg = Release|Win32 - {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.Build.0 = Release|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.ActiveCfg = Debug|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.Build.0 = Debug|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.ActiveCfg = Release|Win32 - {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.Build.0 = Release|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.ActiveCfg = Debug|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.Build.0 = Debug|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.ActiveCfg = Release|Win32 - {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.Build.0 = Release|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.ActiveCfg = Debug|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.Build.0 = Debug|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.ActiveCfg = Release|Win32 - {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.Build.0 = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 - {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 - {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 - {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.ActiveCfg = Debug|Win32 - {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.Build.0 = Debug|Win32 - {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.ActiveCfg = Release|Win32 - {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.Build.0 = Release|Win32 - {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.ActiveCfg = Debug|Win32 - {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.Build.0 = Debug|Win32 - {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.ActiveCfg = Release|Win32 - {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.Build.0 = Release|Win32 - {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.ActiveCfg = Debug|Win32 - {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.Build.0 = Debug|Win32 - {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.ActiveCfg = Release|Win32 - {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.Build.0 = Release|Win32 - {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.ActiveCfg = Debug|Win32 - {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.Build.0 = Debug|Win32 - {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.ActiveCfg = Release|Win32 - {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.Build.0 = Release|Win32 - {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.ActiveCfg = Debug|Win32 - {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.Build.0 = Debug|Win32 - {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.ActiveCfg = Release|Win32 - {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.Build.0 = Release|Win32 - {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.ActiveCfg = Debug|Win32 - {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.Build.0 = Debug|Win32 - {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.ActiveCfg = Release|Win32 - {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.Build.0 = Release|Win32 - {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.ActiveCfg = Debug|Win32 - {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.Build.0 = Debug|Win32 - {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.ActiveCfg = Release|Win32 - {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.Build.0 = Release|Win32 - {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.ActiveCfg = Debug|Win32 - {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.Build.0 = Debug|Win32 - {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.ActiveCfg = Release|Win32 - {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_mapping_test", "shared_memory_mappable_test.vcproj", "{5CE18C83-6025-36FE-A4F7-BA09176D3A11}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_memory_test", "shared_memory_test.vcproj", "{5E2838CC-0916-8F4E-A4F7-93506BA0D310}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared_ptr_test", "shared_ptr_test.vcproj", "{5371C383-6092-1238-A877-BAEB37867609}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slist_test", "slist_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792608}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string_test", "string_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D4A792607}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upgradable_mutex_test", "upgradable_mutex.vcproj", "{4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user_buffer_test", "user_buffer_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792603}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vectorstream_test", "vectorstream_test.vcproj", "{58CCE183-6032-12FE-A4F7-BA893A767601}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_test", "vector_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_condition_test", "named_condition_test.vcproj", "{58CC2563-6092-48FE-FAF7-BA046A792658}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexA", "doc_anonymous_mutexA.vcproj", "{58C1B183-9026-4E63-12F2-005412200054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_mutexB", "doc_anonymous_mutexB.vcproj", "{58C1B183-9026-4E63-12F2-005202441254}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_mutex", "doc_named_mutex.vcproj", "{58C181B3-9516-463E-2F12-122155400054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionA", "doc_anonymous_conditionA.vcproj", "{5C1B8183-0296-4F83-1F22-001005220544}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_conditionB", "doc_anonymous_conditionB.vcproj", "{58C1FE83-2906-E643-2F12-024410052254}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionA", "doc_named_conditionA.vcproj", "{58EB1CB3-1354-364E-12F2-154356612054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_conditionB", "doc_named_conditionB.vcproj", "{58181CB3-5134-634E-12F2-155435622054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreA", "doc_anonymous_semaphoreA.vcproj", "{5CB81183-29FB-F843-24FF-022050100544}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_semaphoreB", "doc_anonymous_semaphoreB.vcproj", "{58FBE8C3-9026-FAB2-E643-000522441254}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_upgradable_mutex_test", "named_upgradable_mutex.vcproj", "{48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexA", "doc_anonymous_upgradable_mutexA.vcproj", "{5C18831B-F162-FA96-E6C3-FA5122040054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_upgradable_mutexB", "doc_anonymous_upgradable_mutexB.vcproj", "{5C1B1043-1EFF-2793-4E63-245241283054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueA", "doc_message_queueA.vcproj", "{51B189C3-4E63-9026-12F2-12200AF54054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_message_queueB", "doc_message_queueB.vcproj", "{5C1B1813-12C2-0296-4E63-244549126520}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cont", "doc_cont.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792653}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contA", "doc_contA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contB", "doc_contB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792651}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory", "doc_shared_memory.vcproj", "{58CCE183-6032-12FE-4FC7-83A79F760B61}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_test", "unique_ptr_test.vcproj", "{571C3383-6092-A877-1238-B3786BAE7605}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_containers", "doc_move_containers.vcproj", "{58C1B183-0296-EA42-EF04-005120054104}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map_index_allocation_test", "map_index_allocation_test.vcproj", "{588CCD13-2962-83FE-F4B7-92230DB73629}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_map_index_allocation_test", "flat_map_index_allocation_test.vcproj", "{51D8E9C3-2D65-48FE-3AA7-7922C0E36329}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iset_index_allocation_test", "iset_index_allocation_test.vcproj", "{58BD1CC3-6972-F3F7-84BE-0DB736035922}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iunordered_set_index_allocation_test", "iunordered_set_index_allocation_test.vcproj", "{5BD1C7C3-3F7F-6972-84BE-B731D9236035}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory2", "doc_shared_memory2.vcproj", "{58CE1D83-F31E-4FD7-6132-8A79F6307B61}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping2", "doc_file_mapping2.vcproj", "{5CE19883-F413-7EFD-6342-B79639F7B611}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping", "doc_file_mapping.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_map", "doc_map.vcproj", "{59CEC183-8192-8F6D-4FB7-BA260A79D352}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_test", "windows_shared_memory_test.vcproj", "{E385C28C-0691-4FA7-F48E-935BA0D06310}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windows_shared_memory_mapping_test", "windows_shared_memory_mapping_test.vcproj", "{518CE8C3-6512-FA75-46EF-B917A3A116D1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_windows_shared_memory_test", "managed_windows_shared_memory.vcproj", "{5D18CE83-1926-7AE4-FE94-B606D9B23131}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_pool_test", "adaptive_pool_test.vcproj", "{58CE1D84-1962-4FE9-BA0D-A4F7973A4652}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_adaptive_pool_test", "cached_adaptive_pool_test.vcproj", "{5188E3CE-2964-F43E-FB87-B037AC692D59}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_adaptive_pool_test", "private_adaptive_pool_test.vcproj", "{5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_allocator", "doc_allocator.vcproj", "{581B1C83-4E12-9526-020F-012482540054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_node_allocator", "doc_node_allocator.vcproj", "{51B17C83-E172-5396-0FA2-825472008554}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_node_allocator", "doc_private_node_allocator.vcproj", "{2B75C833-17D2-4956-A23F-820854254175}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_node_allocator", "doc_cached_node_allocator.vcproj", "{283AD375-7D12-5866-23BF-854308651275}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_adaptive_pool", "doc_adaptive_pool.vcproj", "{57C832B1-17D2-9537-FA12-827220448554}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cached_adaptive_pool", "doc_cached_adaptive_pool.vcproj", "{536C8251-7E12-9537-A1E2-822073258554}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_private_adaptive_pool", "doc_private_adaptive_pool.vcproj", "{83258CB1-127E-9375-F872-8324A1054454}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_raw_allocation", "doc_managed_raw_allocation.vcproj", "{5198EFC3-2731-F34E-4FD8-1859AC94F761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_aligned_allocation", "doc_managed_aligned_allocation.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_interprocesslib", "interprocesslib.vcproj", "{FFAA56F1-32EC-4B22-B6BD-95A311A67C35}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory", "doc_windows_shared_memory.vcproj", "{5E17C9C3-1362-2E1E-C84F-8A76B6739F21}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory2", "doc_windows_shared_memory2.vcproj", "{5E1D6C83-31DE-4F6F-6132-87A9FB663041}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_node_pool_test", "adaptive_node_pool_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_pool_test", "node_pool_test.vcproj", "{8A519DC3-6092-A4FE-F748-BA91328D6522}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deque_test", "deque_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792655}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "barrier_test", "barrier_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792661}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bufferstream_test", "bufferstream_test.vcproj", "{58C183CE-6203-FE12-A237-BA8976695960}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cached_node_allocator_test", "cached_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792659}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private_node_allocator_test", "private_node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792620}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_allocator_test", "node_allocator_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792622}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_mutex_test", "named_mutex_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792625}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_recursive_mutex_test", "named_recursive_mutex_test.vcproj", "{5C83CE18-4F48-A7FE-6092-B7920AD3A624}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_semaphore_test", "named_semaphore_test.vcproj", "{58CCE283-1609-48FE-A4F7-BA0D3A793523}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_heap_memory", "doc_managed_heap_memory.vcproj", "{58CCE183-6092-48FE-A4FC-BA0D3A792647}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "allocexcept_test", "allocexcept_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792662}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "condition_test", "condition_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792658}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data_test", "data_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792657}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_bufferstream", "doc_bufferstream.vcproj", "{58C1B183-9026-4E12-00F2-001200540054}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_intrusive", "doc_intrusive.vcproj", "{5E18CC83-6092-48FE-A677-B832A0D3A650}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageA", "doc_ipc_messageA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageB", "doc_ipc_messageB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792648}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_mapped_file", "doc_managed_mapped_file.vcproj", "{58CCE183-5091-48FE-A4FC-BA0D3A792446}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocA", "doc_named_allocA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocB", "doc_named_allocB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792644}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_offset_ptr", "doc_offset_ptr.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792643}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_scoped_ptr", "doc_scoped_ptr.vcproj", "{58CC8E13-0962-8F4E-77A6-BD3A6832A042}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_vectorstream", "doc_vectorstream.vcproj", "{58C1B183-9260-4E8F-F200-000000000041}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_where_allocate", "doc_where_allocate.vcproj", "{58CCE183-6092-48FE-A677-BA0D3A832640}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_mapping_test", "file_mapping_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792638}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792637}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intrusive_ptr_test", "intrusive_ptr_test.vcproj", "{5821C383-6092-12FE-A877-BA0D33467633}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_ex.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_mapped_file_test", "managed_mapped_file_test.vcproj", "{5CCE1883-0926-F7A4-8FE4-BA0606D92331}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapped_file_test", "mapped_file_test.vcproj", "{5C6D9CE1-2609-F7A4-8FE4-BA0883602330}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_algorithm_test", "memory_algorithm_test.vcproj", "{58E18CC3-6092-8F4E-A3E7-A792230D3629}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_queue_test", "message_queue.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792628}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mutex_test", "mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A27}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "null_index_test", "null_index_test.vcproj", "{0000058C-0000-0000-0000-000000000021}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "recursive_mutex_test", "recursive_mutex_test.vcproj", "{83581CCE-487E-3292-A4E7-BA07926D3A14}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "semaphore_test", "semaphore_test.vcproj", "{5CE28C83-48FE-1676-4FA7-B50D3A76A013}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_multiple_allocation", "doc_managed_multiple_allocation.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_allocation_command", "doc_managed_allocation_command.vcproj", "{5189DEA3-3261-F33E-47ED-83BC69F66061}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_construction_info", "doc_managed_construction_info.vcproj", "{5C82D1D3-3861-3AF1-03EF-89AED4716761}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr_explicit", "doc_shared_ptr_explicit.vcproj", "{4E887AC3-F8EA-6923-A744-C264A398C913}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unique_ptr", "doc_unique_ptr.vcproj", "{589C2EB3-8A57-1862-F4EA-A6B14C7329A3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_ptr", "doc_shared_ptr.vcproj", "{51CE89A3-6092-F4EA-48A7-B4B9AC326093}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "managed_shared_memory_test", "managed_shared_memory.vcproj", "{58DF28E3-0926-F47A-E28A-B03A4D619631}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_grow", "doc_managed_grow.vcproj", "{818C43EE-3561-F3AE-4FD7-8A2076E76A31}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "offset_ptr_test", "offset_ptr_test.vcproj", "{5CE11C83-096A-84FE-4FA2-D3A6BA792002}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_anonymous_shared_memory", "doc_anonymous_shared_memory.vcproj", "{6DE178C3-12FE-6032-4FC7-879B63B9F651}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "anonymous_shared_memory_test", "anonymous_shared_memory_test.vcproj", "{58DE8A13-4FA7-6252-36FE-B3A0A6D92812}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_unordered_map", "doc_unordered_map.vcproj", "{9C185DF3-B75F-1928-8F6D-735108AABE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_multi_index", "doc_multi_index.vcproj", "{918C5DF3-1928-B73F-F626-7358518CBE62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unordered_test", "unordered_test.vcproj", "{C3CE1183-09F2-A46A-4FE6-D06BA7923A02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multi_index_test", "multi_index_test.vcproj", "{9285DFD3-1928-F662-CB73-73518CB53A62}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_lock_test", "file_lock_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792639}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intersegment_ptr_test", "intersegment_ptr_test.vcproj", "{5E81CD01-4FA2-2A96-84FE-DA631CA20962}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_copy_on_write", "doc_managed_copy_on_write.vcproj", "{8E0C437E-3613-FD46-F3AE-876A0731CA85}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.ActiveCfg = Debug|Win32 + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.Build.0 = Debug|Win32 + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.ActiveCfg = Release|Win32 + {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Release.Build.0 = Release|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.ActiveCfg = Debug|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Debug.Build.0 = Debug|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.ActiveCfg = Release|Win32 + {5E2838CC-0916-8F4E-A4F7-93506BA0D310}.Release.Build.0 = Release|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Debug.ActiveCfg = Debug|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Debug.Build.0 = Debug|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Release.ActiveCfg = Release|Win32 + {5371C383-6092-1238-A877-BAEB37867609}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792608}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D4A792607}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.ActiveCfg = Debug|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Debug.Build.0 = Debug|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.ActiveCfg = Release|Win32 + {4E88C1C2-0961-F7A4-F48E-A6A7D3B06004}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792603}.Release.Build.0 = Release|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Debug.Build.0 = Debug|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.ActiveCfg = Release|Win32 + {58CCE183-6032-12FE-A4F7-BA893A767601}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.ActiveCfg = Debug|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Debug.Build.0 = Debug|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.ActiveCfg = Release|Win32 + {58CC2563-6092-48FE-FAF7-BA046A792658}.Release.Build.0 = Release|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Debug.Build.0 = Debug|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Release.ActiveCfg = Release|Win32 + {58C1B183-9026-4E63-12F2-005412200054}.Release.Build.0 = Release|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Debug.Build.0 = Debug|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Release.ActiveCfg = Release|Win32 + {58C1B183-9026-4E63-12F2-005202441254}.Release.Build.0 = Release|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Debug.ActiveCfg = Debug|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Debug.Build.0 = Debug|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Release.ActiveCfg = Release|Win32 + {58C181B3-9516-463E-2F12-122155400054}.Release.Build.0 = Release|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Debug.ActiveCfg = Debug|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Debug.Build.0 = Debug|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Release.ActiveCfg = Release|Win32 + {5C1B8183-0296-4F83-1F22-001005220544}.Release.Build.0 = Release|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Debug.ActiveCfg = Debug|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Debug.Build.0 = Debug|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Release.ActiveCfg = Release|Win32 + {58C1FE83-2906-E643-2F12-024410052254}.Release.Build.0 = Release|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Debug.ActiveCfg = Debug|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Debug.Build.0 = Debug|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Release.ActiveCfg = Release|Win32 + {58EB1CB3-1354-364E-12F2-154356612054}.Release.Build.0 = Release|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Debug.ActiveCfg = Debug|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Debug.Build.0 = Debug|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Release.ActiveCfg = Release|Win32 + {58181CB3-5134-634E-12F2-155435622054}.Release.Build.0 = Release|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Debug.ActiveCfg = Debug|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Debug.Build.0 = Debug|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Release.ActiveCfg = Release|Win32 + {5CB81183-29FB-F843-24FF-022050100544}.Release.Build.0 = Release|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.ActiveCfg = Debug|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Debug.Build.0 = Debug|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Release.ActiveCfg = Release|Win32 + {58FBE8C3-9026-FAB2-E643-000522441254}.Release.Build.0 = Release|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.ActiveCfg = Debug|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Debug.Build.0 = Debug|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.ActiveCfg = Release|Win32 + {48C1FBE8-F7A4-0961-48FE-7D93A63B0A04}.Release.Build.0 = Release|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.ActiveCfg = Debug|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Debug.Build.0 = Debug|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.ActiveCfg = Release|Win32 + {5C18831B-F162-FA96-E6C3-FA5122040054}.Release.Build.0 = Release|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.ActiveCfg = Debug|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Debug.Build.0 = Debug|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Release.ActiveCfg = Release|Win32 + {5C1B1043-1EFF-2793-4E63-245241283054}.Release.Build.0 = Release|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.ActiveCfg = Debug|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Debug.Build.0 = Debug|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Release.ActiveCfg = Release|Win32 + {51B189C3-4E63-9026-12F2-12200AF54054}.Release.Build.0 = Release|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Debug.ActiveCfg = Debug|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Debug.Build.0 = Debug|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Release.ActiveCfg = Release|Win32 + {5C1B1813-12C2-0296-4E63-244549126520}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.Build.0 = Release|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.Build.0 = Debug|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.ActiveCfg = Release|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.Build.0 = Release|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Debug.ActiveCfg = Debug|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Debug.Build.0 = Debug|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Release.ActiveCfg = Release|Win32 + {571C3383-6092-A877-1238-B3786BAE7605}.Release.Build.0 = Release|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Debug.Build.0 = Debug|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Release.ActiveCfg = Release|Win32 + {58C1B183-0296-EA42-EF04-005120054104}.Release.Build.0 = Release|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.ActiveCfg = Debug|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Debug.Build.0 = Debug|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.ActiveCfg = Release|Win32 + {588CCD13-2962-83FE-F4B7-92230DB73629}.Release.Build.0 = Release|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.ActiveCfg = Debug|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Debug.Build.0 = Debug|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.ActiveCfg = Release|Win32 + {51D8E9C3-2D65-48FE-3AA7-7922C0E36329}.Release.Build.0 = Release|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.ActiveCfg = Debug|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Debug.Build.0 = Debug|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.ActiveCfg = Release|Win32 + {58BD1CC3-6972-F3F7-84BE-0DB736035922}.Release.Build.0 = Release|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.ActiveCfg = Debug|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.Build.0 = Debug|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.ActiveCfg = Release|Win32 + {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.Build.0 = Release|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.ActiveCfg = Debug|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.Build.0 = Debug|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.ActiveCfg = Release|Win32 + {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.Build.0 = Release|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.ActiveCfg = Debug|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.Build.0 = Debug|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.ActiveCfg = Release|Win32 + {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.Build.0 = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.ActiveCfg = Debug|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Debug.Build.0 = Debug|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.ActiveCfg = Release|Win32 + {59CEC183-8192-8F6D-4FB7-BA260A79D352}.Release.Build.0 = Release|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.ActiveCfg = Debug|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Debug.Build.0 = Debug|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.ActiveCfg = Release|Win32 + {E385C28C-0691-4FA7-F48E-935BA0D06310}.Release.Build.0 = Release|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.ActiveCfg = Debug|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Debug.Build.0 = Debug|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.ActiveCfg = Release|Win32 + {518CE8C3-6512-FA75-46EF-B917A3A116D1}.Release.Build.0 = Release|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.ActiveCfg = Debug|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Debug.Build.0 = Debug|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.ActiveCfg = Release|Win32 + {5D18CE83-1926-7AE4-FE94-B606D9B23131}.Release.Build.0 = Release|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.ActiveCfg = Debug|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Debug.Build.0 = Debug|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.ActiveCfg = Release|Win32 + {58CE1D84-1962-4FE9-BA0D-A4F7973A4652}.Release.Build.0 = Release|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.ActiveCfg = Debug|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Debug.Build.0 = Debug|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.ActiveCfg = Release|Win32 + {5188E3CE-2964-F43E-FB87-B037AC692D59}.Release.Build.0 = Release|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.ActiveCfg = Debug|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Debug.Build.0 = Debug|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.ActiveCfg = Release|Win32 + {5CE14C83-4962-8F5E-4FA7-B0D3A7B93635}.Release.Build.0 = Release|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Debug.ActiveCfg = Debug|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Debug.Build.0 = Debug|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Release.ActiveCfg = Release|Win32 + {581B1C83-4E12-9526-020F-012482540054}.Release.Build.0 = Release|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Debug.ActiveCfg = Debug|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Debug.Build.0 = Debug|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Release.ActiveCfg = Release|Win32 + {51B17C83-E172-5396-0FA2-825472008554}.Release.Build.0 = Release|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Debug.ActiveCfg = Debug|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Debug.Build.0 = Debug|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Release.ActiveCfg = Release|Win32 + {2B75C833-17D2-4956-A23F-820854254175}.Release.Build.0 = Release|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Debug.ActiveCfg = Debug|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Debug.Build.0 = Debug|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Release.ActiveCfg = Release|Win32 + {283AD375-7D12-5866-23BF-854308651275}.Release.Build.0 = Release|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Debug.ActiveCfg = Debug|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Debug.Build.0 = Debug|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Release.ActiveCfg = Release|Win32 + {57C832B1-17D2-9537-FA12-827220448554}.Release.Build.0 = Release|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Debug.ActiveCfg = Debug|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Debug.Build.0 = Debug|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Release.ActiveCfg = Release|Win32 + {536C8251-7E12-9537-A1E2-822073258554}.Release.Build.0 = Release|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Debug.ActiveCfg = Debug|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Debug.Build.0 = Debug|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Release.ActiveCfg = Release|Win32 + {83258CB1-127E-9375-F872-8324A1054454}.Release.Build.0 = Release|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.ActiveCfg = Debug|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Debug.Build.0 = Debug|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.ActiveCfg = Release|Win32 + {5198EFC3-2731-F34E-4FD8-1859AC94F761}.Release.Build.0 = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 + {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.Build.0 = Release|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.ActiveCfg = Debug|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Debug.Build.0 = Debug|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.ActiveCfg = Release|Win32 + {FFAA56F1-32EC-4B22-B6BD-95A311A67C35}.Release.Build.0 = Release|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.ActiveCfg = Debug|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.Build.0 = Debug|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.ActiveCfg = Release|Win32 + {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.Build.0 = Release|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.ActiveCfg = Debug|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.Build.0 = Debug|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.ActiveCfg = Release|Win32 + {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.ActiveCfg = Debug|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Debug.Build.0 = Debug|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.ActiveCfg = Release|Win32 + {8A519DC3-6092-A4FE-F748-BA91328D6522}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792655}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792661}.Release.Build.0 = Release|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Debug.ActiveCfg = Debug|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Debug.Build.0 = Debug|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Release.ActiveCfg = Release|Win32 + {58C183CE-6203-FE12-A237-BA8976695960}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792659}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792620}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792622}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792625}.Release.Build.0 = Release|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.ActiveCfg = Debug|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Debug.Build.0 = Debug|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.ActiveCfg = Release|Win32 + {5C83CE18-4F48-A7FE-6092-B7920AD3A624}.Release.Build.0 = Release|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.ActiveCfg = Debug|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Debug.Build.0 = Debug|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.ActiveCfg = Release|Win32 + {58CCE283-1609-48FE-A4F7-BA0D3A793523}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4FC-BA0D3A792647}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792662}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792658}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792657}.Release.Build.0 = Release|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Debug.Build.0 = Debug|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Release.ActiveCfg = Release|Win32 + {58C1B183-9026-4E12-00F2-001200540054}.Release.Build.0 = Release|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.ActiveCfg = Debug|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.Build.0 = Debug|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.ActiveCfg = Release|Win32 + {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.Build.0 = Release|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.Build.0 = Debug|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.ActiveCfg = Release|Win32 + {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.Build.0 = Release|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.ActiveCfg = Debug|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Debug.Build.0 = Debug|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.ActiveCfg = Release|Win32 + {58CC8E13-0962-8F4E-77A6-BD3A6832A042}.Release.Build.0 = Release|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Debug.ActiveCfg = Debug|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Debug.Build.0 = Debug|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Release.ActiveCfg = Release|Win32 + {58C1B183-9260-4E8F-F200-000000000041}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A677-BA0D3A832640}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792638}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Debug.ActiveCfg = Debug|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Debug.Build.0 = Debug|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Release.ActiveCfg = Release|Win32 + {5821C383-6092-12FE-A877-BA0D33467633}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.Build.0 = Release|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.ActiveCfg = Debug|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Debug.Build.0 = Debug|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.ActiveCfg = Release|Win32 + {5CCE1883-0926-F7A4-8FE4-BA0606D92331}.Release.Build.0 = Release|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.ActiveCfg = Debug|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Debug.Build.0 = Debug|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.ActiveCfg = Release|Win32 + {5C6D9CE1-2609-F7A4-8FE4-BA0883602330}.Release.Build.0 = Release|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.ActiveCfg = Debug|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Debug.Build.0 = Debug|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.ActiveCfg = Release|Win32 + {58E18CC3-6092-8F4E-A3E7-A792230D3629}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792628}.Release.Build.0 = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.ActiveCfg = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Debug.Build.0 = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.ActiveCfg = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A27}.Release.Build.0 = Release|Win32 + {0000058C-0000-0000-0000-000000000021}.Debug.ActiveCfg = Debug|Win32 + {0000058C-0000-0000-0000-000000000021}.Debug.Build.0 = Debug|Win32 + {0000058C-0000-0000-0000-000000000021}.Release.ActiveCfg = Release|Win32 + {0000058C-0000-0000-0000-000000000021}.Release.Build.0 = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.ActiveCfg = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Debug.Build.0 = Debug|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.ActiveCfg = Release|Win32 + {83581CCE-487E-3292-A4E7-BA07926D3A14}.Release.Build.0 = Release|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.ActiveCfg = Debug|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Debug.Build.0 = Debug|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.ActiveCfg = Release|Win32 + {5CE28C83-48FE-1676-4FA7-B50D3A76A013}.Release.Build.0 = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.ActiveCfg = Debug|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Debug.Build.0 = Debug|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.ActiveCfg = Release|Win32 + {5189DEA3-3261-F33E-47ED-83BC69F66061}.Release.Build.0 = Release|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.ActiveCfg = Debug|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Debug.Build.0 = Debug|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.ActiveCfg = Release|Win32 + {5C82D1D3-3861-3AF1-03EF-89AED4716761}.Release.Build.0 = Release|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.ActiveCfg = Debug|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Debug.Build.0 = Debug|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.ActiveCfg = Release|Win32 + {4E887AC3-F8EA-6923-A744-C264A398C913}.Release.Build.0 = Release|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.ActiveCfg = Debug|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Debug.Build.0 = Debug|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.ActiveCfg = Release|Win32 + {589C2EB3-8A57-1862-F4EA-A6B14C7329A3}.Release.Build.0 = Release|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.ActiveCfg = Debug|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Debug.Build.0 = Debug|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.ActiveCfg = Release|Win32 + {51CE89A3-6092-F4EA-48A7-B4B9AC326093}.Release.Build.0 = Release|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.ActiveCfg = Debug|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Debug.Build.0 = Debug|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.ActiveCfg = Release|Win32 + {58DF28E3-0926-F47A-E28A-B03A4D619631}.Release.Build.0 = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.ActiveCfg = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Debug.Build.0 = Debug|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.ActiveCfg = Release|Win32 + {818C43EE-3561-F3AE-4FD7-8A2076E76A31}.Release.Build.0 = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.ActiveCfg = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Debug.Build.0 = Debug|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.ActiveCfg = Release|Win32 + {5CE11C83-096A-84FE-4FA2-D3A6BA792002}.Release.Build.0 = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.ActiveCfg = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Debug.Build.0 = Debug|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.ActiveCfg = Release|Win32 + {6DE178C3-12FE-6032-4FC7-879B63B9F651}.Release.Build.0 = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.ActiveCfg = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Debug.Build.0 = Debug|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.ActiveCfg = Release|Win32 + {58DE8A13-4FA7-6252-36FE-B3A0A6D92812}.Release.Build.0 = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.ActiveCfg = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Debug.Build.0 = Debug|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.ActiveCfg = Release|Win32 + {9C185DF3-B75F-1928-8F6D-735108AABE62}.Release.Build.0 = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.ActiveCfg = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Debug.Build.0 = Debug|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.ActiveCfg = Release|Win32 + {918C5DF3-1928-B73F-F626-7358518CBE62}.Release.Build.0 = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.ActiveCfg = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Debug.Build.0 = Debug|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.ActiveCfg = Release|Win32 + {C3CE1183-09F2-A46A-4FE6-D06BA7923A02}.Release.Build.0 = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.ActiveCfg = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Debug.Build.0 = Debug|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.ActiveCfg = Release|Win32 + {9285DFD3-1928-F662-CB73-73518CB53A62}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792639}.Release.Build.0 = Release|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.ActiveCfg = Debug|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Debug.Build.0 = Debug|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.ActiveCfg = Release|Win32 + {5E81CD01-4FA2-2A96-84FE-DA631CA20962}.Release.Build.0 = Release|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.ActiveCfg = Debug|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.Build.0 = Debug|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.ActiveCfg = Release|Win32 + {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal From 90400be1043cdd9439c549b0777f9252b3669840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 09:05:10 +0000 Subject: [PATCH 36/77] gcc 4.3 fixes for normal and -std=c++0x modes [SVN r46572] --- .../interprocess/allocators/adaptive_pool.hpp | 2 +- .../allocators/cached_adaptive_pool.hpp | 9 +- .../allocators/cached_node_allocator.hpp | 9 +- .../allocators/node_allocator.hpp | 2 +- .../allocators/private_adaptive_pool.hpp | 4 +- .../allocators/private_node_allocator.hpp | 4 +- .../interprocess/anonymous_shared_memory.hpp | 18 ++- .../boost/interprocess/containers/deque.hpp | 24 ++-- .../containers/detail/flat_tree.hpp | 18 +-- .../containers/detail/node_alloc_holder.hpp | 16 +-- .../interprocess/containers/detail/tree.hpp | 14 +-- .../interprocess/containers/flat_map.hpp | 101 +++++++++------- .../interprocess/containers/flat_set.hpp | 24 ++-- .../boost/interprocess/containers/list.hpp | 35 ++++-- include/boost/interprocess/containers/map.hpp | 50 ++++---- include/boost/interprocess/containers/set.hpp | 24 ++-- .../boost/interprocess/containers/slist.hpp | 14 +-- .../boost/interprocess/containers/string.hpp | 14 +-- .../boost/interprocess/containers/vector.hpp | 16 +-- .../boost/interprocess/detail/algorithms.hpp | 84 ++++++++++++- .../interprocess/detail/file_wrapper.hpp | 2 +- .../detail/managed_memory_impl.hpp | 14 ++- .../detail/managed_multi_shared_memory.hpp | 14 +-- .../detail/managed_open_or_create_impl.hpp | 6 +- .../interprocess/detail/math_functions.hpp | 1 - include/boost/interprocess/detail/move.hpp | 30 +++-- .../interprocess/detail/move_iterator.hpp | 4 +- include/boost/interprocess/detail/mpl.hpp | 1 + .../boost/interprocess/detail/utilities.hpp | 62 +++++++--- .../boost/interprocess/detail/win32_api.hpp | 2 +- .../boost/interprocess/detail/workaround.hpp | 2 + include/boost/interprocess/file_mapping.hpp | 18 ++- .../interprocess/managed_mapped_file.hpp | 29 +++++ .../interprocess/managed_shared_memory.hpp | 32 +++++ .../managed_windows_shared_memory.hpp | 39 ++++++- include/boost/interprocess/mapped_region.hpp | 25 ++-- .../mem_algo/detail/simple_seq_fit_impl.hpp | 14 +-- .../interprocess/mem_algo/rbtree_best_fit.hpp | 6 +- .../boost/interprocess/segment_manager.hpp | 87 +++++++++++--- .../interprocess/shared_memory_object.hpp | 18 ++- .../smart_ptr/detail/shared_count.hpp | 5 + .../smart_ptr/enable_shared_from_this.hpp | 1 - .../interprocess/smart_ptr/shared_ptr.hpp | 74 ++++++++++-- .../interprocess/smart_ptr/unique_ptr.hpp | 28 +++-- .../boost/interprocess/smart_ptr/weak_ptr.hpp | 5 +- .../sync/emulation/interprocess_condition.hpp | 10 +- .../interprocess/sync/math_functions.hpp | 110 ++++++++++++++++++ .../boost/interprocess/sync/scoped_lock.hpp | 17 +-- .../boost/interprocess/sync/sharable_lock.hpp | 18 +-- .../interprocess/sync/upgradable_lock.hpp | 12 +- .../interprocess/windows_shared_memory.hpp | 2 +- 51 files changed, 851 insertions(+), 319 deletions(-) create mode 100644 include/boost/interprocess/sync/math_functions.hpp diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index 7b2ab87..fab13ca 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -69,7 +69,7 @@ class adaptive_pool_base struct node_pool { typedef detail::shared_adaptive_node_pool - < SegmentManager, sizeof(T), NodesPerBlock, MaxFreeBlocks, OverheadPercent> type; + < SegmentManager, sizeof_value::value, NodesPerBlock, MaxFreeBlocks, OverheadPercent> type; static type *get(void *p) { return static_cast(p); } diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index 4247ef6..fc94fb7 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,7 @@ class cached_adaptive_pool_v1 < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock , MaxFreeBlocks , OverheadPercent @@ -59,7 +60,7 @@ class cached_adaptive_pool_v1 < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock , MaxFreeBlocks , OverheadPercent @@ -119,7 +120,7 @@ class cached_adaptive_pool < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(typename detail::if_c::value, int, T>::type) + , sizeof_value::value , NodesPerBlock , MaxFreeBlocks , OverheadPercent @@ -134,7 +135,7 @@ class cached_adaptive_pool < T , detail::shared_adaptive_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock , MaxFreeBlocks , OverheadPercent diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index b220aab..3801dc6 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,7 @@ class cached_node_allocator_v1 < T , detail::shared_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock > , 1> @@ -56,7 +57,7 @@ class cached_node_allocator_v1 < T , detail::shared_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock > , 1> base_t; @@ -95,7 +96,7 @@ class cached_node_allocator < T , detail::shared_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock > , 2> @@ -108,7 +109,7 @@ class cached_node_allocator < T , detail::shared_node_pool < SegmentManager - , sizeof(T) + , sizeof_value::value , NodesPerBlock > , 2> base_t; diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index 9a6c8b5..0ee43c3 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -66,7 +66,7 @@ class node_allocator_base struct node_pool { typedef detail::shared_node_pool - < SegmentManager, sizeof(T), NodesPerBlock> type; + < SegmentManager, sizeof_value::value, NodesPerBlock> type; static type *get(void *p) { return static_cast(p); } diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index b7c63da..c9b4e18 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -67,7 +67,7 @@ class private_adaptive_pool_base , MaxFreeBlocks, OverheadPercent> self_t; typedef detail::private_adaptive_node_pool ::value , NodesPerBlock , MaxFreeBlocks , OverheadPercent @@ -113,7 +113,7 @@ class private_adaptive_pool_base { typedef detail::private_adaptive_node_pool ::value , NodesPerBlock , MaxFreeBlocks , OverheadPercent diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index 284fea2..a7320f1 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -63,7 +63,7 @@ class private_node_allocator_base < Version, T, SegmentManager, NodesPerBlock> self_t; typedef detail::private_node_pool ::value , NodesPerBlock > node_pool_t; @@ -106,7 +106,7 @@ class private_node_allocator_base { typedef detail::private_node_pool ::value , NodesPerBlock > type; diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp index bb89979..3e8a57c 100644 --- a/include/boost/interprocess/anonymous_shared_memory.hpp +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -42,7 +42,13 @@ namespace detail{ class raw_mapped_region_creator { public: - static move_return create_posix_mapped_region(void *address, offset_t offset, std::size_t size) + static + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + mapped_region + #else + move_return + #endif + create_posix_mapped_region(void *address, offset_t offset, std::size_t size) { mapped_region region; region.m_base = address; @@ -61,7 +67,13 @@ namespace detail{ //!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 detail::move_return anonymous_shared_memory(std::size_t size, void *address = 0) +static +#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +mapped_region +#else +detail::move_return +#endif +anonymous_shared_memory(std::size_t size, void *address = 0) #if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) { int flags; @@ -104,7 +116,7 @@ static detail::move_return anonymous_shared_memory(std::size_t si { windows_shared_memory anonymous_mapping(create_only, 0, read_write, size); mapped_region region(anonymous_mapping, read_write, 0, size, address); - return detail::move_return(region); + return region; } #endif diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index 9359db3..d73b501 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -580,7 +580,7 @@ class deque : protected deque_base { this->swap(mx.get()); } #else deque(deque &&x) - : Base(x)) + : Base(detail::move_impl(x)) { this->swap(x); } #endif @@ -679,11 +679,11 @@ class deque : protected deque_base void push_back(value_type &&mt) { if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(detail::move_impl(mt)); ++this->members_.m_finish.m_cur; } else - this->priv_push_back_aux(move(mt)); + this->priv_push_back_aux(detail::move_impl(mt)); } #endif @@ -711,11 +711,11 @@ class deque : protected deque_base void push_front(value_type &&mt) { if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(move(mt)); + new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(detail::move_impl(mt)); --this->members_.m_start.m_cur; } else - this->priv_push_front_aux(move(mt)); + this->priv_push_front_aux(detail::move_impl(mt)); } #endif @@ -777,17 +777,17 @@ class deque : protected deque_base iterator insert(iterator position, value_type &&mx) { if (position.m_cur == this->members_.m_start.m_cur) { - this->push_front(move(mx)); + this->push_front(detail::move_impl(mx)); return this->members_.m_start; } else if (position.m_cur == this->members_.m_finish.m_cur) { - this->push_back(move(mx)); + this->push_back(detail::move_impl(mx)); iterator tmp = this->members_.m_finish; --tmp; return tmp; } else { - return this->priv_insert_aux(position, move(mx)); + return this->priv_insert_aux(position, detail::move_impl(mx)); } } #endif @@ -824,13 +824,13 @@ class deque : protected deque_base this->priv_reserve_elements_at_back(new_size); while(n--){ - //T default_constructed = move(T()); + //T default_constructed = detail::move_impl(T()); T default_constructed; /* if(boost::is_scalar::value){ //Value initialization new(&default_constructed)T(); }*/ - this->push_back(move(default_constructed)); + this->push_back(detail::move_impl(default_constructed)); } } } @@ -1251,7 +1251,7 @@ class deque : protected deque_base this->priv_reserve_map_at_back(); *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); BOOST_TRY { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(detail::move_impl(mt)); 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_first; } @@ -1306,7 +1306,7 @@ class deque : protected deque_base BOOST_TRY { 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_last - 1; - new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(move(mt)); + new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(detail::move_impl(mt)); } BOOST_CATCH(...){ ++this->members_.m_start; diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/detail/flat_tree.hpp index 5901a2f..b4777f2 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/detail/flat_tree.hpp @@ -135,11 +135,11 @@ class flat_tree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_tree(const detail::moved_object &x) - : m_data(move(x.get().m_data)) + : m_data(detail::move_impl(x.get().m_data)) { } #else flat_tree(flat_tree &&x) - : m_data(move(x.m_data)) + : m_data(detail::move_impl(x.m_data)) { } #endif @@ -151,10 +151,10 @@ class flat_tree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_tree& operator=(const detail::moved_object& mx) - { m_data = move(mx.get().m_data); return *this; } + { m_data = detail::move_impl(mx.get().m_data); return *this; } #else flat_tree& operator=(flat_tree &&mx) - { m_data = move(mx.m_data); return *this; } + { m_data = detail::move_impl(mx.m_data); return *this; } #endif public: @@ -250,7 +250,7 @@ class flat_tree insert_commit_data data; std::pair ret = priv_insert_unique_prepare(mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, move(mval)); + ret.first = priv_insert_commit(data, detail::move_impl(mval)); } return ret; } @@ -275,7 +275,7 @@ class flat_tree iterator insert_equal(value_type && mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, move(mval)); + i = this->m_data.m_vect.insert(i, detail::move_impl(mval)); return i; } #endif @@ -306,7 +306,7 @@ class flat_tree insert_commit_data data; std::pair ret = priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, move(mval)); + ret.first = priv_insert_commit(data, detail::move_impl(mval)); } return ret.first; } @@ -331,7 +331,7 @@ class flat_tree { insert_commit_data data; priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, move(mval)); + return priv_insert_commit(data, detail::move_impl(mval)); } #endif @@ -547,7 +547,7 @@ class flat_tree template iterator priv_insert_commit (insert_commit_data &commit_data, Convertible &&convertible) - { return this->m_data.m_vect.insert(commit_data.position, forward(convertible)); } + { return this->m_data.m_vect.insert(commit_data.position, detail::forward_impl(convertible)); } #endif template diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 9f839ba..5eca3fe 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -88,11 +88,11 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE node_alloc_holder(const detail::moved_object &other) - : members_(move(other.get().node_alloc())) + : members_(detail::move_impl(other.get().node_alloc())) { this->swap(other.get()); } #else node_alloc_holder(node_alloc_holder &&other) - : members_(move(other.node_alloc())) + : members_(detail::move_impl(other.node_alloc())) { this->swap(other); } #endif @@ -149,7 +149,7 @@ struct node_alloc_holder #else template static void construct(const NodePtr &ptr, Convertible &&value) - { new((void*)detail::get_pointer(ptr)) Node(forward(value)); } + { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(value)); } #endif static void construct(const NodePtr &ptr) @@ -169,9 +169,9 @@ struct node_alloc_holder new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->m_data; - new((void*)&valueptr->first) first_type(move(value.get().first)); + new((void*)&valueptr->first) first_type(detail::move_impl(value.get().first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(move(value.get().second)); + new((void*)&valueptr->second) second_type(detail::move_impl(value.get().second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -194,9 +194,9 @@ struct node_alloc_holder new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->m_data; - new((void*)&valueptr->first) first_type(move(value.first)); + new((void*)&valueptr->first) first_type(detail::move_impl(value.first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(move(value.second)); + new((void*)&valueptr->second) second_type(detail::move_impl(value.second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -226,7 +226,7 @@ struct node_alloc_holder { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, forward(x)); + self_t::construct(p, detail::forward_impl(x)); node_deallocator.release(); return (p); } diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/detail/tree.hpp index b2e4428..0e042d8 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/detail/tree.hpp @@ -109,7 +109,7 @@ struct rbtree_node #else template rbtree_node(Convertible &&conv) - : m_data(forward(conv)){} + : m_data(detail::forward_impl(conv)){} #endif rbtree_node &operator=(const rbtree_node &other) @@ -153,7 +153,7 @@ struct rbtree_node template static void construct(node_type *ptr, Convertible &&value) - { new(ptr) node_type(forward(value)); } + { new(ptr) node_type(detail::forward_impl(value)); } template static void construct(node_type *ptr, @@ -578,7 +578,7 @@ class rbtree iterator insert_unique_commit (MovableConvertible && mv, insert_commit_data &data) { - NodePtr tmp = AllocHolder::create_node(forward(mv)); + NodePtr tmp = AllocHolder::create_node(detail::forward_impl(mv)); iiterator it(this->icont().insert_unique_commit(*tmp, data)); return iterator(it); } @@ -618,7 +618,7 @@ class rbtree if(!ret.second) return ret; return std::pair - (this->insert_unique_commit(forward(mv), data), true); + (this->insert_unique_commit(detail::forward_impl(mv), data), true); } #endif @@ -654,7 +654,7 @@ class rbtree this->insert_unique_check(hint, KeyOfValue()(mv), data); if(!ret.second) return ret.first; - return this->insert_unique_commit(forward(mv), data); + return this->insert_unique_commit(detail::forward_impl(mv), data); } #endif @@ -691,7 +691,7 @@ class rbtree template iterator insert_equal(MovableConvertible &&mv) { - NodePtr p(AllocHolder::create_node(forward(mv))); + NodePtr p(AllocHolder::create_node(detail::forward_impl(mv))); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } #endif @@ -713,7 +713,7 @@ class rbtree template iterator insert_equal(const_iterator hint, MovableConvertible &&mv) { - NodePtr p(AllocHolder::create_node(move(mv))); + NodePtr p(AllocHolder::create_node(detail::move_impl(mv))); return iterator(this->icont().insert_equal(hint.get(), *p)); } #endif diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 9f713fa..56e265d 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -70,14 +70,6 @@ class flat_map { /// @cond private: - //This is the real tree stored here. It's based on a movable pair - typedef detail::flat_tree, - detail::select1st< detail::pair >, - Pred, - typename Alloc::template - rebind >::other> impl_tree_t; - //This is the tree that we should store if pair was movable typedef detail::flat_tree, @@ -85,7 +77,18 @@ class flat_map Pred, Alloc> tree_t; -// tree_t m_flat_tree; // flat tree representing flat_map + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + //This is the real tree stored here. It's based on a movable pair + typedef detail::flat_tree, + detail::select1st< detail::pair >, + Pred, + typename Alloc::template + rebind >::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; @@ -101,19 +104,23 @@ class flat_map typedef typename impl_tree_t::allocator_type impl_allocator_type; #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE typedef detail::moved_object impl_moved_value_type; - #else - typedef impl_value_type&& impl_moved_value_type; #endif + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static D &force(const S &s) - { return *const_cast((reinterpret_cast(&s))); } + { return *((D*)(void*)(const void*)(&s)); } + #else + //For rvalue-aware compilers, just forward + template + static const Type &force(const Type &t) + { return t; } - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &&force(S &&s) - { return reinterpret_cast(s); } + template + static Type &force(Type &t) + { return t; } #endif + /// @endcond public: @@ -168,11 +175,11 @@ class flat_map //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_map(const detail::moved_object >& x) - : m_flat_tree(move(x.get().m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} #else flat_map(flat_map && x) - : m_flat_tree(move(x.m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} #endif //! Effects: Makes *this a copy of x. @@ -189,10 +196,10 @@ class flat_map //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_map& operator=(const detail::moved_object >& mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_map& operator=(flat_map && mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -315,7 +322,7 @@ class flat_map { return m_flat_tree.max_size(); } //! 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) + //! value_type(detail::move_impl(x), T()) into the flat_map (the key is move-constructed) //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! @@ -342,7 +349,7 @@ class flat_map 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, move(T()))); + i = insert(i, value_type(k, detail::move_impl(T()))); return (*i).second; } #else @@ -358,7 +365,7 @@ class flat_map 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(forward(k), move(T()))); + i = insert(i, value_type(detail::forward_impl(k), detail::move_impl(T()))); return (*i).second; } #endif @@ -418,8 +425,7 @@ class flat_map m_flat_tree.insert_unique(force(x))); } #else std::pair insert(value_type &&x) - { return force >( - m_flat_tree.insert_unique(force(move(x)))); } + { return m_flat_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -452,8 +458,7 @@ class flat_map m_flat_tree.insert_unique(force(position), force(x))); } #else iterator insert(iterator position, value_type &&x) - { return force( - m_flat_tree.insert_unique(force(position), force(move(x)))); } + { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -715,6 +720,12 @@ class flat_multimap { /// @cond private: + typedef detail::flat_tree, + detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE //This is the real tree stored here. It's based on a movable pair typedef detail::flat_tree, @@ -722,13 +733,10 @@ class flat_multimap Pred, typename Alloc::template rebind >::other> impl_tree_t; + #else + typedef tree_t impl_tree_t; + #endif - typedef detail::flat_tree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; -// tree_t m_flat_tree; // flat tree representing flat_multimap impl_tree_t m_flat_tree; // flat tree representing flat_map typedef typename impl_tree_t::value_type impl_value_type; @@ -744,18 +752,21 @@ class flat_multimap typedef typename impl_tree_t::allocator_type impl_allocator_type; #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE typedef detail::moved_object impl_moved_value_type; - #else - typedef impl_value_type&& impl_moved_value_type; #endif + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static D &force(const S &s) { return *const_cast((reinterpret_cast(&s))); } + #else + //For rvalue-aware compilers, just forward + template + static const Type &force(const Type &t) + { return t; } - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &&force(S &&s) - { return reinterpret_cast(s); } + template + static Type &force(Type &t) + { return t; } #endif /// @endcond @@ -812,10 +823,10 @@ class flat_multimap //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multimap(const detail::moved_object >& x) - : m_flat_tree(move(x.get().m_flat_tree)) { } + : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) { } #else flat_multimap(flat_multimap && x) - : m_flat_tree(move(x.m_flat_tree)) { } + : m_flat_tree(detail::move_impl(x.m_flat_tree)) { } #endif //! Effects: Makes *this a copy of x. @@ -831,11 +842,11 @@ class flat_multimap #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multimap& operator=(const detail::moved_object >& mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_multimap& operator=(flat_multimap && mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -1002,7 +1013,7 @@ class flat_multimap { return force(m_flat_tree.insert_equal(force(x))); } #else iterator insert(value_type &&x) - { return force(m_flat_tree.insert_equal(force(move(x)))); } + { return m_flat_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -1035,7 +1046,7 @@ class flat_multimap { return force(m_flat_tree.insert_equal(force(position), force(x))); } #else iterator insert(iterator position, value_type &&x) - { return force(m_flat_tree.insert_equal(force(position), force(move(x)))); } + { return m_flat_tree.insert_equal(force(position), detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index b5db427..e4e3339 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -117,10 +117,10 @@ class flat_set //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_set(const detail::moved_object >& mx) - : m_flat_tree(move(mx.get().m_flat_tree)) {} + : m_flat_tree(detail::move_impl(mx.get().m_flat_tree)) {} #else flat_set(flat_set && mx) - : m_flat_tree(move(mx.m_flat_tree)) {} + : m_flat_tree(detail::move_impl(mx.m_flat_tree)) {} #endif //! Effects: Makes *this a copy of x. @@ -134,11 +134,11 @@ class flat_set //! Complexity: Linear in x.size(). #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_set& operator=(const detail::moved_object > &mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_set& operator=(flat_set &&mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif @@ -314,7 +314,7 @@ class flat_set { return m_flat_tree.insert_unique(x); } #else std::pair insert(value_type && x) - { return m_flat_tree.insert_unique(move(x)); } + { return m_flat_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -345,7 +345,7 @@ class flat_set { return m_flat_tree.insert_unique(position, x); } #else iterator insert(iterator position, value_type && x) - { return m_flat_tree.insert_unique(position, move(x)); } + { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -633,10 +633,10 @@ class flat_multiset #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multiset(const detail::moved_object >& x) - : m_flat_tree(move(x.get().m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} #else flat_multiset(flat_multiset && x) - : m_flat_tree(move(x.m_flat_tree)) {} + : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} #endif flat_multiset& operator=(const flat_multiset& x) @@ -644,10 +644,10 @@ class flat_multiset #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE flat_multiset& operator=(const detail::moved_object >& mx) - { m_flat_tree = move(mx.get().m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_multiset& operator=(flat_multiset && mx) - { m_flat_tree = move(mx.m_flat_tree); return *this; } + { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -814,7 +814,7 @@ class flat_multiset { return m_flat_tree.insert_equal(x); } #else iterator insert(value_type && x) - { return m_flat_tree.insert_equal(move(x)); } + { return m_flat_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -845,7 +845,7 @@ class flat_multiset { return m_flat_tree.insert_equal(position, x); } #else iterator insert(iterator position, value_type && x) - { return m_flat_tree.insert_equal(position, move(x)); } + { return m_flat_tree.insert_equal(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index b9e0801..751408d 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -93,7 +93,7 @@ struct list_node #else template list_node(Convertible &&conv) - : m_data(forward(conv)) + : m_data(detail::forward_impl(conv)) {} #endif @@ -323,7 +323,7 @@ class list {} // list(size_type n) -// : AllocHolder(move(allocator_type())) +// : AllocHolder(detail::move_impl(allocator_type())) // { this->resize(n); } //! Effects: Constructs a list that will use a copy of allocator a @@ -355,11 +355,11 @@ class list //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE list(const detail::moved_object &x) - : AllocHolder(move((AllocHolder&)x.get())) + : AllocHolder(detail::move_impl((AllocHolder&)x.get())) {} #else list(list &&x) - : AllocHolder(move((AllocHolder&)x)) + : AllocHolder(detail::move_impl((AllocHolder&)x)) {} #endif @@ -518,7 +518,7 @@ class list { this->insert(this->begin(), x); } #else void push_front(T &&x) - { this->insert(this->begin(), move(x)); } + { this->insert(this->begin(), detail::move_impl(x)); } #endif //! Effects: Removes the last element from the list. @@ -539,7 +539,7 @@ class list { this->insert(this->end(), x); } #else void push_back (T &&x) - { this->insert(this->end(), move(x)); } + { this->insert(this->end(), detail::move_impl(x)); } #endif //! Effects: Removes the first element from the list. @@ -610,7 +610,7 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - iterator i = this->begin(), iend = this->end(); + iterator iend = this->end(); size_type len = this->size(); if(len > new_size){ @@ -633,15 +633,26 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - iterator i = this->begin(), iend = this->end(); + iterator iend = this->end(); size_type len = this->size(); if(len > new_size){ size_type to_erase = len - new_size; - while(to_erase--){ - --iend; + iterator ifirst; + if(to_erase < len/2u){ + ifirst = iend; + while(to_erase--){ + --ifirst; + } } - this->erase(iend, this->end()); + 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->end(), new_size - len); @@ -763,7 +774,7 @@ class list #else iterator insert(iterator p, T &&x) { - NodePtr tmp = AllocHolder::create_node(move(x)); + NodePtr tmp = AllocHolder::create_node(detail::move_impl(x)); return iterator(this->icont().insert(p.get(), *tmp)); } #endif diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index 575c633..bfd6333 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -8,7 +8,7 @@ // ////////////////////////////////////////////////////////////////////////////// // -// This file comes from SGI's stl_map/stl_multimap files. Modified by Ion Gazta�ga 2004. +// 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. // @@ -166,11 +166,11 @@ class map //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE map(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else map(map &&x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -185,10 +185,10 @@ class map //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE map& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else map& operator=(map &&x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -322,14 +322,14 @@ class map 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, move(T())); - i = insert(i, move(val)); + value_type val(k, detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(move(x), T()) into the map (the key is move-constructed) + //! value_type(detail::move_impl(x), T()) into the map (the key is move-constructed) //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! @@ -342,8 +342,8 @@ class map 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, move(T())); - i = insert(i, move(val)); + value_type val(k, detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } @@ -355,8 +355,8 @@ class map 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(move(k), move(T())); - i = insert(i, move(val)); + value_type val(detail::move_impl(k), detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } @@ -364,7 +364,7 @@ class map /* //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(move(x), T()) into the map (the key is move-constructed) + //! value_type(detail::move_impl(x), T()) into the map (the key is move-constructed) //! //! Returns: A reference to the mapped_type corresponding to x in *this. //! @@ -379,8 +379,8 @@ class map 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, move(T())); - i = insert(i, move(val)); + value_type val(k, detail::move_impl(T())); + i = insert(i, detail::move_impl(val)); } return (*i).second; } @@ -449,7 +449,7 @@ class map { return m_tree.insert_unique(x); } #else std::pair insert(std::pair &&x) - { return m_tree.insert_unique(move(x)); } + { return m_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Move constructs a new value from x if and only if there is @@ -465,7 +465,7 @@ class map { return m_tree.insert_unique(x); } #else std::pair insert(value_type &&x) - { return m_tree.insert_unique(move(x)); } + { return m_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -494,7 +494,7 @@ class map { return m_tree.insert_unique(position, x); } #else iterator insert(iterator position, std::pair &&x) - { return m_tree.insert_unique(position, move(x)); } + { return m_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -517,7 +517,7 @@ class map { return m_tree.insert_unique(position, x); } #else iterator insert(iterator position, value_type &&x) - { return m_tree.insert_unique(position, move(x)); } + { return m_tree.insert_unique(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -813,11 +813,11 @@ class multimap //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multimap(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else multimap(multimap && x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -834,11 +834,11 @@ class multimap #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multimap& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else multimap& operator=(multimap && x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -1006,7 +1006,7 @@ class multimap { return m_tree.insert_equal(x); } #else iterator insert(std::pair && x) - { return m_tree.insert_equal(move(x)); } + { return m_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -1044,7 +1044,7 @@ class multimap { return m_tree.insert_equal(position, x); } #else iterator insert(iterator position, std::pair && x) - { return m_tree.insert_equal(position, move(x)); } + { return m_tree.insert_equal(position, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index cb0443b..a0a3a52 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -143,11 +143,11 @@ class set //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE set(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else set(set &&x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -162,10 +162,10 @@ class set //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE set& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else set& operator=(set &&x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -334,7 +334,7 @@ class set { return m_tree.insert_unique(x); } #else std::pair insert(value_type &&x) - { return m_tree.insert_unique(move(x)); } + { return m_tree.insert_unique(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -360,7 +360,7 @@ class set { return m_tree.insert_unique(p, x); } #else iterator insert(const_iterator p, value_type &&x) - { return m_tree.insert_unique(p, move(x)); } + { return m_tree.insert_unique(p, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. @@ -632,11 +632,11 @@ class multiset //! Postcondition: x is emptied. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multiset(const detail::moved_object >& x) - : m_tree(move(x.get().m_tree)) + : m_tree(detail::move_impl(x.get().m_tree)) {} #else multiset(multiset &&x) - : m_tree(move(x.m_tree)) + : m_tree(detail::move_impl(x.m_tree)) {} #endif @@ -651,10 +651,10 @@ class multiset //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE multiset& operator=(const detail::moved_object >& x) - { m_tree = move(x.get().m_tree); return *this; } + { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else multiset& operator=(multiset &&x) - { m_tree = move(x.m_tree); return *this; } + { m_tree = detail::move_impl(x.m_tree); return *this; } #endif //! Effects: Returns the comparison object out @@ -818,7 +818,7 @@ class multiset { return m_tree.insert_equal(x); } #else iterator insert(value_type && x) - { return m_tree.insert_equal(move(x)); } + { return m_tree.insert_equal(detail::move_impl(x)); } #endif //! Effects: Inserts a copy of x in the container. @@ -845,7 +845,7 @@ class multiset { return m_tree.insert_equal(p, x); } #else iterator insert(const_iterator p, value_type && x) - { return m_tree.insert_equal(p, move(x)); } + { return m_tree.insert_equal(p, detail::move_impl(x)); } #endif //! Requires: i, j are not iterators into *this. diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 3424175..ecf60a5 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -87,7 +87,7 @@ struct slist_node #else template slist_node(Convertible &&value) - : m_data(forward(value)){} + : m_data(detail::forward_impl(value)){} #endif T m_data; @@ -321,7 +321,7 @@ class slist {} // explicit slist(size_type n) -// : AllocHolder(move(allocator_type())) +// : AllocHolder(detail::move_impl(allocator_type())) // { this->resize(n); } //! Effects: Constructs a list that will use a copy of allocator a @@ -367,11 +367,11 @@ class slist //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE slist(const detail::moved_object &x) - : AllocHolder(move((AllocHolder&)x.get())) + : AllocHolder(detail::move_impl((AllocHolder&)x.get())) {} #else slist(slist &&x) - : AllocHolder(move((AllocHolder&)x)) + : AllocHolder(detail::move_impl((AllocHolder&)x)) {} #endif @@ -594,7 +594,7 @@ class slist { this->icont().push_front(*this->create_node(x)); } #else void push_front(T && x) - { this->icont().push_front(*this->create_node(move(x))); } + { this->icont().push_front(*this->create_node(detail::move_impl(x))); } #endif //! Effects: Removes the first element from the list. @@ -659,7 +659,7 @@ class slist { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } #else iterator insert_after(iterator prev_pos, value_type && x) - { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(move(x)))); } + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(detail::move_impl(x)))); } #endif //! Requires: prev_pos must be a valid iterator of *this. @@ -717,7 +717,7 @@ class slist { return this->insert_after(previous(p), x); } #else iterator insert(iterator p, value_type && x) - { return this->insert_after(previous(p), move(x)); } + { return this->insert_after(previous(p), detail::move_impl(x)); } #endif //! Requires: p must be a valid iterator of *this. diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index c1d0c90..2be6993 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -281,7 +281,7 @@ class basic_string_base (void)limit_size; (void)reuse; if(!(command & allocate_new)) - return std::pair(0, 0); + return std::pair(pointer(0), 0); received_size = preferred_size; return std::make_pair(this->alloc().allocate(received_size), false); } @@ -551,11 +551,11 @@ class basic_string //! Complexity: Constant. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE basic_string(const detail::moved_object& s) - : base_t(move((base_t&)s.get())) + : base_t(detail::move_impl((base_t&)s.get())) {} #else basic_string(basic_string && s) - : base_t(move((base_t&)s)) + : base_t(detail::move_impl((base_t&)s)) {} #endif @@ -1940,7 +1940,7 @@ operator+(basic_string && mx, const basic_string& y) { mx += y; - return move(mx); + return detail::move_impl(mx); } #endif @@ -1994,7 +1994,7 @@ operator+(const CharT* s, basic_string && my) { typedef typename basic_string::size_type size_type; - return move(my.get().replace(size_type(0), size_type(0), s)); + return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); } #endif @@ -2061,7 +2061,7 @@ operator+(basic_string && mx, const CharT* s) { mx += s; - return move(mx); + return detail::move_impl(mx); } #endif @@ -2093,7 +2093,7 @@ basic_string && operator+(basic_string && mx, const CharT c) { mx += c; - return move(mx); + return detail::move_impl(mx); } #endif diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 1b6aabc..2663a61 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -288,7 +288,7 @@ struct vector_alloc_holder (void)limit_size; (void)reuse; if(!(command & allocate_new)) - return std::pair(0, 0); + return std::pair(pointer(0), 0); received_size = preferred_size; return std::make_pair(this->alloc().allocate(received_size), false); } @@ -491,7 +491,7 @@ class vector : private detail::vector_alloc_holder { this->swap(mx.get()); } #else vector(vector && mx) - : base_t(mx) + : base_t(detail::move_impl(mx)) { this->swap(mx); } #endif @@ -890,11 +890,11 @@ class vector : private detail::vector_alloc_holder { 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(move(mx)); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(detail::move_impl(mx)); ++this->members_.m_size; } else{ - this->insert(this->end(), move(mx)); + this->insert(this->end(), detail::move_impl(mx)); } } #endif @@ -1719,8 +1719,9 @@ class vector : private detail::vector_alloc_holder //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 = boost::interprocess::n_uninitialized_copy_n + boost::interprocess::uninitialized_copy_n (first, first_count, detail::get_pointer(ret.first)); + FwdIt mid = first + first_count; if(old_offset > n){ //All old elements will be destroyed by "old_values_destroyer" @@ -1734,12 +1735,13 @@ class vector : private detail::vector_alloc_holder this->members_.m_size = first_count + old_size; //Now overwrite the old values size_type second_count = min_value(old_size, n - first_count); - mid = copy_n(mid, second_count, old_start); + copy_n(mid, second_count, old_start); + mid += second_count; //Check if we still have to append elements in the //uninitialized end if(second_count == old_size){ - boost::interprocess::n_uninitialized_copy_n + boost::interprocess::uninitialized_copy_n ( mid , n - first_count - second_count , old_start + old_size); diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index ed61264..9538c46 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -20,8 +20,12 @@ #include #include #include -#include +#include +#include +#include #include +#include +#include namespace boost { namespace interprocess { @@ -62,18 +66,67 @@ inline void construct_in_place(T *dest, default_construct_iterator) } template -InIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) +struct optimize_assign +{ + static const bool value = false; +}; + +template +struct optimize_assign +{ + static const bool value = boost::has_trivial_assign::value; +}; + +template +struct optimize_assign + : public optimize_assign +{}; + +template +struct optimize_copy +{ + static const bool value = false; +}; + +template +struct optimize_copy +{ + static const bool value = boost::has_trivial_copy::value; +}; + +template +struct optimize_copy + : public optimize_copy +{}; + + +template inline +OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, detail::bool_) { for (; length--; ++dest, ++first) *dest = *first; - return first; + return dest; +} + +template inline +T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +{ + std::size_t size = length*sizeof(T); + return ((T*)std::memmove(dest, first, size)) + size; +} + +template inline +OutIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) +{ + const bool do_optimized_assign = optimize_assign::value; + return copy_n_dispatch(first, length, dest, detail::bool_()); } template inline -InIt n_uninitialized_copy_n +FwdIt uninitialized_copy_n_dispatch (InIt first, typename std::iterator_traits::difference_type count, - FwdIt dest) + FwdIt dest, detail::bool_) { typedef typename std::iterator_traits::value_type value_type; //Save initial destination position @@ -95,9 +148,28 @@ InIt n_uninitialized_copy_n BOOST_RETHROW } BOOST_CATCH_END - return first; + return dest; } + +template inline +T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +{ + std::size_t size = length*sizeof(T); + return ((T*)std::memmove(dest, first, size)) + size; +} + +template inline +FwdIt uninitialized_copy_n + (InIt first, + typename std::iterator_traits::difference_type count, + FwdIt dest) +{ + const bool do_optimized_copy = optimize_copy::value; + return uninitialized_copy_n_dispatch(first, count, dest, detail::bool_()); +} + + // uninitialized_copy_copy // Copies [first1, last1) into [result, result + (last1 - first1)), and // copies [first2, last2) into diff --git a/include/boost/interprocess/detail/file_wrapper.hpp b/include/boost/interprocess/detail/file_wrapper.hpp index ca2d3e6..22f92e9 100644 --- a/include/boost/interprocess/detail/file_wrapper.hpp +++ b/include/boost/interprocess/detail/file_wrapper.hpp @@ -72,7 +72,7 @@ class file_wrapper #else file_wrapper &operator=(file_wrapper &&moved) { - file_wrapper tmp(move(moved)); + file_wrapper tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index c659d9d..fee200e 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -94,6 +94,8 @@ class basic_managed_memory_impl /// @cond + typedef typename + segment_manager::char_ptr_holder_t char_ptr_holder_t; //Experimental. Don't use. typedef typename segment_manager::multiallocation_iterator multiallocation_iterator; @@ -105,9 +107,6 @@ class basic_managed_memory_impl private: typedef basic_managed_memory_impl self_t; - typedef typename - segment_manager::char_ptr_holder_t char_ptr_holder_t; - protected: template static bool grow(const char *filename, std::size_t extra_bytes) @@ -687,6 +686,15 @@ class basic_managed_memory_impl get_deleter() { return mp_header->get_deleter(); } + /// @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 + std::pair find_no_lock (char_ptr_holder_t name) + { return mp_header->template find_no_lock(name); } + /// @endcond + protected: //!Swaps the segment manager's managed by this managed memory segment. //!NOT thread-safe. Never throws. diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp index cead8b5..03aaa85 100644 --- a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -117,7 +117,7 @@ class basic_managed_multi_shared_memory shmem_list_t::value_type &m_impl = *mp_frontend->m_shmem_list.rbegin(); return result_type(m_impl.get_real_address(), m_impl.get_real_size()-1); } - return result_type(0, 0); + return result_type((void *)0, 0); } virtual bool update_segments () @@ -174,8 +174,8 @@ class basic_managed_multi_shared_memory //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)){ + if((impl_done = created ? + mp_frontend->create_impl(addr, size) : mp_frontend->open_impl(addr, size))){ return true; } } @@ -315,21 +315,21 @@ class basic_managed_multi_shared_memory case create_open_func::DoCreate: { managed_impl shm(create_only, name, size, read_write, addr, func); - mshm = move(shm); + mshm = detail::move_impl(shm); } break; case create_open_func::DoOpen: { managed_impl shm(open_only, name,read_write, addr, func); - mshm = move(shm); + mshm = detail::move_impl(shm); } break; case create_open_func::DoOpenOrCreate: { managed_impl shm(open_or_create, name, size, read_write, addr, func); - mshm = move(shm); + mshm = detail::move_impl(shm); } break; @@ -339,7 +339,7 @@ class basic_managed_multi_shared_memory } //This can throw. - m_shmem_list.push_back(move(mshm)); + m_shmem_list.push_back(detail::move_impl(mshm)); return true; } BOOST_CATCH(const std::bad_alloc&){ diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index 9ce306c..2f498b4 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -176,7 +176,7 @@ class managed_open_or_create_impl #else managed_open_or_create_impl &operator=(managed_open_or_create_impl &&moved) { - managed_open_or_create_impl tmp(move(moved)); + managed_open_or_create_impl tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -209,6 +209,10 @@ class managed_open_or_create_impl 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 diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 9aaf686..f1faf80 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -16,7 +16,6 @@ #ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP #define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP -#include #include namespace boost { diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index 7e0c549..6159df9 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include //!\file //!Describes a function and a type to emulate move semantics. @@ -106,16 +108,25 @@ struct return_type namespace boost { namespace interprocess { +namespace detail{ + //!A function that converts an object to a moved object so that //!it can match a function taking a detail::moved_object object. template -typename detail::move_type::type move - (const Object &object) +typename detail::move_type::type move_impl(const Object &object) { typedef typename detail::move_type::type type; return type(object); } +} //namespace detail { + +//!A function that converts an object to a moved object so that +//!it can match a function taking a detail::moved_object object. +template +typename detail::move_type::type move(const Object &object) +{ return detail::move_impl(object); } + } //namespace interprocess { } //namespace boost { @@ -126,15 +137,20 @@ typename detail::move_type::type move namespace boost { namespace interprocess { +namespace detail { + template -inline typename detail::remove_reference::type&& -move(T&& t) +inline typename detail::remove_reference::type&& move_impl(T&& t) { return t; } template -inline -T&& -forward(typename identity::type&& t) +inline T&& forward_impl(typename detail::identity::type&& t) +{ return t; } + +} //namespace detail { + +template +inline typename detail::remove_reference::type&& move(T&& t) { return t; } } //namespace interprocess { diff --git a/include/boost/interprocess/detail/move_iterator.hpp b/include/boost/interprocess/detail/move_iterator.hpp index 83af256..4c9f282 100644 --- a/include/boost/interprocess/detail/move_iterator.hpp +++ b/include/boost/interprocess/detail/move_iterator.hpp @@ -53,7 +53,7 @@ class move_iterator reference operator*() const #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - { return move(*m_it); } + { return detail::move_impl(*m_it); } #else { return *m_it; } #endif @@ -86,7 +86,7 @@ class move_iterator { m_it -= n; return *this; } reference operator[](difference_type n) const - { return move(m_it[n]); } + { return detail::move_impl(m_it[n]); } private: It m_it; diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index 1c100c5..dfdd38c 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -117,6 +117,7 @@ template struct identity // : public std::unary_function { + typedef T type; const T& operator()(const T& x) const { return x; } }; diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index d188e9a..f4043de 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -526,61 +526,61 @@ struct pair #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object >& p) - : first(move(p.get().first)), second(move(p.get().second)) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else template pair(std::pair && p) - : first(move(p.first)), second(move(p.second)) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object >& p) - : first(move(p.get().first)), second(move(p.get().second)) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else template pair(pair && p) - : first(move(p.first)), second(move(p.second)) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object &x, const detail::moved_object &y) - : first(move(x.get())), second(move(y.get())) + : first(detail::move_impl(x.get())), second(detail::move_impl(y.get())) {} #else template pair(U &&x, V &&y) - : first(move(x)), second(move(y)) + : first(detail::move_impl(x)), second(detail::move_impl(y)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE pair(const detail::moved_object &p) - : first(move(p.get().first)), second(move(p.get().second)) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else pair(pair &&p) - : first(move(p.first)), second(move(p.second)) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) {} #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE pair& operator=(const detail::moved_object &p) { - first = move(p.get().first); - second = move(p.get().second); + first = detail::move_impl(p.get().first); + second = detail::move_impl(p.get().second); return *this; } #else pair& operator=(pair &&p) { - first = move(p.first); - second = move(p.second); + first = detail::move_impl(p.first); + second = detail::move_impl(p.second); return *this; } #endif @@ -596,16 +596,16 @@ struct pair template pair& operator=(const detail::moved_object > &p) { - first = move(p.get().first); - second = move(p.get().second); + first = detail::move_impl(p.get().first); + second = detail::move_impl(p.get().second); return *this; } #else template pair& operator=(std::pair &&p) { - first = move(p.first); - second = move(p.second); + first = detail::move_impl(p.first); + second = detail::move_impl(p.second); return *this; } #endif @@ -785,6 +785,36 @@ class value_eraser bool m_erase; }; +template +struct sizeof_value +{ + static const std::size_t value = sizeof(T); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index b6771d0..b07910d 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -225,7 +225,7 @@ extern "C" __declspec(dllimport) void * __stdcall OpenSemaphoreA(unsigned long, 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 _SECURITY_ATTRIBUTES*, unsigned long, unsigned long, void *); +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) void __stdcall GetSystemInfo (struct system_info *); extern "C" __declspec(dllimport) int __stdcall FlushViewOfFile (void *, std::size_t); diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index b22e283..1bc1b3a 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -13,6 +13,8 @@ #include +#undef BOOST_DISABLE_WIN32 + #if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) #include diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index 8ddebef..28b3662 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -79,7 +79,7 @@ class file_mapping #else file_mapping &operator=(file_mapping &&moved) { - file_mapping tmp(move(moved)); + file_mapping tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -180,6 +180,22 @@ struct is_movable ///@endcond +//!A class that stores the name of a 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 { diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index eda6b90..be3a15a 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace boost { namespace interprocess { @@ -54,6 +55,9 @@ class basic_managed_mapped_file 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 @@ -102,6 +106,16 @@ class basic_managed_mapped_file 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 #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE @@ -168,6 +182,21 @@ class basic_managed_mapped_file } /// @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 + std::pair find (char_ptr_holder_t name) + { + if(m_mfile.get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + private: managed_open_or_create_type m_mfile; /// @endcond diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index d66b2be..21d9b5b 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -57,6 +57,9 @@ class basic_managed_shared_memory basic_managed_shared_memory *get_this_pointer() { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; /// @endcond public: //functions @@ -108,6 +111,17 @@ class basic_managed_shared_memory 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, @@ -168,6 +182,24 @@ class basic_managed_shared_memory return base_t::template shrink_to_fit (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 + std::pair find (char_ptr_holder_t name) + { + if(base2_t::get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + + /// @endcond }; ///@cond diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index 1623225..805a481 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -57,6 +57,9 @@ class basic_managed_windows_shared_memory basic_managed_windows_shared_memory *get_this_pointer() { return this; } + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; /// @endcond public: //functions @@ -90,8 +93,8 @@ class basic_managed_windows_shared_memory //!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) + 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)) @@ -100,11 +103,20 @@ class basic_managed_windows_shared_memory //!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) + 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)) + 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. @@ -146,6 +158,21 @@ class basic_managed_windows_shared_memory 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 + std::pair find (char_ptr_holder_t name) + { + if(m_wshm.get_mapped_region().get_mode() == read_only){ + return base_t::template find_no_lock(name); + } + else{ + return base_t::template find(name); + } + } + private: detail::managed_open_or_create_impl m_wshm; /// @endcond diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index d7527cd..dad831e 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -109,6 +109,10 @@ class mapped_region //!mapped memory. Never throws. offset_t get_offset() const; + //!Returns the mode of the mapping used to contruct 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); @@ -137,6 +141,7 @@ class mapped_region std::size_t m_size; offset_t m_offset; offset_t m_extra_offset; + mode_t m_mode; #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) file_handle_t m_file_mapping_hnd; #endif @@ -164,16 +169,19 @@ inline mapped_region::~mapped_region() inline std::size_t mapped_region::get_size() const { return m_size; } -inline offset_t mapped_region::get_offset() const +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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) inline mapped_region::mapped_region() - : m_base(0), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(0), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) , m_file_mapping_hnd(detail::invalid_file()) {} @@ -181,12 +189,14 @@ inline mapped_region::mapped_region() inline mapped_region::mapped_region(detail::moved_object 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.get()); } #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 @@ -206,7 +216,7 @@ inline mapped_region::mapped_region ,offset_t offset ,std::size_t size ,const void *address) - : m_base(0), m_size(0), m_offset(0), m_extra_offset(0) + : 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(); @@ -378,16 +388,16 @@ inline void mapped_region::dont_close_on_destruction() #else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) inline mapped_region::mapped_region() - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) {} #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE inline mapped_region::mapped_region(detail::moved_object other) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) { this->swap(other.get()); } #else inline mapped_region::mapped_region(mapped_region &&other) - : m_base(MAP_FAILED), m_size(0), m_offset(0) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_mode(read_only) , m_extra_offset(0) { this->swap(other); } #endif @@ -403,7 +413,7 @@ inline mapped_region::mapped_region 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_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode) { if(size == 0){ // offset_t filesize = lseek64 @@ -540,6 +550,7 @@ inline void mapped_region::swap(mapped_region &other) 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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) detail::do_swap(this->m_file_mapping_hnd, other.m_file_mapping_hnd); #endif diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index f011528..3898d5f 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -577,7 +577,7 @@ inline std::pair simple_seq_fit_impl:: void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) - return std::pair(0, 0); + return std::pair((void*)0, 0); if(command & try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object @@ -596,7 +596,7 @@ inline std::pair simple_seq_fit_impl:: void *reuse_ptr, std::size_t sizeof_object) { command &= ~expand_bwd; - if(!command) return std::pair(0, false); + if(!command) return std::pair((void*)0, false); std::pair ret; std::size_t max_count = m_header.m_size/sizeof_object; @@ -769,7 +769,7 @@ std::pair simple_seq_fit_impl:: received_size = 0; if(limit_size > preferred_size) - return return_type(0, false); + return return_type((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; @@ -819,7 +819,7 @@ std::pair simple_seq_fit_impl:: 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(0, false); + return return_type((void*)0, false); received_size = biggest_block->m_size*Alignment - BlockCtrlUnits; void *ret = this->priv_check_and_allocate @@ -836,7 +836,7 @@ std::pair simple_seq_fit_impl:: algo_impl_t::assert_alignment(ret.first); return ret; } - return return_type(0, false); + return return_type((void*)0, false); } template inline @@ -888,13 +888,13 @@ inline } if(prev_block == root || !prev_block->m_next) - return prev_pair_t(0, 0); + return prev_pair_t((block_ctrl*)0, (block_ctrl*)0); //Check if the previous block is in the managed segment std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment; if(distance >= (m_header.m_size/Alignment)){ //"previous_block" does not exist so we can't expand "block" - return prev_pair_t(0, 0); + return prev_pair_t((block_ctrl*)0, (block_ctrl*)0); } return prev_pair_t(prev_2_block, prev_block); } diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 5e1f8ef..f24db2d 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -664,7 +664,7 @@ inline std::pair rbtree_best_fit(0, 0); + return std::pair((void *)0, 0); if(command & try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object @@ -930,7 +930,7 @@ std::pair rbtree_best_fit: received_size = 0; if(limit_size > preferred_size) - return return_type(0, false); + return return_type((void*)0, false); //Number of units to request (including block_ctrl header) std::size_t preferred_units = priv_get_total_units(preferred_size); @@ -969,7 +969,7 @@ std::pair rbtree_best_fit: (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); } - return return_type(0, false); + return return_type((void*)0, false); } template diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index 51a0e0e..545cf5d 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include //std::size_t #include //char_traits #include //std::nothrow @@ -292,7 +294,7 @@ class segment_manager_base block_header_t *ctrl_data = block_header_t::block_header_from_value(object, table.size, table.alignment); //------------------------------- - //boost::interprocess::scoped_lock guard(m_header); + //scoped_lock guard(m_header); //------------------------------- if(ctrl_data->allocation_type() != anonymous_type){ @@ -423,10 +425,10 @@ class segment_manager void *ret; if(name == reinterpret_cast(-1)){ - ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t()); + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), true); } else{ - ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t()); + ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), true); } return std::pair(static_cast(ret), size); } @@ -439,7 +441,7 @@ class segment_manager { detail::placement_destroy table; std::size_t size; - void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t()); + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), true); return std::pair(static_cast(ret), size); } @@ -502,7 +504,7 @@ class segment_manager //!executing the object function call*/ template void atomic_func(Func &f) - { boost::interprocess::scoped_lock guard(m_header); f(); } + { scoped_lock guard(m_header); f(); } //!Destroys a previously created unique instance. //!Returns false if the object was not present. @@ -559,7 +561,7 @@ class segment_manager void reserve_named_objects(std::size_t num) { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- m_header.m_named_index.reserve(num); } @@ -570,7 +572,7 @@ class segment_manager void reserve_unique_objects(std::size_t num) { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- m_header.m_unique_index.reserve(num); } @@ -580,7 +582,7 @@ class segment_manager void shrink_to_fit_indexes() { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- m_header.m_named_index.shrink_to_fit(); m_header.m_unique_index.shrink_to_fit(); @@ -591,7 +593,7 @@ class segment_manager std::size_t get_num_named_objects() { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- return m_header.m_named_index.size(); } @@ -601,7 +603,7 @@ class segment_manager std::size_t get_num_unique_objects() { //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- return m_header.m_unique_index.size(); } @@ -688,6 +690,39 @@ class segment_manager (priv_generic_construct(name, num, try2find, dothrow, table)); } + //!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 + std::pair find_no_lock (const CharType* name) + { + //The name can't be null, no anonymous object can be found by name + assert(name != 0); + detail::placement_destroy table; + std::size_t size; + void *ret; + + if(name == reinterpret_cast(-1)){ + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), false); + } + else{ + ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), false); + } + return std::pair(static_cast(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 + std::pair find_no_lock (const detail::unique_instance_t* name) + { + detail::placement_destroy table; + std::size_t size; + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), false); + return std::pair(static_cast(ret), size); + } + private: void *priv_generic_construct(const CharType *name, std::size_t num, @@ -790,7 +825,8 @@ class segment_manager IndexType > &index, detail::in_place_interface &table, std::size_t &length, - detail::true_ is_intrusive) + detail::true_ is_intrusive, + bool use_lock) { (void)is_intrusive; typedef IndexType > index_type; @@ -798,7 +834,7 @@ class segment_manager typedef typename index_type::iterator index_it; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(priv_get_lock(use_lock)); //------------------------------- //Find name in index detail::intrusive_compare_key key @@ -829,7 +865,8 @@ class segment_manager IndexType > &index, detail::in_place_interface &table, std::size_t &length, - detail::false_ is_intrusive) + detail::false_ is_intrusive, + bool use_lock) { (void)is_intrusive; typedef IndexType > index_type; @@ -837,7 +874,7 @@ class segment_manager typedef typename index_type::iterator index_it; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(priv_get_lock(use_lock)); //------------------------------- //Find name in index index_it it = index.find(key_type(name, std::char_traits::length(name))); @@ -900,7 +937,7 @@ class segment_manager typedef typename index_type::value_type intrusive_value_type; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Find name in index detail::intrusive_compare_key key @@ -950,7 +987,7 @@ class segment_manager typedef typename index_type::key_type key_type; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Try to find the name in the index index_it it = index.find(key_type (name, @@ -1038,7 +1075,7 @@ class segment_manager typedef std::pair index_ib; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Insert the node. This can throw. //First, we want to know if the key is already present before @@ -1164,7 +1201,7 @@ class segment_manager typedef std::pair index_ib; //------------------------------- - boost::interprocess::scoped_lock guard(m_header); + scoped_lock guard(m_header); //------------------------------- //Insert the node. This can throw. //First, we want to know if the key is already present before @@ -1272,6 +1309,20 @@ class segment_manager typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + scoped_lock + #else + detail::move_return > + #endif + priv_get_lock(bool use_lock) + { + scoped_lock local(m_header, defer_lock); + if(use_lock){ + local.lock(); + } + return local; + } + //!This struct includes needed data and derives from //!rmutex to allow EBO when using null interprocess_mutex struct header_t diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index ffae736..6bdc3ea 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -99,7 +99,7 @@ class shared_memory_object #else shared_memory_object &operator=(shared_memory_object &&moved) { - shared_memory_object tmp(move(moved)); + shared_memory_object tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } @@ -355,6 +355,22 @@ struct is_movable ///@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 { diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 3c48eda..8e4db51 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -72,6 +72,11 @@ class shared_count : m_px(0), m_pi(0) // nothrow {} + template + shared_count(const shared_count &other_shared_count, const Ptr &p) + : m_px(p), m_pi(other_shared_count.m_pi) + {} + template shared_count(const Ptr &p, const VoidAllocator &a, Deleter d) : m_px(p), m_pi(0) diff --git a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp index 6863bbd..b984b8b 100644 --- a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp +++ b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp @@ -60,7 +60,6 @@ class enable_shared_from_this return p; } - private: /// @cond typedef T element_type; mutable weak_ptr _internal_weak_this; diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index 9566224..fa272aa 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -47,19 +48,21 @@ namespace detail{ template inline void sp_enable_shared_from_this - (shared_count const & pn, - const typename pointer_to_other ::pointer, - enable_shared_from_this >::type &pe, - const typename shared_count::pointer &px) + (shared_count const & pn + ,enable_shared_from_this *pe + ,T *ptr) + { - if(pe != 0) + (void)ptr; + if(pe != 0){ pe->_internal_weak_this._internal_assign(pn); + } } -/* + template inline void sp_enable_shared_from_this(shared_count const &, ...) {} -*/ + } // namespace detail //!shared_ptr stores a pointer to a dynamically allocated object. @@ -122,9 +125,17 @@ class shared_ptr typedef typename detail::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); - //detail::sp_enable_shared_from_this( m_pn, p, p ); + detail::sp_enable_shared_from_this( 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 @@ -139,6 +150,19 @@ class shared_ptr : 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. + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + explicit shared_ptr(detail::moved_object other) + : m_pn() + { this->swap(other.get()); } + #else + explicit shared_ptr(shared_ptr &&other) + : m_pn() + { this->swap(other); } + #endif + /// @cond template shared_ptr(shared_ptr const & r, detail::static_cast_tag) @@ -172,6 +196,22 @@ class shared_ptr return *this; } + //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). + //!Never throws + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + shared_ptr & operator=(detail::moved_object 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() @@ -192,6 +232,12 @@ class shared_ptr this_type(p, a, d).swap(*this); } + template + void reset(shared_ptr const & r, const pointer &p) + { + this_type(r, p).swap(*this); + } + //!Returns a reference to the //!pointed type reference operator* () const // never throws @@ -333,6 +379,18 @@ typename detail::pointer_to_other, Deleter get_deleter(shared_ptr const & p) { return static_cast(p._internal_get_deleter(typeid(Deleter))); } */ + +/// @cond + +//!This class has move constructor +template +struct is_movable > +{ + enum { value = true }; +}; + +/// @endcond + } // namespace interprocess /// @cond diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index 70fc9e2..ca5f1bd 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -142,7 +142,7 @@ class unique_ptr //! //!After the construction, u no longer owns a pointer. //![ Note: The deleter constructor can be implemented with - //!std::forward. -end note ] + //!std::detail::forward_impl. -end note ] //! //!Postconditions: get() == value u.get() had before the construction. //!get_deleter() returns a reference to the internally stored deleter which @@ -152,11 +152,11 @@ class unique_ptr //!Throws: nothing. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE unique_ptr(detail::moved_object u) - : ptr_(u.get().release(), move(u.get().get_deleter())) + : ptr_(u.get().release(), detail::move_impl(u.get().get_deleter())) {} #else unique_ptr(unique_ptr &&u) - : ptr_(u.release(), forward(u.get_deleter())) + : ptr_(u.release(), detail::forward_impl(u.get_deleter())) {} #endif @@ -192,12 +192,12 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u.get()).release(), move(u.get().get_deleter())) + : ptr_(const_cast&>(u.get()).release(), detail::move_impl(u.get().get_deleter())) {} #else template unique_ptr(unique_ptr && u, - typename boost::enable_if_c< + typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && ( @@ -207,7 +207,7 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u).release(), forward(u.get_deleter())) + : ptr_(const_cast&>(u).release(), detail::forward_impl(u.get_deleter())) {} #endif @@ -234,14 +234,14 @@ class unique_ptr unique_ptr& operator=(detail::moved_object u) { reset(u.get().release()); - ptr_.second() = move(u.get().get_deleter()); + ptr_.second() = detail::move_impl(u.get().get_deleter()); return *this; } #else - unique_ptr(unique_ptr && u) + unique_ptr& operator=(unique_ptr && u) { reset(u.release()); - ptr_.second() = move(u.get_deleter()); + ptr_.second() = detail::move_impl(u.get_deleter()); return *this; } #endif @@ -265,14 +265,14 @@ class unique_ptr unique_ptr& operator=(detail::moved_object > mu) { reset(mu.get().release()); - ptr_.second() = move(mu.get().get_deleter()); + ptr_.second() = detail::move_impl(mu.get().get_deleter()); return *this; } #else - unique_ptr(unique_ptr && u) + unique_ptr& operator=(unique_ptr && u) { reset(u.release()); - ptr_.second() = move(u.get_deleter()); + ptr_.second() = detail::move_impl(u.get_deleter()); return *this; } #endif @@ -597,9 +597,13 @@ struct managed_unique_ptr //!with boost::interproces::deleter from a pointer //!of type T that has been allocated in the passed managed segment template +#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE inline typename detail::return_type ::type >::type +#else +typename managed_unique_ptr::type +#endif make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory) { typename managed_unique_ptr::type to_return diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index 7e48cd7..e43c519 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -200,7 +200,10 @@ class weak_ptr template void _internal_assign(const detail::shared_count & pn2) - { m_pn = pn2; } + { + + m_pn = pn2; + } private: diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index bc3306c..05f6ff2 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -9,7 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// #include - +#include namespace boost { namespace interprocess { @@ -94,11 +94,11 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_enter_mut, abs_time); - lock = move(dummy); + lock = detail::move_impl(dummy); } else{ InternalLock dummy(m_enter_mut); - lock = move(dummy); + lock = detail::move_impl(dummy); } if(!lock) @@ -161,11 +161,11 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_check_mut, abs_time); - lock = move(dummy); + lock = detail::move_impl(dummy); } else{ InternalLock dummy(m_check_mut); - lock = move(dummy); + lock = detail::move_impl(dummy); } if(!lock) diff --git a/include/boost/interprocess/sync/math_functions.hpp b/include/boost/interprocess/sync/math_functions.hpp new file mode 100644 index 0000000..54d4126 --- /dev/null +++ b/include/boost/interprocess/sync/math_functions.hpp @@ -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 //BOOST_STATIC_ASSERT +#include //CHAR_BIT + +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 +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 +inline Integer lcm(const Integer & A, const Integer & B) +{ + Integer ret = A; + ret /= gcd(A, B); + ret *= B; + return ret; +} + +template +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 +inline Integer upper_power_of_2(const Integer & A) +{ + Integer power_of_2 = 1; + + while(power_of_2 < A){ + power_of_2 <<= 1; + } + return power_of_2; +} + +//This function uses binary search to discover the +//highest set bit of the integer +inline std::size_t floor_log2 (std::size_t x) +{ + const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; + const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); + BOOST_STATIC_ASSERT(Size_t_Bits_Power_2); + + std::size_t n = x; + std::size_t log2 = 0; + + for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ + std::size_t tmp = n >> shift; + if (tmp) + log2 += shift, n = tmp; + } + + return log2; +} + +} // namespace detail +} // namespace interprocess +} // namespace boost + +#endif diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index 2e4442c..f9e155e 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -122,15 +122,16 @@ class scoped_lock //! 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: "move(lock);". This + //! can be moved with the expression: "detail::move_impl(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit scoped_lock(detail::moved_object > scop) + scoped_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(scop.get().owns()) { mp_mutex = scop.get().release(); } #else - explicit scoped_lock(scoped_lock &&scop) + + scoped_lock(scoped_lock &&scop) : mp_mutex(0), m_locked(scop.owns()) { mp_mutex = scop.release(); } #endif @@ -144,11 +145,11 @@ class scoped_lock //! 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: "move(lock);" This constructor may block if + //! the expression: "detail::move_impl(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). #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit scoped_lock(detail::moved_object > upgr) + scoped_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr.get(); @@ -159,7 +160,7 @@ class scoped_lock mp_mutex = u_lock.release(); } #else - explicit scoped_lock(upgradable_lock &&upgr) + scoped_lock(upgradable_lock &&upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -326,7 +327,7 @@ class scoped_lock //! mutex after the assignment (and scop will not), but the mutex's lock //! count will be decremented by one. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_lock &operator=(detail::moved_object > scop) + scoped_lock &operator=(detail::moved_object scop) { if(this->owns()) this->unlock(); @@ -335,7 +336,7 @@ class scoped_lock return *this; } #else - scoped_lock &operator=(scoped_lock &&scop) + scoped_lock &operator=(scoped_lock &&scop) { if(this->owns()) this->unlock(); diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index 1fbe7d1..705f863 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -127,14 +127,14 @@ class sharable_lock //! 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: - //! "move(lock);". This constructor does not alter the state of the mutex, + //! "detail::move_impl(lock);". This constructor does not alter the state of the mutex, //! only potentially who owns it. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit sharable_lock(detail::moved_object > upgr) + sharable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(upgr.get().owns()) { mp_mutex = upgr.get().release(); } #else - explicit sharable_lock(sharable_lock &&upgr) + sharable_lock(sharable_lock &&upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } #endif @@ -147,9 +147,9 @@ class sharable_lock //!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: - //! "move(lock);".*/ + //! "detail::move_impl(lock);".*/ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit sharable_lock(detail::moved_object > upgr) + sharable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr.get(); @@ -160,7 +160,7 @@ class sharable_lock mp_mutex = u_lock.release(); } #else - explicit sharable_lock(upgradable_lock &&upgr) + sharable_lock(upgradable_lock &&upgr) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -181,9 +181,9 @@ class sharable_lock //! 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: - //! "move(lock);".*/ + //! "detail::move_impl(lock);".*/ #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit sharable_lock(detail::moved_object > scop) + sharable_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop.get(); @@ -194,7 +194,7 @@ class sharable_lock mp_mutex = e_lock.release(); } #else - explicit sharable_lock(scoped_lock &&scop) + sharable_lock(scoped_lock &&scop) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop; diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 6399400..6b1340d 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -121,14 +121,14 @@ class 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: "move(lock);". This constructor does not alter the + //! expression: "detail::move_impl(lock);". This constructor does not alter the //! state of the mutex, only potentially who owns it. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit upgradable_lock(detail::moved_object > upgr) + upgradable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(upgr.get().owns()) { mp_mutex = upgr.get().release(); } #else - explicit upgradable_lock(upgradable_lock &&upgr) + upgradable_lock(upgradable_lock &&upgr) : mp_mutex(0), m_locked(upgr.owns()) { mp_mutex = upgr.release(); } #endif @@ -141,9 +141,9 @@ class upgradable_lock //! 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: "move(lock);". + //! expression: "detail::move_impl(lock);". #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - explicit upgradable_lock(detail::moved_object > scop) + upgradable_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop.get(); @@ -154,7 +154,7 @@ class upgradable_lock mp_mutex = u_lock.release(); } #else - explicit upgradable_lock(scoped_lock &&scop) + upgradable_lock(scoped_lock &&scop) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop; diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index 9317509..976e0c0 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -104,7 +104,7 @@ class windows_shared_memory #else windows_shared_memory &operator=(windows_shared_memory &&moved) { - windows_shared_memory tmp(move(moved)); + windows_shared_memory tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } From e3acc1d098460eed2537ab9b4a6b7c93bcec1454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 09:08:13 +0000 Subject: [PATCH 37/77] gcc 4.3 fixes for normal and -std=c++0x modes [SVN r46574] --- doc/interprocess.qbk | 108 +++++++++++--- example/doc_complex_map.cpp | 81 +++++++++++ example/doc_managed_copy_on_write.cpp | 25 ++-- example/doc_move_containers.cpp | 4 +- example/doc_shared_memory2.cpp | 2 +- proj/to-do.txt | 20 +-- proj/vc7ide/Interprocess.sln | 16 +++ proj/vc7ide/doc_complex_map.vcproj | 133 +++++++++++++++++ .../enable_shared_from_this_test.vcproj | 136 ++++++++++++++++++ 9 files changed, 478 insertions(+), 47 deletions(-) create mode 100644 example/doc_complex_map.cpp create mode 100644 proj/vc7ide/doc_complex_map.vcproj create mode 100644 proj/vc7ide/enable_shared_from_this_test.vcproj diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 3c4870f..21be343 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -171,6 +171,9 @@ also the comparison functor when an allocator is passed in the constructor: [import ../example/doc_map.cpp] [doc_map] +For a more advanced example including containers of containers, see the section +[link interprocess.allocators_containers.containers_explained.containers_of_containers Containers of containers]. + [endsect] [endsect] @@ -2162,7 +2165,8 @@ more features and operations, see their reference for more informations [section:lock_conversions Lock Transfers Through Move Semantics] -[blurb [*Interprocess uses its own move semantics emulation code. +[blurb [*Interprocess uses its own move semantics emulation code for compilers +that don't support rvalues references. This is a temporary solution until a Boost move semantics library is accepted.]] Scoped locks and similar utilities offer simple resource management possibilities, @@ -3260,21 +3264,6 @@ The following features are common to all managed memory segment classes, but we will use managed shared memory in our examples. We can do the same with memory mapped files or other managed memory segment classes. -[section:copy_on_write Opening managed shared memory and mapped files with Copy On Write mode] - -When mapping a memory segment based on shared memory or files, there is an option to -open them using `open_copy_on_write` option. This option is similar to `open_only` but -every change the programmer does with this managed segment is kept private to this process -and is not translated to the underlying device (shared memory or file). - -The underlying shared memory or file is opened as read-only so several processes can -share an initial managed segment and make private changes to it. Here's an example: - -[import ../example/doc_managed_copy_on_write.cpp] -[doc_managed_copy_on_write] - -[endsect] - [section:allocate_deallocate Allocating fragments of a managed memory segment] If a basic raw-byte allocation is needed from a managed memory @@ -3569,6 +3558,36 @@ Here is an example showing this functionality: [endsect] +[section:managed_memory_segment_atomic_func Executing an object function atomically] + +Sometimes the programmer must execute some code, and needs to execute it with the +guarantee that no other process or thread will create or destroy any named, unique +or anonymous object while executing the functor. A user might want to create several +named objects and initialize them, but those objects should be available for the rest of processes +at once. + +To achieve this, the programmer can use the `atomic_func()` function offered by +managed classes: + +[c++] + + //This object function will create several named objects + create_several_objects_func func(/**/); + + //While executing the function, no other process will be + //able to create or destroy objects + managed_memory.atomic_func(func); + + +Note that `atomic_func` does not prevent other processes from allocating raw memory +or executing member functions for already constructed objects (e.g.: another process +might be pushing elements into a vector placed in the segment). The atomic function +only blocks named, unique and anonymous creation, search and destruction +(concurrent calls to `construct<>`, `find<>`, `find_or_construct<>`, `destroy<>`...) +from other processes. + +[endsect] + [endsect] [section:managed_memory_segment_advanced_features Managed Memory Segment Advanced Features] @@ -3985,6 +4004,43 @@ requests and the memory waste. [endsect] +[section:copy_on_write_read_only Opening managed shared memory and mapped files with Copy On Write or Read Only modes] + +When mapping a memory segment based on shared memory or files, there is an option to +open them using [*open_copy_on_write] option. This option is similar to `open_only` but +every change the programmer does with this managed segment is kept private to this process +and is not translated to the underlying device (shared memory or file). + +The underlying shared memory or file is opened as read-only so several processes can +share an initial managed segment and make private changes to it. If many processes +open a managed segment in copy on write mode and not modified pages from the managed +segment will be shared between all those processes, with considerable memory savings. + +Opening managed shared memory and mapped files with [*open_read_only] maps the the +underlying device in memory with [*read-only] attributes. This means that any attempt +to write that memory, either creating objects or locking any mutex might result in an +page-fault error (and thus, program termination) from the OS. Read-only mode opens +the underlying device (shared memory, file...) in read-only mode and +can result in considerable memory savings if several processes just want to process +a managed memory segment without modifying it. Read-only mode operations are limited: + +* Read-only mode must be used only from managed classes. If the programmer obtains + the segment manager and tries to use it directly it might result in an access violation. + The reason for this is that the segment manager is placed in the underlying device + and does not nothing about the mode it's been mapped in memory. + +* Only const member functions from managed segments should be used. + +* Additionally, the `find<>` member function avoids using internal locks and can be + used to look for named and unique objects. + +Here's an example that shows the use of these two open modes: + +[import ../example/doc_managed_copy_on_write.cpp] +[doc_managed_copy_on_write] + +[endsect] + [endsect] [section:managed_heap_memory_external_buffer Managed Heap Memory And Managed External Buffer] @@ -4983,6 +5039,21 @@ Boost.Interprocess containers: [endsect] +[section:containers_of_containers Containers of containers] + +When creating containers of containers, each container needs an allocator. +To avoid using several allocators with complex type definitions, we can take +advantage of the type erasure provided by void allocators and the ability +to implicitly convert void allocators in allocators that allocate other types. + +Here we have an example that builds a map in shared memory. Key is a string +and the mapped type is a class that stores several containers: + +[import ../example/doc_complex_map.cpp] +[doc_complex_map] + +[endsect] + [endsect] [section:additional_containers Boost containers compatible with Boost.Interprocess] @@ -6475,7 +6546,10 @@ warranty. * Added anonymous shared memory for UNIX systems. * Fixed erroneous `void` return types from `flat_map::erase()` functions. * Fixed missing move semantics on managed memory classes. -* Added copy_on_write option for shared memory and mapped file managed classes. +* Added copy_on_write and open_read_only options for shared memory and mapped file managed classes. +* [*ABI breaking]: Added to `mapped_region` the mode used to create it. +* Corrected instantiation errors in void allocators. +* `shared_ptr` is movable and supports aliasing. [endsect] diff --git a/example/doc_complex_map.cpp b/example/doc_complex_map.cpp new file mode 100644 index 0000000..1d64dac --- /dev/null +++ b/example/doc_complex_map.cpp @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[doc_complex_map +#include +#include +#include +#include +#include + +using namespace boost::interprocess; + +//Typedefs of allocators and containers +typedef managed_shared_memory::segment_manager segment_manager_t; +typedef allocator void_allocator; +typedef allocator int_allocator; +typedef vector int_vector; +typedef allocator int_vector_allocator; +typedef vector int_vector_vector; +typedef allocator char_allocator; +typedef basic_string, char_allocator> char_string; + +class complex_data +{ + int id_; + char_string char_string_; + int_vector_vector int_vector_vector_; + + public: + //Since void_allocator is convertible to any other allocator, we can simplify + //the initialization taking just one allocator for all inner containers. + complex_data(int id, const char *name, const void_allocator &void_alloc) + : id_(id), char_string_(name, void_alloc), int_vector_vector_(void_alloc) + {} + //Other members... +}; + +//Definition of the map holding a string as key and complex_data as mapped type +typedef std::pair map_value_type; +typedef std::pair movable_to_map_value_type; +typedef allocator map_value_type_allocator; +typedef map< char_string, complex_data + , std::less, map_value_type_allocator> complex_map_type; + +int main () +{ + shared_memory_object::remove("MySharedMemory"); + remove_shared_memory_on_destroy remove_on_destroy("MySharedMemory"); + { + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); + + //An allocator convertible to any allocator type + void_allocator alloc_inst (segment.get_segment_manager()); + + //Construct the shared memory map and fill it + complex_map_type *mymap = segment.construct + //(object name), (first ctor parameter, second ctor parameter) + ("MyMap")(std::less(), alloc_inst); + + for(int i = 0; i < 100; ++i){ + //Both key(string) and value(complex_data) need an allocator in their constructors + char_string key_object(alloc_inst); + complex_data mapped_object(i, "default_name", alloc_inst); + map_value_type value(key_object, mapped_object); + //Modify values and insert them in the map + mymap->insert(value); + } + } + return 0; +} +//] +#include diff --git a/example/doc_managed_copy_on_write.cpp b/example/doc_managed_copy_on_write.cpp index 5acda74..0b8fecc 100644 --- a/example/doc_managed_copy_on_write.cpp +++ b/example/doc_managed_copy_on_write.cpp @@ -12,6 +12,7 @@ #include #include //std::fstream #include //std::remove +#include //std::distance int main() { @@ -20,8 +21,10 @@ int main() //Try to erase any previous managed segment with the same name std::remove("MyManagedFile"); std::remove("MyManagedFile2"); + remove_file_on_destroy destroyer1("MyManagedFile"); + remove_file_on_destroy destroyer2("MyManagedFile2"); - try{ + { //Create an named integer in a managed mapped file managed_mapped_file managed_file(create_only, "MyManagedFile", 65536); managed_file.construct("MyInt")(0u); @@ -43,7 +46,7 @@ int main() throw int(0); { //Dump the modified copy on write segment to a file - std::fstream file("MyManagedFile2", std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); + std::fstream file("MyManagedFile2", std::ios_base::out | std::ios_base::binary); if(!file) throw int(0); file.write((const char *)managed_file_cow.get_address(), managed_file_cow.get_size()); @@ -54,13 +57,19 @@ int main() if(managed_file_cow2.find("MyInt").first && !managed_file_cow2.find("MyInt2").first) throw int(0); } - catch(...){ - std::remove("MyManagedFile"); - std::remove("MyManagedFile2"); - throw; + { + //Now create a read-only version + managed_mapped_file managed_file_ro(open_read_only, "MyManagedFile"); + + //Check the original is intact + if(!managed_file_ro.find("MyInt").first && managed_file_ro.find("MyInt2").first) + throw int(0); + + //Check the number of named objects using the iterators + if(std::distance(managed_file_ro.named_begin(), managed_file_ro.named_end()) != 1 && + std::distance(managed_file_ro.unique_begin(), managed_file_ro.unique_end()) != 0 ) + throw int(0); } - std::remove("MyManagedFile"); - std::remove("MyManagedFile2"); return 0; } //] diff --git a/example/doc_move_containers.cpp b/example/doc_move_containers.cpp index 65f75f2..aeadf61 100644 --- a/example/doc_move_containers.cpp +++ b/example/doc_move_containers.cpp @@ -53,7 +53,7 @@ int main () //In the following line, no string copy-constructor will be called. //"move_me"'s contents will be transferred to the string created in //the vector - myshmvector->push_back(move(move_me)); + myshmvector->push_back(boost::interprocess::move(move_me)); //The source string is in default constructed state assert(move_me.empty()); @@ -69,7 +69,7 @@ int main () //No string copy-constructor or assignments will be called, but //move constructors and move-assignments. No memory allocation //function will be called in this operations!! - myshmvector->insert(myshmvector->begin(), move(string_to_compare)); + myshmvector->insert(myshmvector->begin(), boost::interprocess::move(string_to_compare)); //Destroy vector. This will free all strings that the vector contains shm.destroy_ptr(myshmvector); diff --git a/example/doc_shared_memory2.cpp b/example/doc_shared_memory2.cpp index ad7b8ec..3fd2da2 100644 --- a/example/doc_shared_memory2.cpp +++ b/example/doc_shared_memory2.cpp @@ -33,13 +33,13 @@ int main () } } std::cout << "Test successful!" << std::endl; - shared_memory_object::remove("shared_memory"); } catch(interprocess_exception &ex){ std::cout << "Unexpected exception: " << ex.what() << std::endl; shared_memory_object::remove("shared_memory"); return 1; } + shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/proj/to-do.txt b/proj/to-do.txt index c03de84..99dd486 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -24,25 +24,11 @@ -> Add default algorithm and index types. The user does not need to know how are they implemented. --> Add private mapping to managed classes. - --> Add unique_ptr documentation. - -> Pass max size check in allocation to node pools --> Add atomic_func explanation in docs - --> Once shrink to fit indexes is implemented test all memory has been deallocated - in tests to detect leaks/implementation failures. - --> Improve allocate_many functions to allocate all the nodes forming a singly - linked list of nodes. - -> Use in-place expansion capabilities to shrink_to_fit and reserve functions from iunordered_index. --> Optimize copy_n with std::copy in vector. Revise other functions to improve optimizations - -> Keep an eye on container iterator constness issue to bring Interprocess containers up-to-date. -> change unique_ptr to avoid using compressed_pair @@ -51,10 +37,6 @@ -> barrier_test fails on MacOS X on PowerPC. --> void allocator instantiations fail. - --> Read-only managed classes. They should avoid internal locking and map memory as read-only - -> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ --> add contiguous_elements option to burst allocation +-> add contiguous_elements option to burst allocation \ No newline at end of file diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index 1539527..7f00fbe 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -451,6 +451,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_copy_on_write", ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "enable_shared_from_this_test", "enable_shared_from_this_test.vcproj", "{571C3483-87C7-6921-1238-B086B3E766C9}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_complex_map", "doc_complex_map.vcproj", "{5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -911,6 +919,14 @@ Global {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Debug.Build.0 = Debug|Win32 {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.ActiveCfg = Release|Win32 {8E0C437E-3613-FD46-F3AE-876A0731CA85}.Release.Build.0 = Release|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Debug.ActiveCfg = Debug|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Debug.Build.0 = Debug|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Release.ActiveCfg = Release|Win32 + {571C3483-87C7-6921-1238-B086B3E766C9}.Release.Build.0 = Release|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Debug.ActiveCfg = Debug|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Debug.Build.0 = Debug|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Release.ActiveCfg = Release|Win32 + {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/doc_complex_map.vcproj b/proj/vc7ide/doc_complex_map.vcproj new file mode 100644 index 0000000..855420e --- /dev/null +++ b/proj/vc7ide/doc_complex_map.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/enable_shared_from_this_test.vcproj b/proj/vc7ide/enable_shared_from_this_test.vcproj new file mode 100644 index 0000000..e6ff1fe --- /dev/null +++ b/proj/vc7ide/enable_shared_from_this_test.vcproj @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 513019d931956edd01c3caa5a3fbc0b65b8175ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 09:11:38 +0000 Subject: [PATCH 38/77] gcc 4.3 fixes for normal and -std=c++0x modes [SVN r46575] --- test/enable_shared_from_this_test.cpp | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 test/enable_shared_from_this_test.cpp diff --git a/test/enable_shared_from_this_test.cpp b/test/enable_shared_from_this_test.cpp new file mode 100644 index 0000000..6cc7a78 --- /dev/null +++ b/test/enable_shared_from_this_test.cpp @@ -0,0 +1,97 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2002, 2003 Peter Dimov +// +// This file is the adaptation of shared_from_this_test.cpp from smart_ptr library +// +// (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 +#include +#include +#include + +#include +#include +#include "get_process_id_name.hpp" + +// + +using namespace boost::interprocess; + +typedef allocator + v_allocator_t; + +struct X; + +typedef deleter x_deleter_t; + +struct X : + public enable_shared_from_this +{ +}; + +typedef shared_ptr v_shared_ptr; + + +template +void test_enable_shared_this(ManagedMemory &managed_mem) +{ + v_shared_ptr p(make_managed_shared_ptr + (managed_mem.template construct(anonymous_instance)(), managed_mem)); + + v_shared_ptr q = p->shared_from_this(); + BOOST_TEST(p == q); + BOOST_TEST(!(p < q) && !(q < p)); + + X v2(*p); + + try + { + //This should throw bad_weak_ptr + v_shared_ptr r = v2.shared_from_this(); + BOOST_ERROR("v2.shared_from_this() failed to throw"); + } + catch(boost::interprocess::bad_weak_ptr const &) + { + //This is the expected path + } + catch(...){ + BOOST_ERROR("v2.shared_from_this() threw an unexpected exception"); + } + + try + { + //This should not throw bad_weak_ptr + *p = X(); + v_shared_ptr r = p->shared_from_this(); + BOOST_TEST(p == r); + BOOST_TEST(!(p < r) && !(r < p)); + } + catch(boost::interprocess::bad_weak_ptr const &) + { + BOOST_ERROR("p->shared_from_this() threw bad_weak_ptr after *p = X()"); + } + catch(...) + { + BOOST_ERROR("p->shared_from_this() threw an unexpected exception after *p = X()"); + } +} + + +int main() +{ + std::string process_name; + test::get_process_id_name(process_name); + shared_memory_object::remove(process_name.c_str()); + managed_shared_memory shmem(create_only, process_name.c_str(), 65536); + test_enable_shared_this(shmem); + shared_memory_object::remove(process_name.c_str()); + return boost::report_errors(); +} + +#include From 989c4332cf03c77f609073265b1985a8f7b808f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 09:12:15 +0000 Subject: [PATCH 39/77] gcc 4.3 fixes for normal and -std=c++0x modes [SVN r46576] --- test/adaptive_pool_test.cpp | 2 + test/cached_adaptive_pool_test.cpp | 3 +- test/cached_node_allocator_test.cpp | 2 + test/deque_test.cpp | 12 +-- test/dummy_test_allocator.hpp | 2 +- test/file_mapping_test.cpp | 4 +- test/iset_index_allocation_test.cpp | 1 - test/list_test.hpp | 8 +- test/managed_mapped_file_test.cpp | 13 +++- test/managed_shared_memory_test.cpp | 13 +++- test/managed_windows_shared_memory_test.cpp | 13 +++- test/map_test.hpp | 32 ++++---- test/mapped_file_test.cpp | 4 +- test/node_allocator_test.cpp | 2 + test/private_adaptive_pool_test.cpp | 2 + test/private_node_allocator_test.cpp | 2 + test/set_test.hpp | 72 +++++++++--------- test/shared_memory_mapping_test.cpp | 4 +- test/shared_memory_test.cpp | 4 +- test/shared_ptr_test.cpp | 83 ++++++++++++++++++++- test/string_test.cpp | 4 +- test/unique_ptr_test.cpp | 28 +++---- test/upgradable_mutex_test.cpp | 70 ++++++++--------- test/user_buffer_test.cpp | 12 +-- test/vector_test.hpp | 16 ++-- 25 files changed, 262 insertions(+), 146 deletions(-) diff --git a/test/adaptive_pool_test.cpp b/test/adaptive_pool_test.cpp index 196d0d5..ebc3043 100644 --- a/test/adaptive_pool_test.cpp +++ b/test/adaptive_pool_test.cpp @@ -32,6 +32,8 @@ typedef detail::adaptive_pool_v1 //Explicit instantiations to catch compilation errors template class adaptive_pool; template class detail::adaptive_pool_v1; +template class adaptive_pool; +template class detail::adaptive_pool_v1; //Alias list types typedef list MyShmList; diff --git a/test/cached_adaptive_pool_test.cpp b/test/cached_adaptive_pool_test.cpp index 5d5a8c7..0f5a09a 100644 --- a/test/cached_adaptive_pool_test.cpp +++ b/test/cached_adaptive_pool_test.cpp @@ -34,7 +34,8 @@ typedef detail::cached_adaptive_pool_v1 //Explicit instantiations to catch compilation errors template class cached_adaptive_pool; template class detail::cached_adaptive_pool_v1; - +template class cached_adaptive_pool; +template class detail::cached_adaptive_pool_v1; //Alias list types typedef list MyShmList; diff --git a/test/cached_node_allocator_test.cpp b/test/cached_node_allocator_test.cpp index 0900a4c..c29e639 100644 --- a/test/cached_node_allocator_test.cpp +++ b/test/cached_node_allocator_test.cpp @@ -32,6 +32,8 @@ typedef detail::cached_node_allocator_v1 //Explicit instantiations to catch compilation errors template class cached_node_allocator; template class detail::cached_node_allocator_v1; +template class cached_node_allocator; +template class detail::cached_node_allocator_v1; //Alias list types typedef list MyShmList; diff --git a/test/deque_test.cpp b/test/deque_test.cpp index c9a6934..483f8da 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -65,12 +65,12 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) { IntType move_me(1); stddeque->insert(stddeque->begin()+size/2, 50, 1); - shmdeque->insert(shmdeque->begin()+size/2, 50, move(move_me)); + shmdeque->insert(shmdeque->begin()+size/2, 50, detail::move_impl(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { IntType move_me(2); - shmdeque->assign(shmdeque->size()/2, move(move_me)); + shmdeque->assign(shmdeque->size()/2, detail::move_impl(move_me)); stddeque->assign(stddeque->size()/2, 2); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } @@ -120,7 +120,7 @@ bool do_test() int i; for(i = 0; i < max; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->end(), move(move_me)); + shmdeque->insert(shmdeque->end(), detail::move_impl(move_me)); stddeque->insert(stddeque->end(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; @@ -141,7 +141,7 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me (-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -164,7 +164,7 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -189,7 +189,7 @@ bool do_test() for(i = 0; i < max; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->begin(), move(move_me)); + shmdeque->insert(shmdeque->begin(), detail::move_impl(move_me)); stddeque->insert(stddeque->begin(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index 7c66735..e8466f0 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -115,7 +115,7 @@ class dummy_test_allocator size_type, size_type, size_type &, const pointer & = 0) - { return std::pair(0, true); } + { return std::pair(pointer(0), true); } //!Returns maximum the number of objects the previously allocated memory //!pointed by p can hold. diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 0efee1c..743c917 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -125,9 +125,9 @@ int main () { //Now test move semantics file_mapping mapping(test::get_process_id_name(), read_only); - file_mapping move_ctor(move(mapping)); + file_mapping move_ctor(detail::move_impl(mapping)); file_mapping move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } } catch(std::exception &exc){ diff --git a/test/iset_index_allocation_test.cpp b/test/iset_index_allocation_test.cpp index a5bae3f..9e25313 100644 --- a/test/iset_index_allocation_test.cpp +++ b/test/iset_index_allocation_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include "named_allocation_test_template.hpp" diff --git a/test/list_test.hpp b/test/list_test.hpp index a8982f6..deaa277 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -36,7 +36,7 @@ struct push_data_function typedef typename MyShmList::value_type IntType; for(int i = 0; i < max; ++i){ IntType move_me(i); - shmlist->push_back(move(move_me)); + shmlist->push_back(detail::move_impl(move_me)); stdlist->push_back(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -54,7 +54,7 @@ struct push_data_function typedef typename MyShmList::value_type IntType; for(int i = 0; i < max; ++i){ IntType move_me(i); - shmlist->push_front(move(move_me)); + shmlist->push_front(detail::move_impl(move_me)); stdlist->push_front(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -136,7 +136,7 @@ int list_test (bool copied_allocators_equal = true) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -166,7 +166,7 @@ int list_test (bool copied_allocators_equal = true) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index c4c6cbc..0d00edb 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -117,6 +117,15 @@ int main () return -1; } } + { + //Map preexisting file again in copy-on-write + managed_mapped_file mfile(open_read_only, FileName); + + //Check vector is still there + MyVect *mfile_vect = mfile.find("MyVector").first; + if(!mfile_vect) + return -1; + } { std::size_t old_free_memory; { @@ -194,9 +203,9 @@ int main () { //Now test move semantics managed_mapped_file original(open_only, FileName); - managed_mapped_file move_ctor(move(original)); + managed_mapped_file move_ctor(detail::move_impl(original)); managed_mapped_file move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } } diff --git a/test/managed_shared_memory_test.cpp b/test/managed_shared_memory_test.cpp index 57cc678..2004af8 100644 --- a/test/managed_shared_memory_test.cpp +++ b/test/managed_shared_memory_test.cpp @@ -113,6 +113,15 @@ int main () return -1; } } + { + //Map preexisting shmem again in copy-on-write + managed_shared_memory shmem(open_read_only, ShmemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } { std::size_t old_free_memory; { @@ -190,9 +199,9 @@ int main () { //Now test move semantics managed_shared_memory original(open_only, ShmemName); - managed_shared_memory move_ctor(move(original)); + managed_shared_memory move_ctor(detail::move_impl(original)); managed_shared_memory move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } } diff --git a/test/managed_windows_shared_memory_test.cpp b/test/managed_windows_shared_memory_test.cpp index 61dbd35..f02868f 100644 --- a/test/managed_windows_shared_memory_test.cpp +++ b/test/managed_windows_shared_memory_test.cpp @@ -113,6 +113,15 @@ int main () return -1; } } + { + //Map preexisting shmem again in copy-on-write + managed_windows_shared_memory shmem(open_read_only, MemName); + + //Check vector is still there + MyVect *shmem_vect = shmem.find("MyVector").first; + if(!shmem_vect) + return -1; + } //Destroy and check it is not present w_shm_new.destroy_ptr(w_shm_vect); @@ -121,9 +130,9 @@ int main () //Now test move semantics managed_windows_shared_memory original(open_only, MemName); - managed_windows_shared_memory move_ctor(move(original)); + managed_windows_shared_memory move_ctor(detail::move_impl(original)); managed_windows_shared_memory move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } } diff --git a/test/map_test.hpp b/test/map_test.hpp index 4d9902f..13363bf 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -115,9 +115,9 @@ int map_test () int i, j; for(i = 0; i < max; ++i){ - shmmap->insert(move(IntPairType (move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType (detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(StdPairType(i, i)); } @@ -232,9 +232,9 @@ int map_test () } for(i = 0; i < max; ++i){ - shmmap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(StdPairType(i, i)); } @@ -242,10 +242,10 @@ int map_test () if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; for(i = 0; i < max; ++i){ - shmmap->insert(shmmap->begin(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->begin(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->begin(), StdPairType(i, i)); //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->begin(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->begin(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->begin(), StdPairType(i, i)); //PrintContainers(shmmultimap, stdmultimap); if(!CheckEqualPairContainers(shmmap, stdmap)) @@ -253,29 +253,29 @@ int map_test () if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - shmmap->insert(shmmap->end(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->end(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->end(), StdPairType(i, i)); - shmmultimap->insert(shmmultimap->end(), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->end(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->end(), StdPairType(i, i)); if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - shmmap->insert(shmmap->lower_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->lower_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->lower_bound(i), StdPairType(i, i)); //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->lower_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->lower_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->lower_bound(i), StdPairType(i, i)); //PrintContainers(shmmultimap, stdmultimap); if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - shmmap->insert(shmmap->upper_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(shmmap->upper_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(stdmap->upper_bound(i), StdPairType(i, i)); //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->upper_bound(IntType(i)), move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(shmmultimap->upper_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(stdmultimap->upper_bound(i), StdPairType(i, i)); //PrintContainers(shmmultimap, stdmultimap); if(!CheckEqualPairContainers(shmmap, stdmap)) @@ -303,8 +303,8 @@ int map_test () for(j = 0; j < 3; ++j) for(i = 0; i < 100; ++i){ - shmmap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); if(shmmap->count(IntType(i)) != typename MyShmMultiMap::size_type(1)) return 1; if(shmmultimap->count(IntType(i)) != typename MyShmMultiMap::size_type(j+1)) @@ -367,9 +367,9 @@ int map_test_copyable () int i; for(i = 0; i < max; ++i){ - shmmap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(move(IntPairType(move(IntType(i)), move(IntType(i))))); + shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); stdmultimap->insert(StdPairType(i, i)); } if(!CheckEqualContainers(shmmap, stdmap)) return 1; diff --git a/test/mapped_file_test.cpp b/test/mapped_file_test.cpp index 99ef3fd..75bb9eb 100644 --- a/test/mapped_file_test.cpp +++ b/test/mapped_file_test.cpp @@ -76,9 +76,9 @@ int main () std::memset(file1.get_user_address(), 0, file1.get_user_size()); //Now test move semantics - mapped_file move_ctor(move(file1)); + mapped_file move_ctor(detail::move_impl(file1)); mapped_file move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } std::remove(FileName); return 0; diff --git a/test/node_allocator_test.cpp b/test/node_allocator_test.cpp index 8c7682b..4c1235f 100644 --- a/test/node_allocator_test.cpp +++ b/test/node_allocator_test.cpp @@ -31,6 +31,8 @@ typedef detail::node_allocator_v1 //Explicit instantiations to catch compilation errors template class node_allocator; template class detail::node_allocator_v1; +template class node_allocator; +template class detail::node_allocator_v1; //Alias list types typedef list MyShmList; diff --git a/test/private_adaptive_pool_test.cpp b/test/private_adaptive_pool_test.cpp index 2237b80..953bdfa 100644 --- a/test/private_adaptive_pool_test.cpp +++ b/test/private_adaptive_pool_test.cpp @@ -31,6 +31,8 @@ typedef detail::private_adaptive_pool_v1 //Explicit instantiations to catch compilation errors template class private_adaptive_pool; template class detail::private_adaptive_pool_v1; +template class private_adaptive_pool; +template class detail::private_adaptive_pool_v1; //Alias list types typedef list MyShmList; diff --git a/test/private_node_allocator_test.cpp b/test/private_node_allocator_test.cpp index 692fd3c..ad3fc5d 100644 --- a/test/private_node_allocator_test.cpp +++ b/test/private_node_allocator_test.cpp @@ -31,6 +31,8 @@ typedef detail::private_node_allocator_v1 //Explicit instantiations to catch compilation errors template class private_node_allocator; template class detail::private_node_allocator_v1; +template class private_node_allocator; +template class detail::private_node_allocator_v1; //Alias list types typedef list MyShmList; diff --git a/test/set_test.hpp b/test/set_test.hpp index f35ccee..db8766f 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -63,7 +63,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -72,7 +72,7 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect3[i] = move(move_me); + aux_vect3[i] = detail::move_impl(move_me); } MyShmSet *shmset2 = @@ -108,20 +108,20 @@ int set_test () int i, j; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(move(move_me)" << std::endl; + std::cout << "Error in shmset->insert(detail::move_impl(move_me)" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(move(move_me)" << std::endl; + std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me)" << std::endl; return 1; } @@ -183,7 +183,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -192,7 +192,7 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = move(move_me); + aux_vect3[i] = detail::move_impl(move_me); } shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); @@ -228,7 +228,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = move(move_me); + aux_vect[i] = detail::move_impl(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -237,19 +237,19 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = move(move_me); + aux_vect3[i] = detail::move_impl(move_me); } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect4[i] = move(move_me); + aux_vect4[i] = detail::move_impl(move_me); } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect5[i] = move(move_me); + aux_vect5[i] = detail::move_impl(move_me); } shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); @@ -285,88 +285,88 @@ int set_test () for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(move(move_me)) try 2" << std::endl; + std::cout << "Error in shmset->insert(detail::move_impl(move_me)) try 2" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(move(move_me2)) try 2" << std::endl; + std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me2)) try 2" << std::endl; return 1; } for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(shmset->begin(), move(move_me)); + shmset->insert(shmset->begin(), detail::move_impl(move_me)); stdset->insert(stdset->begin(), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->begin(), move(move_me2)); + shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2)); stdmultiset->insert(stdmultiset->begin(), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->begin(), move(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->begin(), detail::move_impl(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), move(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2))" << std::endl; return 1; } IntType move_me3(i); - shmset->insert(shmset->end(), move(move_me3)); + shmset->insert(shmset->end(), detail::move_impl(move_me3)); stdset->insert(stdset->end(), i); IntType move_me4(i); - shmmultiset->insert(shmmultiset->end(), move(move_me4)); + shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4)); stdmultiset->insert(stdmultiset->end(), i); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->end(), move(move_me3))" << std::endl; + std::cout << "Error in shmset->insert(shmset->end(), detail::move_impl(move_me3))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->end(), move(move_me4))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4))" << std::endl; return 1; } { IntType move_me(i); - shmset->insert(shmset->upper_bound(move_me), move(move_me)); + shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me)); stdset->insert(stdset->upper_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->upper_bound(move_me2), move(move_me2)); + shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2)); stdmultiset->insert(stdmultiset->upper_bound(i), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), move(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), move(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2))" << std::endl; return 1; } } { IntType move_me(i); - shmset->insert(shmset->lower_bound(move_me), move(move_me2)); + shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2)); stdset->insert(stdset->lower_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->lower_bound(move_me2), move(move_me2)); + shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2)); stdmultiset->insert(stdmultiset->lower_bound(i), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), move(move_me2))" << std::endl; + std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), move(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2))" << std::endl; return 1; } } @@ -392,9 +392,9 @@ int set_test () for(j = 0; j < 3; ++j) for(i = 0; i < 100; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); IntType count_me(i); if(shmset->count(count_me) != typename MyShmMultiSet::size_type(1)){ std::cout << "Error in shmset->count(count_me)" << std::endl; @@ -461,10 +461,10 @@ int set_test_copyable () int i; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(move(move_me)); + shmset->insert(detail::move_impl(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(move(move_me2)); + shmmultiset->insert(detail::move_impl(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)) return 1; diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index eba27c1..54fc31d 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -139,9 +139,9 @@ int main () { //Now test move semantics shared_memory_object mapping(open_only, test::get_process_id_name(), read_write); - shared_memory_object move_ctor(move(mapping)); + shared_memory_object move_ctor(detail::move_impl(mapping)); shared_memory_object move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } } catch(std::exception &exc){ diff --git a/test/shared_memory_test.cpp b/test/shared_memory_test.cpp index 1299911..976a4a2 100644 --- a/test/shared_memory_test.cpp +++ b/test/shared_memory_test.cpp @@ -76,9 +76,9 @@ int main () std::memset(shm1.get_user_address(), 0, shm1.get_user_size()); //Now test move semantics - shared_memory move_ctor(move(shm1)); + shared_memory move_ctor(detail::move_impl(shm1)); shared_memory move_assign; - move_assign = move(move_ctor); + move_assign = detail::move_impl(move_ctor); } } catch(std::exception &ex){ diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index 7371f89..ef7066a 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -1,7 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Peter Dimov 2002-2005. -// (C) Copyright Ion Gaztanaga 2006-2007. +// (C) Copyright Peter Dimov 2002-2005, 2007. +// (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) @@ -168,6 +168,8 @@ int string_shared_ptr_vector_insertion_test() //Now fill a shared memory vector of shared_ptrs to a string string_shared_ptr_vector_t my_sharedptr_vector(string_shared_ptr_allocator); my_sharedptr_vector.insert(my_sharedptr_vector.begin(), NumElements, string_shared_ptr); + //Insert in the middle to test movability + my_sharedptr_vector.insert(my_sharedptr_vector.begin() + my_sharedptr_vector.size()/2, NumElements, string_shared_ptr); //Now check the shared count is the objects contained in the //vector plus string_shared_ptr if(string_shared_ptr.use_count() != static_cast(my_sharedptr_vector.size()+1)){ @@ -536,6 +538,81 @@ int basic_shared_ptr_test() return boost::report_errors(); } +struct alias_tester +{ + int v_; + + explicit alias_tester( int v ): v_( v ) + { + } + + ~alias_tester() + { + v_ = 0; + } +}; + +void test_alias() +{ + typedef allocator + v_allocator_t; + + typedef deleter + alias_tester_deleter_t; + + typedef deleter + int_deleter_t; + + typedef shared_ptr alias_tester_shared_ptr; + + typedef shared_ptr int_shared_ptr; + typedef shared_ptr const_int_shared_ptr; + typedef shared_ptr volatile_int_shared_ptr; + + std::string process_name; + test::get_process_id_name(process_name); + + shared_memory_object::remove(process_name.c_str()); + { + managed_shared_memory shmem(create_only, process_name.c_str(), 10000); + + { + int m = 0; + int_shared_ptr p; + int_shared_ptr p2( p, &m ); + + BOOST_TEST( detail::get_pointer(p2.get()) == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + + p2.reset( p, (int*)0 ); + + BOOST_TEST( p2.get() == 0 ); + + BOOST_TEST( p2? false: true ); + BOOST_TEST( !p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + + { + int m = 0; + int_shared_ptr p(make_managed_shared_ptr + (shmem.construct(anonymous_instance)(), shmem)); + const_int_shared_ptr p2( p, &m ); + + BOOST_TEST( detail::get_pointer(p2.get()) == &m ); + BOOST_TEST( p2? true: false ); + BOOST_TEST( !!p2 ); + BOOST_TEST( p2.use_count() == p.use_count() ); + BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); + } + } + shared_memory_object::remove(process_name.c_str()); +} + int main() { @@ -548,6 +625,8 @@ int main() if(0 != basic_shared_ptr_test()) return 1; + test_alias(); + return 0; } diff --git a/test/string_test.cpp b/test/string_test.cpp index 9009186..62318bb 100644 --- a/test/string_test.cpp +++ b/test/string_test.cpp @@ -127,7 +127,7 @@ int string_test() std::sprintf(buffer, "%i", i); auxShmString += buffer; auxStdString += buffer; - shmStringVect->push_back(move(auxShmString)); + shmStringVect->push_back(detail::move_impl(auxShmString)); stdStringVect->push_back(auxStdString); } @@ -157,7 +157,7 @@ int string_test() std::sprintf(buffer, "%i", i); auxShmString += buffer; auxStdString += buffer; - shmStringVect->insert(shmStringVect->begin(), move(auxShmString)); + shmStringVect->insert(shmStringVect->begin(), detail::move_impl(auxShmString)); stdStringVect->insert(stdStringVect->begin(), auxStdString); } diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp index 19830fb..be43789 100644 --- a/test/unique_ptr_test.cpp +++ b/test/unique_ptr_test.cpp @@ -70,14 +70,14 @@ int main() //Test some copy constructors my_unique_ptr_class my_ptr3(0, segment.get_deleter()); - my_unique_ptr_class my_ptr4(move(my_ptr3)); + my_unique_ptr_class my_ptr4(detail::move_impl(my_ptr3)); //Construct a list and fill MyList list(segment.get_segment_manager()); //Insert from my_unique_ptr_class - list.push_front(move(my_ptr)); - list.push_back(move(my_ptr2)); + list.push_front(detail::move_impl(my_ptr)); + list.push_back(detail::move_impl(my_ptr2)); //Check pointers assert(my_ptr.get() == 0); @@ -85,9 +85,9 @@ int main() assert(list.begin()->get() == ptr1); assert(list.rbegin()->get() == ptr2); - //MyList list2(move(list)); - //list2.swap(move(MyList(segment.get_segment_manager()))); - //list.swap(move(MyList(segment.get_segment_manager()))); + //MyList list2(detail::move_impl(list)); + //list2.swap(detail::move_impl(MyList(segment.get_segment_manager()))); + //list.swap(detail::move_impl(MyList(segment.get_segment_manager()))); assert(list.begin()->get() == ptr1); assert(list.rbegin()->get() == ptr2); @@ -97,8 +97,8 @@ int main() MySet set(set_less_t(), segment.get_segment_manager()); //Insert in set from list passing ownership - set.insert(move(*list.begin())); - set.insert(move(*list.rbegin())); + set.insert(detail::move_impl(*list.begin())); + set.insert(detail::move_impl(*list.rbegin())); //Check pointers assert(list.begin()->get() == 0); @@ -120,12 +120,12 @@ int main() //Insert from my_unique_ptr_class if(ptr1 < ptr2){ - vector.insert(vector.begin(), move(*set.begin())); - vector.insert(vector.end(), move(*set.rbegin())); + vector.insert(vector.begin(), detail::move_impl(*set.begin())); + vector.insert(vector.end(), detail::move_impl(*set.rbegin())); } else{ - vector.insert(vector.begin(), move(*set.rbegin())); - vector.insert(vector.end(), move(*set.begin())); + vector.insert(vector.begin(), detail::move_impl(*set.rbegin())); + vector.insert(vector.end(), detail::move_impl(*set.begin())); } //Check pointers @@ -134,14 +134,14 @@ int main() assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); - MyVector vector2(move(vector)); + MyVector vector2(detail::move_impl(vector)); vector2.swap(vector); assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); my_unique_ptr_class a(0, segment.get_deleter()), b(0, segment.get_deleter()); - a = move(b); + a = detail::move_impl(b); } shared_memory_object::remove(process_name.c_str()); return 0; diff --git a/test/upgradable_mutex_test.cpp b/test/upgradable_mutex_test.cpp index d94bb1b..846743a 100644 --- a/test/upgradable_mutex_test.cpp +++ b/test/upgradable_mutex_test.cpp @@ -35,135 +35,135 @@ int main () //Conversions to scoped_lock { scoped_lock lock(mut); - scoped_lock e_lock(move(lock)); - lock.swap(move(e_lock)); + scoped_lock e_lock(detail::move_impl(lock)); + lock.swap(detail::move_impl(e_lock)); } { scoped_lock lock(mut); scoped_lock e_lock(mut2); - e_lock = move(lock); + e_lock = detail::move_impl(lock); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() - scoped_lock e_lock(move(u_lock)); + scoped_lock e_lock(detail::move_impl(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(u_lock)); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(u_lock)); + e_lock = detail::move_impl(moved); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() - scoped_lock e_lock(move(u_lock), try_to_lock); + scoped_lock e_lock(detail::move_impl(u_lock), try_to_lock); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(u_lock), try_to_lock); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(u_lock), try_to_lock); + e_lock = detail::move_impl(moved); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock u_lock(mut); //This calls timed_unlock_upgradable_and_lock() - scoped_lock e_lock(move(u_lock), t); + scoped_lock e_lock(detail::move_impl(u_lock), t); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock u_lock(mut); //This calls timed_unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(u_lock), t); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(u_lock), t); + e_lock = detail::move_impl(moved); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() - scoped_lock e_lock(move(s_lock), try_to_lock); + scoped_lock e_lock(detail::move_impl(s_lock), try_to_lock); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(move(s_lock), try_to_lock); - e_lock = move(moved); + scoped_lock moved(detail::move_impl(s_lock), try_to_lock); + e_lock = detail::move_impl(moved); } //Conversions to upgradable_lock { upgradable_lock lock(mut); - upgradable_lock u_lock(move(lock)); - lock.swap(move(u_lock)); + upgradable_lock u_lock(detail::move_impl(lock)); + lock.swap(detail::move_impl(u_lock)); } { upgradable_lock lock(mut); upgradable_lock u_lock(mut2); - upgradable_lock moved(move(lock)); - u_lock = move(moved); + upgradable_lock moved(detail::move_impl(lock)); + u_lock = detail::move_impl(moved); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() - upgradable_lock u_lock(move(s_lock), try_to_lock); + upgradable_lock u_lock(detail::move_impl(s_lock), try_to_lock); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(move(s_lock), try_to_lock); - u_lock = move(moved); + upgradable_lock moved(detail::move_impl(s_lock), try_to_lock); + u_lock = detail::move_impl(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() - upgradable_lock u_lock(move(e_lock)); + upgradable_lock u_lock(detail::move_impl(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(move(e_lock)); - u_lock = move(moved); + upgradable_lock moved(detail::move_impl(e_lock)); + u_lock = detail::move_impl(moved); } //Conversions to sharable_lock { sharable_lock lock(mut); - sharable_lock s_lock(move(lock)); - lock.swap(move(s_lock)); + sharable_lock s_lock(detail::move_impl(lock)); + lock.swap(detail::move_impl(s_lock)); } { sharable_lock lock(mut); sharable_lock s_lock(mut2); - sharable_lock moved(move(lock)); - s_lock = move(moved); + sharable_lock moved(detail::move_impl(lock)); + s_lock = detail::move_impl(moved); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() - sharable_lock s_lock(move(u_lock)); + sharable_lock s_lock(detail::move_impl(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(move(u_lock)); - s_lock = move(moved); + sharable_lock moved(detail::move_impl(u_lock)); + s_lock = detail::move_impl(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() - sharable_lock s_lock(move(e_lock)); + sharable_lock s_lock(detail::move_impl(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(move(e_lock)); - s_lock = move(moved); + sharable_lock moved(detail::move_impl(e_lock)); + s_lock = detail::move_impl(moved); } } diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index 8b97058..0835575 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -65,13 +65,13 @@ int main () //Test move semantics { wmanaged_external_buffer user_default; - wmanaged_external_buffer temp_external(move(user_buffer)); - user_default = move(temp_external); - user_buffer = move(user_default); + wmanaged_external_buffer temp_external(detail::move_impl(user_buffer)); + user_default = detail::move_impl(temp_external); + user_buffer = detail::move_impl(user_default); wmanaged_heap_memory heap_default; - wmanaged_heap_memory temp_heap(move(heap_buffer)); - heap_default = move(temp_heap); - heap_buffer = move(heap_default); + wmanaged_heap_memory temp_heap(detail::move_impl(heap_buffer)); + heap_default = detail::move_impl(temp_heap); + heap_buffer = detail::move_impl(heap_default); } //Initialize memory diff --git a/test/vector_test.hpp b/test/vector_test.hpp index 114017a..d2f17ac 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -48,18 +48,18 @@ bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) { IntType move_me(1); stdvector->insert(stdvector->begin()+size/2, 50, 1); - shmvector->insert(shmvector->begin()+size/2, 50, move(move_me)); + shmvector->insert(shmvector->begin()+size/2, 50, detail::move_impl(move_me)); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(2); - shmvector->assign(shmvector->size()/2, move(move_me)); + shmvector->assign(shmvector->size()/2, detail::move_impl(move_me)); stdvector->assign(stdvector->size()/2, 2); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(3); - shmvector->assign(shmvector->size()*3-1, move(move_me)); + shmvector->assign(shmvector->size()*3-1, detail::move_impl(move_me)); stdvector->assign(stdvector->size()*3-1, 3); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } @@ -109,7 +109,7 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType new_int(i); - shmvector->insert(shmvector->end(), move(new_int)); + shmvector->insert(shmvector->end(), detail::move_impl(new_int)); stdvector->insert(stdvector->end(), i); } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -131,7 +131,7 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = move(new_int); + aux_vect[i] = detail::move_impl(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -154,7 +154,7 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = move(new_int); + aux_vect[i] = detail::move_impl(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -172,7 +172,7 @@ int vector_test() if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; IntType push_back_this(1); - shmvector->push_back(move(push_back_this)); + shmvector->push_back(detail::move_impl(push_back_this)); stdvector->push_back(int(1)); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -187,7 +187,7 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType insert_this(i); - shmvector->insert(shmvector->begin(), move(insert_this)); + shmvector->insert(shmvector->begin(), detail::move_impl(insert_this)); stdvector->insert(stdvector->begin(), i); } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; From b045c841f0521b23b2a40701f39de89b03c6f538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 12:21:37 +0000 Subject: [PATCH 40/77] "this->purge_blocks()()" should be "this->purge_blocks()" [SVN r46578] --- include/boost/interprocess/allocators/detail/node_pool.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index 3e573d2..23c032c 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -331,7 +331,7 @@ class private_node_pool_impl //!Deprecated, use purge_blocks void purge_chunks() - { this->purge_blocks()(); } + { this->purge_blocks(); } private: //!Returns a reference to the block hook placed in the end of the block From 241740498595354cf79eb0025f7fe6c92ed996a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 17:20:02 +0000 Subject: [PATCH 41/77] gcc 4.3 fixes for normal and -std=c++0x modes [SVN r46581] --- include/boost/interprocess/containers/detail/tree.hpp | 9 ++++----- include/boost/interprocess/containers/vector.hpp | 10 ++++++++-- include/boost/interprocess/detail/algorithms.hpp | 9 +++++++++ include/boost/interprocess/detail/workaround.hpp | 7 +++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/detail/tree.hpp index 0e042d8..2bd77bb 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/detail/tree.hpp @@ -130,7 +130,7 @@ struct rbtree_node { m_data = v; } public: - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) template static void construct(node_type *ptr, const Convertible &value) @@ -149,7 +149,7 @@ struct rbtree_node new((void*)ptr) hack_node_t(value); } - #else + #elif !defined(BOOST_INTERPROCESS_RVALUE_PAIR) template static void construct(node_type *ptr, Convertible &&value) @@ -167,19 +167,18 @@ struct rbtree_node new((void*)ptr) hack_node_t(value); } - #endif }; }//namespace detail { - +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) template struct has_own_construct_from_it < boost::interprocess::detail::rbtree_node > { static const bool value = true; }; - +#endif namespace detail { template diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 2663a61..85bd620 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -434,7 +434,10 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for copy constructors //so that std::copy and similar can use memcpy typedef typename detail::if_c - ::value + ::value + #endif ,T* ,detail::move_iterator >::type copy_move_it; @@ -442,7 +445,10 @@ class vector : private detail::vector_alloc_holder //This is the optimized move iterator for assignments //so that std::uninitialized_copy and similar can use memcpy typedef typename detail::if_c - ::value + ::value + #endif ,T* ,detail::move_iterator >::type assign_move_it; diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index 9538c46..a949e96 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -30,6 +30,8 @@ namespace boost { namespace interprocess { +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) + template struct has_own_construct_from_it { @@ -59,12 +61,19 @@ inline void construct_in_place(T* dest, InpIt source) detail::construct_in_place_impl(dest, source, boolean_t()); } +#else +template +inline void construct_in_place(T* dest, InpIt source) +{ new((void*)dest)T(*source); } +#endif + template inline void construct_in_place(T *dest, default_construct_iterator) { new((void*)dest)T(); } + template struct optimize_assign { diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index 1bc1b3a..9e4f3fa 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -107,8 +107,11 @@ // 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_INTERPROCESS_RVALUE_REFERENCE -# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES +# define BOOST_INTERPROCESS_RVALUE_REFERENCE +# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES +# if defined(__GLIBCPP__) || defined(__GLIBCXX__) +# define BOOST_INTERPROCESS_RVALUE_PAIR +# endif # endif #endif From 1876ffd0b9cb8f6a2699ea5357420de5659dc36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 21 Jun 2008 17:20:20 +0000 Subject: [PATCH 42/77] gcc 4.3 fixes for normal and -std=c++0x modes [SVN r46582] --- proj/to-do.txt | 4 +++- test/adaptive_node_pool_test.cpp | 12 +++++++----- test/node_pool_test.cpp | 7 ++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/proj/to-do.txt b/proj/to-do.txt index 99dd486..1a56abb 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -39,4 +39,6 @@ -> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ --> add contiguous_elements option to burst allocation \ No newline at end of file +-> add contiguous_elements option to burst allocation + +-> Completely erase is_movable in code and tests for compilers with rvalue reference \ No newline at end of file diff --git a/test/adaptive_node_pool_test.cpp b/test/adaptive_node_pool_test.cpp index 11ce510..4ecdafb 100644 --- a/test/adaptive_node_pool_test.cpp +++ b/test/adaptive_node_pool_test.cpp @@ -10,16 +10,18 @@ #include #include "node_pool_test.hpp" #include - #include +using namespace boost::interprocess; +typedef managed_shared_memory::segment_manager segment_manager_t; + +//Explicit specialization to catch compilation errors +template class detail::private_adaptive_node_pool_impl; + int main () { - using namespace boost::interprocess; - typedef managed_shared_memory::segment_manager segment_manager; - typedef detail::private_adaptive_node_pool - node_pool_t; + node_pool_t; if(!test::test_all_node_pool()) return 1; diff --git a/test/node_pool_test.cpp b/test/node_pool_test.cpp index 418ce4d..da4dcc2 100644 --- a/test/node_pool_test.cpp +++ b/test/node_pool_test.cpp @@ -11,14 +11,15 @@ #include "node_pool_test.hpp" #include +using namespace boost::interprocess; +typedef managed_shared_memory::segment_manager segment_manager_t; +template class detail::private_node_pool_impl; int main () { - using namespace boost::interprocess; - typedef managed_shared_memory::segment_manager segment_manager; typedef detail::private_node_pool - node_pool_t; + node_pool_t; if(!test::test_all_node_pool()) return 1; From 4438851b1dfacd0640fbd3a6214e032e48b32c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 22 Jun 2008 08:16:41 +0000 Subject: [PATCH 43/77] Missing boost/static_assert.hpp include [SVN r46601] --- include/boost/interprocess/detail/math_functions.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index f1faf80..5623924 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -17,6 +17,7 @@ #define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP #include +#include namespace boost { namespace interprocess { From db781340737b2eecccc8032250679cfa95ba839a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 22 Jun 2008 17:43:15 +0000 Subject: [PATCH 44/77] Fixes to avoid documentation warnings with Boostbook [SVN r46615] --- include/boost/interprocess/containers/flat_set.hpp | 11 +++++++++++ include/boost/interprocess/containers/slist.hpp | 5 +++-- include/boost/interprocess/containers/string.hpp | 3 ++- include/boost/interprocess/detail/math_functions.hpp | 2 +- include/boost/interprocess/file_mapping.hpp | 3 ++- .../interprocess/indexes/unordered_map_index.hpp | 4 ++++ include/boost/interprocess/ipc/message_queue.hpp | 3 ++- include/boost/interprocess/mapped_region.hpp | 4 ++-- .../boost/interprocess/mem_algo/rbtree_best_fit.hpp | 4 ++++ include/boost/interprocess/shared_memory_object.hpp | 4 ++-- .../smart_ptr/enable_shared_from_this.hpp | 4 ++++ include/boost/interprocess/sync/file_lock.hpp | 2 ++ .../interprocess/sync/interprocess_condition.hpp | 2 ++ .../sync/interprocess_upgradable_mutex.hpp | 5 ++++- include/boost/interprocess/sync/named_condition.hpp | 7 +++++++ .../boost/interprocess/sync/named_recursive_mutex.hpp | 4 ++++ .../interprocess/sync/named_upgradable_mutex.hpp | 5 ++++- include/boost/interprocess/windows_shared_memory.hpp | 4 ++-- 18 files changed, 62 insertions(+), 14 deletions(-) diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index e4e3339..bdffbf5 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -588,6 +588,17 @@ inline bool operator<(const flat_multiset& x, const flat_multiset& 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 flat_multiset { diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index ecf60a5..a0724e2 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -1426,7 +1426,8 @@ struct has_trivial_destructor_after_move > // Specialization of insert_iterator so that insertions will be constant // time rather than linear time. -//iG +///@cond + //Ummm, I don't like to define things in namespace std, but //there is no other way namespace std { @@ -1464,7 +1465,7 @@ class insert_iterator > } //namespace std; - +///@endcond #include diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 2be6993..33ca269 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -520,8 +520,9 @@ class basic_string /// @endcond public: // Constructor, destructor, assignment. - + /// @cond struct reserve_t {}; + /// @endcond basic_string(reserve_t, std::size_t n, const allocator_type& a = allocator_type()) diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 5623924..7094b78 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -89,7 +89,7 @@ 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); + BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true)); std::size_t n = x; std::size_t log2 = 0; diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index 28b3662..acab048 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -160,6 +160,8 @@ inline file_mapping::file_mapping m_mode = mode; } +///@cond + inline void file_mapping::priv_close() { if(m_handle != detail::invalid_file()){ @@ -168,7 +170,6 @@ inline void file_mapping::priv_close() } } -///@cond //!Trait class to detect if a type is //!movable diff --git a/include/boost/interprocess/indexes/unordered_map_index.hpp b/include/boost/interprocess/indexes/unordered_map_index.hpp index 8c2f670..7c91148 100644 --- a/include/boost/interprocess/indexes/unordered_map_index.hpp +++ b/include/boost/interprocess/indexes/unordered_map_index.hpp @@ -27,6 +27,8 @@ namespace boost { namespace interprocess { +///@cond + //!Helper class to define typedefs from //!IndexTraits template @@ -55,6 +57,8 @@ struct unordered_map_index_aux 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 diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index 4a48b5d..757a367 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -368,7 +368,6 @@ class initialization_func_t }; } //namespace detail { -/// @endcond inline message_queue::~message_queue() {} @@ -611,6 +610,8 @@ inline std::size_t message_queue::get_num_msg() inline bool message_queue::remove(const char *name) { return shared_memory_object::remove(name); } +/// @endcond + }} //namespace boost{ namespace interprocess{ #include diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index dad831e..b3808a0 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -152,6 +152,8 @@ class mapped_region /// @endcond }; +///@cond + inline void swap(mapped_region &x, mapped_region &y) { x.swap(y); } @@ -556,8 +558,6 @@ inline void mapped_region::swap(mapped_region &other) #endif } -/// @cond - //!No-op functor struct null_mapped_region_function { diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index f24db2d..9634116 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -352,6 +352,8 @@ class rbtree_best_fit static const std::size_t PayloadPerAllocation = AllocatedCtrlBytes - UsableByPreviousChunk; }; +/// @cond + template inline std::size_t rbtree_best_fit ::priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes) @@ -1332,6 +1334,8 @@ void rbtree_best_fit::priv_deallocate(vo priv_mark_as_free_block(block_to_insert); } +/// @endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index 6bdc3ea..c07c79f 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -152,6 +152,8 @@ class shared_memory_object /// @endcond }; +/// @cond + inline shared_memory_object::shared_memory_object() : m_handle(file_handle_t(detail::invalid_file())) {} @@ -343,8 +345,6 @@ inline void shared_memory_object::priv_close() #endif -///@cond - //!Trait class to detect if a type is //!movable template<> diff --git a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp index b984b8b..5d1c98e 100644 --- a/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp +++ b/include/boost/interprocess/smart_ptr/enable_shared_from_this.hpp @@ -27,6 +27,10 @@ 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 and shared_ptr, depending on constness, to this. template class enable_shared_from_this { diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index ae3597a..d3f7e0b 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -32,6 +32,8 @@ 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 diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 1ec3f74..59ebbdb 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -50,6 +50,8 @@ 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 diff --git a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp index c600e4c..80c975d 100644 --- a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -266,6 +266,8 @@ class interprocess_upgradable_mutex /// @endcond }; +/// @cond + template const unsigned interprocess_upgradable_mutex::base_constants_t::max_readers; @@ -633,8 +635,9 @@ inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradab return true; } -} //namespace interprocess { +/// @endcond +} //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index acdb6c2..cc3b758 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -40,6 +40,9 @@ namespace interprocess { 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 @@ -183,6 +186,8 @@ class named_condition /// @endcond }; +/// @cond + inline named_condition::~named_condition() {} @@ -329,6 +334,8 @@ inline bool named_condition::timed_wait inline bool named_condition::remove(const char *name) { return shared_memory_object::remove(name); } +/// @endcond + } //namespace interprocess } //namespace boost diff --git a/include/boost/interprocess/sync/named_recursive_mutex.hpp b/include/boost/interprocess/sync/named_recursive_mutex.hpp index 3d62284..9f8b8f3 100644 --- a/include/boost/interprocess/sync/named_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/named_recursive_mutex.hpp @@ -108,6 +108,8 @@ class named_recursive_mutex /// @endcond }; +/// @cond + inline named_recursive_mutex::~named_recursive_mutex() {} @@ -159,6 +161,8 @@ inline bool named_recursive_mutex::timed_lock(const boost::posix_time::ptime &ab inline bool named_recursive_mutex::remove(const char *name) { return shared_memory_object::remove(name); } +/// @endcond + } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/sync/named_upgradable_mutex.hpp b/include/boost/interprocess/sync/named_upgradable_mutex.hpp index 853ced4..79c624f 100644 --- a/include/boost/interprocess/sync/named_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -233,6 +233,8 @@ class named_upgradable_mutex /// @endcond }; +/// @cond + inline named_upgradable_mutex::~named_upgradable_mutex() {} @@ -339,8 +341,9 @@ inline bool named_upgradable_mutex::try_unlock_sharable_and_lock_upgradable() inline bool named_upgradable_mutex::remove(const char *name) { return shared_memory_object::remove(name); } -} //namespace interprocess { +/// @endcond +} //namespace interprocess { } //namespace boost { #include diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index 976e0c0..88165be 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -143,6 +143,8 @@ class windows_shared_memory /// @endcond }; +/// @cond + inline windows_shared_memory::windows_shared_memory() : m_handle(0) {} @@ -235,8 +237,6 @@ inline void windows_shared_memory::priv_close() } } -///@cond - //!Trait class to detect if a type is //!movable template<> From 513cf6fbb4ae55e1a91700e32a392206e703cbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 22 Jun 2008 17:43:22 +0000 Subject: [PATCH 45/77] Fixes to avoid documentation warnings with Boostbook [SVN r46616] --- proj/to-do.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proj/to-do.txt b/proj/to-do.txt index 1a56abb..785bafa 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -41,4 +41,6 @@ -> add contiguous_elements option to burst allocation --> Completely erase is_movable in code and tests for compilers with rvalue reference \ No newline at end of file +-> Completely erase is_movable in code and tests for compilers with rvalue reference + +-> named_xxx classes and file lock should be movable \ No newline at end of file From 2e27404b333ab993b1fafce8825fffe91697098a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 27 Jun 2008 18:19:38 +0000 Subject: [PATCH 46/77] Some fixes for inspection report, Run Date: 15:00:47 UTC, Friday 27 June 2008 [SVN r46786] --- .../boost/interprocess/containers/string.hpp | 12 +- .../boost/interprocess/containers/vector.hpp | 12 +- .../boost/interprocess/detail/algorithms.hpp | 4 +- .../interprocess/detail/config_begin.hpp | 25 ++-- .../boost/interprocess/detail/config_end.hpp | 9 ++ .../interprocess/detail/math_functions.hpp | 2 +- .../smart_ptr/detail/sp_counted_base.hpp | 11 ++ .../interprocess/sync/math_functions.hpp | 110 ------------------ 8 files changed, 52 insertions(+), 133 deletions(-) delete mode 100644 include/boost/interprocess/sync/math_functions.hpp diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 33ca269..b1bf30d 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -1952,7 +1952,7 @@ operator+(const basic_string& x, const detail::moved_object >& my) { typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), x); + return my.get().replace(size_type(0), size_type(0), x); } #else template @@ -1961,7 +1961,7 @@ operator+(const basic_string& x, basic_string && my) { typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), x); + return my.replace(size_type(0), size_type(0), x); } #endif @@ -1986,7 +1986,7 @@ operator+(const CharT* s, const detail::moved_object >& my) { typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), s); + return my.get().replace(size_type(0), size_type(0), s); } #else template @@ -1995,7 +1995,7 @@ operator+(const CharT* s, basic_string && my) { typedef typename basic_string::size_type size_type; - return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); + return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); } #endif @@ -2019,7 +2019,7 @@ operator+(CharT c, const detail::moved_object >& my) { typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), &c, &c + 1); + return my.get().replace(size_type(0), size_type(0), &c, &c + 1); } #else template @@ -2028,7 +2028,7 @@ operator+(CharT c, basic_string && my) { typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), &c, &c + 1); + return my.replace(size_type(0), size_type(0), &c, &c + 1); } #endif diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 85bd620..5372eda 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -1042,7 +1042,7 @@ class vector : private detail::vector_alloc_holder T *pos = detail::get_pointer(position.get_ptr()); T *beg = detail::get_pointer(this->members_.m_start); - std::copy(assign_move_it(pos + 1), assign_move_it(beg + this->members_.m_size), pos); + std::copy(assign_move_it(pos + 1), assign_move_it(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); @@ -1056,12 +1056,12 @@ class vector : private detail::vector_alloc_holder //! Complexity: 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 + 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(std::copy (assign_move_it(detail::get_pointer(last.get_ptr())) ,assign_move_it(end_pos) - ,detail::get_pointer(first.get_ptr()) + ,detail::get_pointer(first.get_ptr()) )); size_type destroyed = (end_pos - ptr); this->destroy_n(ptr, destroyed); @@ -1310,8 +1310,8 @@ class vector : private detail::vector_alloc_holder //Destroy and deallocate old elements //If there is allocated memory, destroy and deallocate if(this->members_.m_start != 0){ - if(!base_t::trivial_dctr_after_move) - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); + if(!base_t::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; @@ -1702,7 +1702,7 @@ class vector : private detail::vector_alloc_holder 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->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; diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index a949e96..62e3637 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -121,7 +121,7 @@ template inline T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) { std::size_t size = length*sizeof(T); - return ((T*)std::memmove(dest, first, size)) + size; + return ((T*)std::memmove(dest, first, size)) + size; } template inline @@ -165,7 +165,7 @@ template inline T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) { std::size_t size = length*sizeof(T); - return ((T*)std::memmove(dest, first, size)) + size; + return ((T*)std::memmove(dest, first, size)) + size; } template inline diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp index e872b53..0273a8e 100644 --- a/include/boost/interprocess/detail/config_begin.hpp +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -1,3 +1,12 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 @@ -15,20 +24,20 @@ #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 : 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 : 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 : 4996) // "function": was declared deprecated #pragma warning (disable : 4197) // top-level volatile in cast is ignored #endif diff --git a/include/boost/interprocess/detail/config_end.hpp b/include/boost/interprocess/detail/config_end.hpp index 5c6ad50..1e6c30e 100644 --- a/include/boost/interprocess/detail/config_end.hpp +++ b/include/boost/interprocess/detail/config_end.hpp @@ -1,3 +1,12 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 diff --git a/include/boost/interprocess/detail/math_functions.hpp b/include/boost/interprocess/detail/math_functions.hpp index 7094b78..3d750ea 100644 --- a/include/boost/interprocess/detail/math_functions.hpp +++ b/include/boost/interprocess/detail/math_functions.hpp @@ -97,7 +97,7 @@ inline std::size_t floor_log2 (std::size_t x) for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ std::size_t tmp = n >> shift; if (tmp) - log2 += shift, n = tmp; + log2 += shift, n = tmp; } return log2; diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp index 9d144f5..8d0c65d 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_base.hpp @@ -1,3 +1,14 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 diff --git a/include/boost/interprocess/sync/math_functions.hpp b/include/boost/interprocess/sync/math_functions.hpp deleted file mode 100644 index 54d4126..0000000 --- a/include/boost/interprocess/sync/math_functions.hpp +++ /dev/null @@ -1,110 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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 //BOOST_STATIC_ASSERT -#include //CHAR_BIT - -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 -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 -inline Integer lcm(const Integer & A, const Integer & B) -{ - Integer ret = A; - ret /= gcd(A, B); - ret *= B; - return ret; -} - -template -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 -inline Integer upper_power_of_2(const Integer & A) -{ - Integer power_of_2 = 1; - - while(power_of_2 < A){ - power_of_2 <<= 1; - } - return power_of_2; -} - -//This function uses binary search to discover the -//highest set bit of the integer -inline std::size_t floor_log2 (std::size_t x) -{ - const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT; - const bool Size_t_Bits_Power_2= !(Bits & (Bits-1)); - BOOST_STATIC_ASSERT(Size_t_Bits_Power_2); - - std::size_t n = x; - std::size_t log2 = 0; - - for(std::size_t shift = Bits >> 1; shift; shift >>= 1){ - std::size_t tmp = n >> shift; - if (tmp) - log2 += shift, n = tmp; - } - - return log2; -} - -} // namespace detail -} // namespace interprocess -} // namespace boost - -#endif From 66800fc44589bf9b3899b7153e35d9e304501aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 27 Jun 2008 18:20:47 +0000 Subject: [PATCH 47/77] Some fixes for inspection report, Run Date: 15:00:47 UTC, Friday 27 June 2008 [SVN r46787] --- index.html | 5 +++++ proj/to-do.txt | 46 ---------------------------------------------- 2 files changed, 5 insertions(+), 46 deletions(-) delete mode 100644 proj/to-do.txt diff --git a/index.html b/index.html index 099c9e8..a656e41 100644 --- a/index.html +++ b/index.html @@ -1,3 +1,8 @@ + diff --git a/proj/to-do.txt b/proj/to-do.txt deleted file mode 100644 index 785bafa..0000000 --- a/proj/to-do.txt +++ /dev/null @@ -1,46 +0,0 @@ --> Implement zero_memory flag for allocation_command - --> The general allocation funtion can be improved with some fixed size allocation bins. - --> Adapt error reporting to TR1 system exceptions - --> Improve exception messages - --> Movability of containers should depend on the no-throw guarantee of allocators copy constructor - --> Check self-assignment for vectors - --> Update writing a new memory allocator explaining new functions (like alignment) - --> private node allocators could take the number of nodes as a runtime parameter. - --> Explain how to build intrusive indexes. - --> Add intrusive index types as available indexes. - --> Add maximum alignment allocation limit in PageSize bytes. Otherwise, we can't - guarantee alignment for process-shared allocations. - --> Add default algorithm and index types. The user does not need to know how are - they implemented. - --> Pass max size check in allocation to node pools - --> Use in-place expansion capabilities to shrink_to_fit and reserve functions - from iunordered_index. - --> Keep an eye on container iterator constness issue to bring Interprocess containers up-to-date. - --> change unique_ptr to avoid using compressed_pair - --> Improve unique_ptr test to test move assignment and other goodies like assigment from null - --> barrier_test fails on MacOS X on PowerPC. - --> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ - --> add contiguous_elements option to burst allocation - --> Completely erase is_movable in code and tests for compilers with rvalue reference - --> named_xxx classes and file lock should be movable \ No newline at end of file From 0f43d3613acc2330773517205e1ba00a9af614b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 30 Jun 2008 16:56:05 +0000 Subject: [PATCH 48/77] Fixed bug for unix systems in file locking functions [SVN r46922] --- include/boost/interprocess/detail/os_file_functions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp index 0a81c59..35e7e72 100644 --- a/include/boost/interprocess/detail/os_file_functions.hpp +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -310,7 +310,7 @@ inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired) lock.l_len = 0; int ret = ::fcntl(hnd, F_SETLK, &lock); if(ret == -1){ - return (errno != EAGAIN && errno != EACCES) ? + return (errno == EAGAIN || errno == EACCES) ? acquired = false, true : false; } return (acquired = true); @@ -345,7 +345,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) lock.l_len = 0; int ret = ::fcntl(hnd, F_SETLK, &lock); if(ret == -1){ - return (errno != EAGAIN && errno != EACCES) ? + return (errno == EAGAIN || errno == EACCES) ? acquired = false, true : false; } return (acquired = true); From 51446228122b131d81149c1699aa7fa2aa661e2b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 2 Jul 2008 19:52:59 +0000 Subject: [PATCH 49/77] Fix an import path. [SVN r47002] --- doc/interprocess.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 21be343..e0bd4a0 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -6418,7 +6418,7 @@ will manage the index. `segment_manager` will define interesting internal types For example, the index type `flat_map_index` based in `boost::interprocess::flat_map` is just defined as: -[import ../../boost/interprocess/indexes/flat_map_index.hpp] +[import ../../../boost/interprocess/indexes/flat_map_index.hpp] [flat_map_index] From ec9b099a8f15325acc97547d3ee63aebc4a766be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 1 Aug 2008 14:05:32 +0000 Subject: [PATCH 50/77] Added FILE_SHARE_DELETE to CreateFile to allow unix-like behaviour when deleting shared memory [SVN r47929] --- include/boost/interprocess/detail/win32_api.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index b07910d..2860bda 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -65,6 +65,7 @@ static const unsigned long file_map_all_access = section_all_access; 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 generic_read = 0x80000000L; static const unsigned long generic_write = 0x40000000L; @@ -355,7 +356,7 @@ static inline void *map_view_of_file_ex(void *handle, unsigned long file_access, { return MapViewOfFileEx(handle, file_access, highoffset, lowoffset, numbytes, base_addr); } static inline void *create_file(const char *name, unsigned long access, unsigned long creation_flags, unsigned long attributes = 0) -{ return CreateFileA(name, access, file_share_read | file_share_write, 0, creation_flags, attributes, 0); } +{ 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); } From 6a6b28ed385a4e699cc11a9179a4eb5564321485 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Fri, 10 Oct 2008 16:10:00 +0000 Subject: [PATCH 51/77] Change includes of to . Previously if Boost.TR1 was in the include path then including pulls in all the new TR1 math functions, which in turn also requires linking to an external library. With auto-linking support this requires that library to have been built and be present in the library search path, even if the actual library under use is header only. Fixes #2392. [SVN r49254] --- .../boost/interprocess/allocators/detail/adaptive_node_pool.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index c5ef2a4..ed464b6 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include //!\file From 02d366387bc3f62674e665a150d58f58b3c61978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 11 Oct 2008 13:14:49 +0000 Subject: [PATCH 52/77] Changes and fixes for Boost 1.37 [SVN r49276] --- .../interprocess/allocators/allocator.hpp | 2 +- .../allocators/detail/adaptive_node_pool.hpp | 21 +- .../allocators/detail/node_pool.hpp | 15 +- .../interprocess/anonymous_shared_memory.hpp | 12 +- .../boost/interprocess/containers/deque.hpp | 970 +++++++++--------- .../containers/detail/flat_tree.hpp | 204 +++- .../containers/detail/node_alloc_holder.hpp | 112 +- .../interprocess/containers/detail/tree.hpp | 302 ++++-- .../interprocess/containers/flat_map.hpp | 277 +++-- .../interprocess/containers/flat_set.hpp | 187 +++- .../boost/interprocess/containers/list.hpp | 254 +++-- include/boost/interprocess/containers/map.hpp | 102 ++ include/boost/interprocess/containers/set.hpp | 167 +++ .../boost/interprocess/containers/slist.hpp | 265 +++-- .../boost/interprocess/containers/string.hpp | 2 + .../boost/interprocess/containers/vector.hpp | 806 +++++++++------ .../detail/advanced_insert_int.hpp | 395 +++++++ .../boost/interprocess/detail/algorithms.hpp | 11 +- include/boost/interprocess/detail/atomic.hpp | 8 +- .../interprocess/detail/config_begin.hpp | 4 + .../interprocess/detail/intersegment_ptr.hpp | 69 +- .../detail/managed_memory_impl.hpp | 10 +- .../detail/managed_multi_shared_memory.hpp | 4 +- .../detail/managed_open_or_create_impl.hpp | 8 +- include/boost/interprocess/detail/move.hpp | 12 + .../boost/interprocess/detail/named_proxy.hpp | 195 ++-- .../interprocess/detail/os_file_functions.hpp | 13 +- .../interprocess/detail/preprocessor.hpp | 113 ++ .../detail/segment_manager_helper.hpp | 30 +- .../boost/interprocess/detail/type_traits.hpp | 41 +- .../boost/interprocess/detail/utilities.hpp | 155 ++- .../detail/variadic_templates_tools.hpp | 153 +++ .../boost/interprocess/detail/win32_api.hpp | 17 +- include/boost/interprocess/errors.hpp | 2 +- include/boost/interprocess/file_mapping.hpp | 2 +- .../boost/interprocess/interprocess_fwd.hpp | 5 + .../boost/interprocess/ipc/message_queue.hpp | 36 +- include/boost/interprocess/mapped_region.hpp | 11 +- .../mem_algo/detail/mem_algo_common.hpp | 37 +- .../detail/multi_simple_seq_fit_impl.hpp | 72 +- .../mem_algo/detail/simple_seq_fit_impl.hpp | 75 +- .../interprocess/mem_algo/rbtree_best_fit.hpp | 85 +- include/boost/interprocess/offset_ptr.hpp | 16 +- .../boost/interprocess/segment_manager.hpp | 88 +- .../interprocess/shared_memory_object.hpp | 1 + .../interprocess/smart_ptr/unique_ptr.hpp | 2 +- .../boost/interprocess/smart_ptr/weak_ptr.hpp | 2 +- .../sync/emulation/interprocess_condition.hpp | 16 +- .../sync/emulation/interprocess_mutex.hpp | 10 +- .../interprocess_recursive_mutex.hpp | 4 + .../sync/emulation/interprocess_semaphore.hpp | 4 + include/boost/interprocess/sync/file_lock.hpp | 8 + .../sync/interprocess_condition.hpp | 12 +- .../interprocess/sync/interprocess_mutex.hpp | 2 +- .../sync/interprocess_recursive_mutex.hpp | 3 +- .../sync/interprocess_semaphore.hpp | 4 +- .../sync/interprocess_upgradable_mutex.hpp | 12 + .../boost/interprocess/sync/lock_options.hpp | 2 +- .../interprocess/sync/named_condition.hpp | 16 + .../boost/interprocess/sync/named_mutex.hpp | 16 +- .../sync/named_recursive_mutex.hpp | 8 +- .../interprocess/sync/named_semaphore.hpp | 16 +- .../sync/named_upgradable_mutex.hpp | 26 +- .../sync/posix/interprocess_mutex.hpp | 4 + .../posix/interprocess_recursive_mutex.hpp | 4 + .../sync/posix/interprocess_semaphore.hpp | 8 +- .../sync/posix/semaphore_wrapper.hpp | 2 +- .../boost/interprocess/sync/sharable_lock.hpp | 2 +- .../interprocess/sync/upgradable_lock.hpp | 4 +- 69 files changed, 3895 insertions(+), 1658 deletions(-) create mode 100644 include/boost/interprocess/detail/advanced_insert_int.hpp create mode 100644 include/boost/interprocess/detail/preprocessor.hpp create mode 100644 include/boost/interprocess/detail/variadic_templates_tools.hpp diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index a6f1eee..60c7fb6 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -147,7 +147,7 @@ class allocator (void)hint; if(count > this->max_size()) throw bad_alloc(); - return pointer((value_type*)mp_mngr->allocate(count*sizeof(T))); + return pointer(static_cast(mp_mngr->allocate(count*sizeof(T)))); } //!Deallocates memory previously allocated. diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index ed464b6..30a6c07 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -410,14 +410,14 @@ class private_adaptive_node_pool_impl (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((block_info_t*)detail::get_pointer(to_deallocate)); + 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 + //#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 @@ -463,10 +463,10 @@ class private_adaptive_node_pool_impl 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((char*)&*it- (char*)hdr_off_holder)); + assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast(&*it)- reinterpret_cast(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 = (hdr_offset_holder *)((char*)hdr_off_holder + m_real_block_alignment); + hdr_off_holder = reinterpret_cast(reinterpret_cast(hdr_off_holder) + m_real_block_alignment); } } } @@ -498,19 +498,20 @@ class private_adaptive_node_pool_impl block_info_t *priv_block_from_node(void *node) const { hdr_offset_holder *hdr_off_holder = - (hdr_offset_holder*)((std::size_t)node & std::size_t(~(m_real_block_alignment - 1))); + reinterpret_cast((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 = (block_info_t *)(((char*)hdr_off_holder) + hdr_off_holder->hdr_offset); + block_info_t *block = reinterpret_cast + (reinterpret_cast(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 = (hdr_offset_holder*) - (((char*)block) - (m_num_subblocks-1)*m_real_block_alignment); - assert(hdr_off_holder->hdr_offset == std::size_t((char*)block - (char*)hdr_off_holder)); + hdr_offset_holder *hdr_off_holder = reinterpret_cast + (reinterpret_cast(block) - (m_num_subblocks-1)*m_real_block_alignment); + assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast(block) - reinterpret_cast(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; @@ -526,7 +527,7 @@ class private_adaptive_node_pool_impl 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 = detail::char_ptr_cast + char *mem_address = static_cast (mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment)); if(!mem_address) throw std::bad_alloc(); ++m_totally_free_blocks; diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index 23c032c..bf6c758 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -96,7 +96,7 @@ class private_node_pool_impl if (m_freelist.empty()) priv_alloc_block(); //We take the first free node - node_t *n = (node_t*)&m_freelist.front(); + node_t *n = &m_freelist.front(); m_freelist.pop_front(); ++m_allocated; return n; @@ -292,13 +292,13 @@ class private_node_pool_impl : std::unary_function { is_between(const void *addr, std::size_t size) - : beg_((const char *)addr), end_(beg_+size) + : beg_(static_cast(addr)), end_(beg_+size) {} bool operator()(typename free_nodes_t::const_reference v) const { - return (beg_ <= (const char *)&v && - end_ > (const char *)&v); + return (beg_ <= reinterpret_cast(&v) && + end_ > reinterpret_cast(&v)); } private: const char * beg_; @@ -312,7 +312,7 @@ class private_node_pool_impl //element in the free Node list std::size_t blocksize = detail::get_rounded_size(m_real_node_size*m_nodes_per_block, alignment_of::value); - char *pNode = detail::char_ptr_cast + char *pNode = reinterpret_cast (mp_segment_mngr_base->allocate(blocksize + sizeof(node_t))); if(!pNode) throw bad_alloc(); char *pBlock = pNode; @@ -337,14 +337,13 @@ class private_node_pool_impl //!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 *static_cast( - static_cast((detail::char_ptr_cast(block) + blocksize))); + return *reinterpret_cast(reinterpret_cast(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 static_cast((detail::char_ptr_cast(hook) - blocksize)); + return (reinterpret_cast(hook) - blocksize); } private: diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp index 3e8a57c..e933e3c 100644 --- a/include/boost/interprocess/anonymous_shared_memory.hpp +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -93,12 +93,12 @@ anonymous_shared_memory(std::size_t size, void *address = 0) #endif - address = mmap( (void*)address - , size - , PROT_READ|PROT_WRITE - , flags - , fd - , 0); + address = mmap( address + , size + , PROT_READ|PROT_WRITE + , flags + , fd + , 0); if(address == MAP_FAILED){ if(fd != -1) diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index d73b501..c4661d2 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -57,16 +57,21 @@ #include #include #include -#include #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include #include #include -#include +#include namespace boost { namespace interprocess { @@ -75,6 +80,21 @@ namespace interprocess { template class deque; +template +struct deque_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::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) @@ -105,16 +125,18 @@ class deque_base typedef allocator_type stored_allocator_type; protected: - enum { trivial_dctr_after_move = boost::has_trivial_destructor::value }; + typedef deque_value_traits traits_t; typedef typename Alloc::template rebind::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(deque_buf_size(sizeof(T))); } + { return this->alloc().allocate(s_buffer_size()); } void priv_deallocate_node(val_alloc_ptr p) - { this->alloc().deallocate(p, deque_buf_size(sizeof(T))); } + { this->alloc().deallocate(p, s_buffer_size()); } ptr_alloc_ptr priv_allocate_map(std::size_t n) { return this->ptr_alloc().allocate(n); } @@ -153,7 +175,7 @@ class deque_base val_alloc_cptr, val_alloc_cref> { public: - static std::size_t s_buffer_size() { return deque_buf_size(sizeof(T)); } + static std::size_t s_buffer_size() { return deque_base::s_buffer_size(); } typedef std::random_access_iterator_tag iterator_category; typedef val_alloc_val value_type; @@ -297,7 +319,7 @@ class deque_base public: typedef std::random_access_iterator_tag iterator_category; typedef val_alloc_val value_type; - typedef ptr_alloc_ptr pointer; + typedef val_alloc_ptr pointer; typedef val_alloc_ref reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; @@ -371,34 +393,40 @@ class deque_base 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) { - std::size_t num_nodes = num_elements / deque_buf_size(sizeof(T)) + 1; +// 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); + 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 + 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 % deque_buf_size(sizeof(T)); + 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) @@ -495,10 +523,14 @@ class deque : protected deque_base typedef std::reverse_iterator reverse_iterator; /// @cond - protected: // Internal typedefs + private: // Internal typedefs typedef ptr_alloc_ptr index_pointer; static std::size_t s_buffer_size() - { return deque_buf_size(sizeof(T)); } + { return Base::s_buffer_size(); } + typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef repeat_iterator r_iterator; + typedef detail::move_iterator move_it; + /// @endcond allocator_type get_allocator() const { return Base::alloc(); } @@ -528,6 +560,18 @@ class deque : protected deque_base 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)]; } @@ -545,18 +589,12 @@ class deque : protected deque_base reference front() { return *this->members_.m_start; } - reference back() - { - iterator tmp = this->members_.m_finish; - --tmp; - return *tmp; - } + reference back() { return *(end()-1); } const_reference front() const { return *this->members_.m_start; } - const_reference back() const - { const_iterator tmp = this->members_.m_finish; --tmp; return *tmp; } + const_reference back() const { return *(cend()-1); } size_type size() const { return this->members_.m_finish - this->members_.m_start; } @@ -565,10 +603,11 @@ class deque : protected deque_base { return this->alloc().max_size(); } bool empty() const - { return this->members_.m_finish == this->members_.m_start; } + { return this->members_.m_finish == this->members_.m_start; } explicit deque(const allocator_type& a = allocator_type()) - : Base(a, 0) {} + : Base(a) + {} deque(const deque& x) : Base(x.alloc(), x.size()) @@ -576,11 +615,11 @@ class deque : protected deque_base #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE deque(const detail::moved_object &mx) - : Base(mx.get()) + : Base(mx.get().alloc()) { this->swap(mx.get()); } #else deque(deque &&x) - : Base(detail::move_impl(x)) + : Base(x.alloc()) { this->swap(x); } #endif @@ -593,8 +632,8 @@ class deque : protected deque_base // Check whether it's an integral type. If so, it's not an iterator. template - deque(InpIt first, InpIt last, - const allocator_type& a = allocator_type()) : Base(a) + 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::value; @@ -603,7 +642,9 @@ class deque : protected deque_base } ~deque() - { priv_destroy_range(this->members_.m_start, this->members_.m_finish); } + { + priv_destroy_range(this->members_.m_start, this->members_.m_finish); + } deque& operator= (const deque& x) { @@ -622,13 +663,22 @@ class deque : protected deque_base #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE deque& operator= (const detail::moved_object &mx) - { this->clear(); this->swap(mx.get()); return *this; } + { + deque &x = mx.get(); #else - deque& operator= (deque &&mx) - { this->clear(); this->swap(mx); return *this; } + deque& operator= (deque &&x) + { #endif + this->clear(); + this->swap(x); + return *this; + } + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE 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); @@ -639,16 +689,14 @@ class deque : protected deque_base #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void swap(const detail::moved_object &mx) { this->swap(mx.get()); } - #else - void swap(deque &&mx) - { this->swap(mx); } #endif void assign(size_type n, const T& val) { this->priv_fill_assign(n, val); } template - void assign(InpIt first, InpIt last) { + void assign(InpIt first, InpIt last) + { //Dispatch depending on integer/iterator const bool aux_boolean = detail::is_convertible::value; typedef detail::bool_ Result; @@ -657,67 +705,59 @@ class deque : protected deque_base void push_back(const value_type& t) { - if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); - ++this->members_.m_finish.m_cur; + 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); } - else - this->priv_push_back_aux(t); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void push_back(const detail::moved_object &mt) { - if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); - ++this->members_.m_finish.m_cur; - } - else - this->priv_push_back_aux(mt); - } + value_type &t = mt.get(); #else - void push_back(value_type &&mt) + void push_back(value_type &&t) { - if (this->members_.m_finish.m_cur != this->members_.m_finish.m_last - 1) { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(detail::move_impl(mt)); - ++this->members_.m_finish.m_cur; - } - else - this->priv_push_back_aux(detail::move_impl(mt)); - } #endif + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(detail::move_impl(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->members_.m_start.m_cur != this->members_.m_start.m_first) { - new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(t); - --this->members_.m_start.m_cur; + 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); } - else - this->priv_push_front_aux(t); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void push_front(const detail::moved_object &mt) { - if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(mt); - --this->members_.m_start.m_cur; - } - else - this->priv_push_front_aux(mt); - } + value_type &t = mt.get(); #else - void push_front(value_type &&mt) + void push_front(value_type &&t) { - if (this->members_.m_start.m_cur != this->members_.m_start.m_first) { - new((void*)(detail::get_pointer(this->members_.m_start.m_cur)- 1))value_type(detail::move_impl(mt)); - --this->members_.m_start.m_cur; - } - else - this->priv_push_front_aux(detail::move_impl(mt)); - } #endif + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(detail::move_impl(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() { @@ -739,65 +779,53 @@ class deque : protected deque_base this->priv_pop_front_aux(); } - iterator insert(iterator position, const value_type& x) + iterator insert(const_iterator position, const value_type& x) { - if (position.m_cur == this->members_.m_start.m_cur) { + if (position == cbegin()){ this->push_front(x); - return this->members_.m_start; + return begin(); } - else if (position.m_cur == this->members_.m_finish.m_cur) { + else if (position == cend()){ this->push_back(x); - iterator tmp = this->members_.m_finish; - --tmp; - return tmp; + return (end()-1); } else { - return this->priv_insert_aux(position, x); + size_type n = position - cbegin(); + this->priv_insert_aux(position, size_type(1), x); + return iterator(this->begin() + n); } } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object &mx) + iterator insert(const_iterator position, const detail::moved_object &m) { - if (position.m_cur == this->members_.m_start.m_cur) { - this->push_front(mx); - return this->members_.m_start; - } - else if (position.m_cur == this->members_.m_finish.m_cur) { - this->push_back(mx); - iterator tmp = this->members_.m_finish; - --tmp; - return tmp; - } - else { - return this->priv_insert_aux(position, mx); - } - } + value_type &mx = m.get(); #else - iterator insert(iterator position, value_type &&mx) + iterator insert(const_iterator position, value_type &&mx) { - if (position.m_cur == this->members_.m_start.m_cur) { + #endif + if (position == cbegin()) { this->push_front(detail::move_impl(mx)); - return this->members_.m_start; + return begin(); } - else if (position.m_cur == this->members_.m_finish.m_cur) { + else if (position == cend()) { this->push_back(detail::move_impl(mx)); - iterator tmp = this->members_.m_finish; - --tmp; - return tmp; + return(end()-1); } else { - return this->priv_insert_aux(position, detail::move_impl(mx)); + //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); } } - #endif - void insert(iterator pos, size_type n, const value_type& x) - { this->priv_fill_insert(pos, n, x); } + 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 - void insert(iterator pos, InpIt first, InpIt last) + void insert(const_iterator pos, InpIt first, InpIt last) { //Dispatch depending on integer/iterator const bool aux_boolean = detail::is_convertible::value; @@ -805,6 +833,158 @@ class deque : protected deque_base this->priv_insert_dispatch(pos, first, last, Result()); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + template + void emplace_back(Args&&... args) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(detail::forward_impl(args)...); + this->priv_push_back_simple_commit(); + } + else{ + detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); + this->priv_insert_aux_impl(this->cend(), 1, proxy); + } + } + + template + void emplace_front(Args&&... args) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(detail::forward_impl(args)...); + this->priv_push_front_simple_commit(); + } + else{ + detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); + this->priv_insert_aux_impl(this->cbegin(), 1, proxy); + } + } + + template + iterator emplace(const_iterator p, Args&&... args) + { + if(p == this->cbegin()){ + this->emplace_front(detail::forward_impl(args)...); + return this->begin(); + } + else if(p == this->cend()){ + this->emplace_back(detail::forward_impl(args)...); + return (this->end()-1); + } + else{ + size_type n = p - this->cbegin(); + detail::advanced_insert_aux_emplace proxy(detail::forward_impl(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 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 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 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 \ + 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) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cend(), 1, proxy); \ + } \ + } \ + \ + template \ + 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) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cbegin(), 1, proxy); \ + } \ + } \ + \ + template \ + 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) \ + \ + 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(); @@ -821,41 +1001,32 @@ class deque : protected deque_base this->erase(this->members_.m_start + new_size, this->members_.m_finish); else{ size_type n = new_size - this->size(); - this->priv_reserve_elements_at_back(new_size); - - while(n--){ - //T default_constructed = detail::move_impl(T()); - T default_constructed; -/* if(boost::is_scalar::value){ - //Value initialization - new(&default_constructed)T(); - }*/ - this->push_back(detail::move_impl(default_constructed)); - } + detail::default_construct_aux_proxy proxy(n); + priv_insert_aux_impl(this->cend(), n, proxy); } } - iterator erase(iterator pos) + iterator erase(const_iterator pos) { - iterator next = pos; + const_iterator next = pos; ++next; difference_type index = pos - this->members_.m_start; if (size_type(index) < (this->size() >> 1)) { - std::copy_backward( detail::make_move_iterator(this->members_.m_start) - , detail::make_move_iterator(pos) - , next); + std::copy_backward( detail::make_move_iterator(begin()) + , detail::make_move_iterator(iterator(pos)) + , iterator(next)); pop_front(); } else { - std::copy( detail::make_move_iterator(next) - , detail::make_move_iterator(this->members_.m_finish) - , pos); + std::copy( detail::make_move_iterator(iterator(next)) + , detail::make_move_iterator(end()) + , iterator(pos)); pop_back(); } return this->members_.m_start + index; } - iterator erase(iterator first, iterator last) + iterator erase(const_iterator first, const_iterator last) { if (first == this->members_.m_start && last == this->members_.m_finish) { this->clear(); @@ -865,21 +1036,21 @@ class deque : protected deque_base difference_type n = last - first; difference_type elems_before = first - this->members_.m_start; if (elems_before < static_cast(this->size() - n) - elems_before) { - std::copy_backward( detail::make_move_iterator(this->members_.m_start) - , detail::make_move_iterator(first) - , last); + std::copy_backward( detail::make_move_iterator(begin()) + , detail::make_move_iterator(iterator(first)) + , iterator(last)); iterator new_start = this->members_.m_start + n; - if(!Base::trivial_dctr_after_move) + 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 { - std::copy( detail::make_move_iterator(last) - , detail::make_move_iterator(this->members_.m_finish) - , first); + std::copy( detail::make_move_iterator(iterator(last)) + , detail::make_move_iterator(end()) + , iterator(first)); iterator new_finish = this->members_.m_finish - n; - if(!Base::trivial_dctr_after_move) + 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; @@ -911,56 +1082,58 @@ class deque : protected deque_base /// @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(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(detail::get_pointer(this->members_.m_start.m_cur) - 1); } + + void priv_push_front_simple_commit() + { --this->members_.m_start.m_cur; } + template - void insert(iterator pos, InpIt first, InpIt last, std::input_iterator_tag) - { std::copy(first, last, std::inserter(*this, pos)); } + void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, move_impl(value_type(*first))); + } + } template - void insert(iterator pos, FwdIt first, FwdIt last, std::forward_iterator_tag) - { - - size_type n = 0; - n = std::distance(first, last); - - if (pos.m_cur == this->members_.m_start.m_cur) { - iterator new_start = this->priv_reserve_elements_at_front(n); - BOOST_TRY{ - std::uninitialized_copy(first, last, new_start); - this->members_.m_start = new_start; - } - BOOST_CATCH(...){ - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); - BOOST_RETHROW - } - BOOST_CATCH_END - } - else if (pos.m_cur == this->members_.m_finish.m_cur) { - iterator new_finish = this->priv_reserve_elements_at_back(n); - BOOST_TRY{ - std::uninitialized_copy(first, last, this->members_.m_finish); - this->members_.m_finish = new_finish; - } - BOOST_CATCH(...){ - this->priv_destroy_nodes(this->members_.m_finish.m_node + 1, new_finish.m_node + 1); - BOOST_RETHROW - } - BOOST_CATCH_END - } - else - this->priv_insert_aux(pos, first, last, n); - } + 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) { + void priv_fill_assign(size_type n, const T& val) + { if (n > size()) { std::fill(begin(), end(), val); - this->insert(end(), n - size(), val); + this->insert(cend(), n - size(), val); } else { - this->erase(begin() + n, end()); + this->erase(cbegin() + n, cend()); std::fill(begin(), end(), val); } } @@ -1009,112 +1182,80 @@ class deque : protected deque_base for ( ; first != last && cur != end(); ++cur, ++first) *cur = *first; if (first == last) - this->erase(cur, end()); + this->erase(cur, cend()); else - this->insert(end(), first, last); + this->insert(cend(), first, last); } template - void priv_assign_aux(FwdIt first, FwdIt last, - std::forward_iterator_tag) { - size_type len = 0; - std::distance(first, last, len); + 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(end(), mid, last); + this->insert(cend(), mid, last); } else - this->erase(std::copy(first, last, begin()), end()); + this->erase(std::copy(first, last, begin()), cend()); } template - void priv_insert_dispatch(iterator pos, Integer n, Integer x, - detail::true_) - { - this->priv_fill_insert(pos, (size_type) n, (value_type) x); - } + 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 - void priv_insert_dispatch(iterator pos, - InpIt first, InpIt last, - detail::false_) + void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, detail::false_) { typedef typename std::iterator_traits::iterator_category ItCat; - this->insert(pos, first, last, ItCat()); + this->priv_insert_aux(pos, first, last, ItCat()); } - iterator priv_insert_aux(iterator pos, const value_type& x) - { - size_type n = pos - begin(); - this->priv_insert_aux(pos, size_type(1), x); - return iterator(this->begin() + n); - } - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator priv_insert_aux(iterator pos, const detail::moved_object &mx) - { - typedef repeat_iterator r_iterator; - typedef detail::move_iterator move_it; - //Just call more general insert(pos, size, value) and return iterator - size_type n = pos - begin(); - this->insert(pos - ,move_it(r_iterator(mx.get(), 1)) - ,move_it(r_iterator())); - return iterator(this->begin() + n); - } - #else - iterator priv_insert_aux(iterator pos, value_type &&mx) - { - typedef repeat_iterator r_iterator; - typedef detail::move_iterator move_it; - //Just call more general insert(pos, size, value) and return iterator - size_type n = pos - begin(); - this->insert(pos - ,move_it(r_iterator(mx, 1)) - ,move_it(r_iterator())); - return iterator(this->begin() + n); - } - #endif - - void priv_insert_aux(iterator pos, size_type n, const value_type& x) + void priv_insert_aux(const_iterator pos, size_type n, const value_type& x) { typedef constant_iterator c_it; - this->insert(pos, c_it(x, n), c_it()); + this->priv_insert_aux(pos, c_it(x, n), c_it()); } + //Just forward all operations to priv_insert_aux_impl template - void priv_insert_aux(iterator pos, FwdIt first, FwdIt last, size_type n) + void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) { + detail::advanced_insert_aux_proxy 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 = size(); + size_type length = this->size(); if (elemsbefore < static_cast(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; - BOOST_TRY { - if (elemsbefore >= difference_type(n)) { - iterator start_n = this->members_.m_start + difference_type(n); - std::uninitialized_copy(detail::make_move_iterator(this->members_.m_start), detail::make_move_iterator(start_n), new_start); - this->members_.m_start = new_start; - std::copy(detail::make_move_iterator(start_n), detail::make_move_iterator(pos), old_start); - std::copy(first, last, pos - difference_type(n)); - } - else { - FwdIt mid = first; - std::advance(mid, difference_type(n) - elemsbefore); - this->priv_uninitialized_copy_copy - (detail::make_move_iterator(this->members_.m_start), detail::make_move_iterator(pos), first, mid, new_start); - this->members_.m_start = new_start; - std::copy(mid, last, old_start); - } + if (elemsbefore >= difference_type(n)) { + iterator start_n = this->members_.m_start + difference_type(n); + std::uninitialized_copy(detail::make_move_iterator(this->members_.m_start), detail::make_move_iterator(start_n), new_start); + this->members_.m_start = new_start; + std::copy(detail::make_move_iterator(start_n), detail::make_move_iterator(pos), old_start); + interf.copy_all_to(pos - difference_type(n)); } - BOOST_CATCH(...){ - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); - BOOST_RETHROW + 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; + std::uninitialized_copy(detail::make_move_iterator(old_start), detail::make_move_iterator(pos), new_start); + this->members_.m_start = new_start; + interf.copy_all_to(old_start); } - BOOST_CATCH_END } else { iterator new_finish = this->priv_reserve_elements_at_back(n); @@ -1122,31 +1263,24 @@ class deque : protected deque_base const difference_type elemsafter = difference_type(length) - elemsbefore; pos = this->members_.m_finish - elemsafter; - BOOST_TRY { - if (elemsafter > difference_type(n)) { - iterator finish_n = this->members_.m_finish - difference_type(n); - std::uninitialized_copy(detail::make_move_iterator(finish_n), detail::make_move_iterator(this->members_.m_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - std::copy_backward(detail::make_move_iterator(pos), detail::make_move_iterator(finish_n), old_finish); - std::copy(first, last, pos); - } - else { - FwdIt mid = first; - std::advance(mid, elemsafter); - this->priv_uninitialized_copy_copy(mid, last, detail::make_move_iterator(pos), detail::make_move_iterator(this->members_.m_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - std::copy(first, mid, pos); - } + if (elemsafter >= difference_type(n)) { + iterator finish_n = this->members_.m_finish - difference_type(n); + std::uninitialized_copy(detail::make_move_iterator(finish_n), detail::make_move_iterator(this->members_.m_finish), this->members_.m_finish); + this->members_.m_finish = new_finish; + std::copy_backward(detail::make_move_iterator(pos), detail::make_move_iterator(finish_n), old_finish); + interf.copy_all_to(pos); } - BOOST_CATCH(...){ - this->priv_destroy_nodes(this->members_.m_finish.m_node + 1, new_finish.m_node + 1); - BOOST_RETHROW + else { + interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); + this->members_.m_finish += n-elemsafter; + std::uninitialized_copy(detail::make_move_iterator(pos), detail::make_move_iterator(old_finish), this->members_.m_finish); + this->members_.m_finish = new_finish; + interf.copy_all_to(pos); } - BOOST_CATCH_END } } - void priv_fill_insert(iterator pos, size_type n, const value_type& x) + void priv_fill_insert(const_iterator pos, size_type n, const value_type& x) { typedef constant_iterator c_it; this->insert(pos, c_it(x, n), c_it()); @@ -1211,112 +1345,6 @@ class deque : protected deque_base BOOST_CATCH_END } - // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_last - 1. - void priv_push_back_aux(const value_type& t = value_type()) - { - this->priv_reserve_map_at_back(); - *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); - BOOST_TRY { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(t); - 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_first; - } - BOOST_CATCH(...){ - this->priv_deallocate_node(*(this->members_.m_finish.m_node + 1)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_last - 1. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void priv_push_back_aux(const detail::moved_object &mt) - { - this->priv_reserve_map_at_back(); - *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); - BOOST_TRY { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(mt); - 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_first; - } - BOOST_CATCH(...){ - this->priv_deallocate_node(*(this->members_.m_finish.m_node + 1)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #else - void priv_push_back_aux(value_type &&mt) - { - this->priv_reserve_map_at_back(); - *(this->members_.m_finish.m_node + 1) = this->priv_allocate_node(); - BOOST_TRY { - new((void*)detail::get_pointer(this->members_.m_finish.m_cur))value_type(detail::move_impl(mt)); - 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_first; - } - BOOST_CATCH(...){ - this->priv_deallocate_node(*(this->members_.m_finish.m_node + 1)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #endif - - // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_first. - void priv_push_front_aux(const value_type& t) - { - this->priv_reserve_map_at_front(); - *(this->members_.m_start.m_node - 1) = this->priv_allocate_node(); - BOOST_TRY { - 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_last - 1; - new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(t); - } - BOOST_CATCH(...){ - ++this->members_.m_start; - this->priv_deallocate_node(*(this->members_.m_start.m_node - 1)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void priv_push_front_aux(const detail::moved_object &mt) - { - this->priv_reserve_map_at_front(); - *(this->members_.m_start.m_node - 1) = this->priv_allocate_node(); - BOOST_TRY { - 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_last - 1; - new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(mt); - } - BOOST_CATCH(...){ - ++this->members_.m_start; - this->priv_deallocate_node(*(this->members_.m_start.m_node - 1)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #else - void priv_push_front_aux(value_type &&mt) - { - this->priv_reserve_map_at_front(); - *(this->members_.m_start.m_node - 1) = this->priv_allocate_node(); - BOOST_TRY { - 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_last - 1; - new((void*)detail::get_pointer(this->members_.m_start.m_cur))value_type(detail::move_impl(mt)); - } - BOOST_CATCH(...){ - ++this->members_.m_start; - this->priv_deallocate_node(*(this->members_.m_start.m_node - 1)); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #endif - // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first. void priv_pop_back_aux() { @@ -1341,70 +1369,54 @@ class deque : protected deque_base 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) - this->priv_new_elements_at_front(n - vacancies); + 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) - this->priv_new_elements_at_back(n - vacancies); + 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_new_elements_at_front(size_type new_elems) - { - size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / - this->s_buffer_size(); - this->priv_reserve_map_at_front(new_nodes); - size_type i = 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 - } - - void priv_new_elements_at_back(size_type new_elems) - { - size_type new_nodes = (new_elems + this->s_buffer_size() - 1) - / this->s_buffer_size(); - this->priv_reserve_map_at_back(new_nodes); - size_type i; - BOOST_TRY { - for (i = 1; i <= new_nodes; ++i) - *(this->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 - } - - // Makes sure the this->members_.m_map has space for new nodes. Does not actually - // add the nodes. Can invalidate this->members_.m_map pointers. (And consequently, - // deque iterators.) - void priv_reserve_map_at_back (size_type nodes_to_add = 1) - { - if (nodes_to_add + 1 > this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)) - this->priv_reallocate_map(nodes_to_add, false); - } - - void priv_reserve_map_at_front (size_type nodes_to_add = 1) - { - if (nodes_to_add > size_type(this->members_.m_start.m_node - this->members_.m_map)) - this->priv_reallocate_map(nodes_to_add, true); - } - void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) { size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1; @@ -1437,68 +1449,6 @@ class deque : protected deque_base this->members_.m_start.priv_set_node(new_nstart); this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); } - - // this->priv_uninitialized_copy_fill - // Copies [first1, last1) into [first2, first2 + (last1 - first1)), and - // fills [first2 + (last1 - first1), last2) with x. - void priv_uninitialized_copy_fill(iterator first1, iterator last1, - iterator first2, iterator last2, - const T& x) - { - iterator mid2 = std::uninitialized_copy(first1, last1, first2); - BOOST_TRY { - std::uninitialized_fill(mid2, last2, x); - } - BOOST_CATCH(...){ - for(;first2 != mid2; ++first2){ - detail::get_pointer(&*first2)->~value_type(); - } - BOOST_RETHROW - } - BOOST_CATCH_END - } - - // this->priv_uninitialized_fill_copy - // Fills [result, mid) with x, and copies [first, last) into - // [mid, mid + (last - first)). - iterator priv_uninitialized_fill_copy(iterator result, iterator mid, - const T& x, - iterator first, iterator last) - { - std::uninitialized_fill(result, mid, x); - BOOST_TRY { - return std::uninitialized_copy(first, last, mid); - } - BOOST_CATCH(...){ - for(;result != mid; ++result){ - detail::get_pointer(&*result)->~value_type(); - } - BOOST_RETHROW - } - BOOST_CATCH_END - } - - // this->priv_uninitialized_copy_copy - // Copies [first1, last1) into [result, result + (last1 - first1)), and - // copies [first2, last2) into - // [result, result + (last1 - first1) + (last2 - first2)). - template - FwdIt priv_uninitialized_copy_copy(InpIt1 first1, InpIt1 last1, - InpIt2 first2, InpIt2 last2, - FwdIt result) - { - FwdIt mid = std::uninitialized_copy(first1, last1, result); - BOOST_TRY { - return std::uninitialized_copy(first2, last2, mid); - } - BOOST_CATCH(...){ - for(;result != mid; ++result){ - detail::get_pointer(&*result)->~value_type(); - } - BOOST_RETHROW - } - BOOST_CATCH_END - } /// @endcond }; diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/detail/flat_tree.hpp index b4777f2..76503b4 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/detail/flat_tree.hpp @@ -175,25 +175,37 @@ class flat_tree { 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 const_reverse_iterator(this->end()); } + { 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 const_reverse_iterator(this->begin()); } + { return this->crend(); } + + const_reverse_iterator crend() const + { return const_reverse_iterator(this->cbegin()); } bool empty() const { return this->m_data.m_vect.empty(); } @@ -237,24 +249,18 @@ class flat_tree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE std::pair insert_unique(const detail::moved_object& mval) { - insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(mval.get(), data); - if(ret.second){ - ret.first = priv_insert_commit(data, mval); - } - return ret; - } + value_type &val = mval.get(); #else - std::pair insert_unique(value_type && mval) + std::pair insert_unique(value_type && val) { + #endif insert_commit_data data; - std::pair ret = priv_insert_unique_prepare(mval, data); + std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(mval)); + ret.first = priv_insert_commit(data, detail::move_impl(val)); } return ret; } - #endif iterator insert_equal(const value_type& val) @@ -350,6 +356,146 @@ class flat_tree priv_insert_equal(first, last, ItCat()); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + template + iterator emplace_unique(Args&&... args) + { + value_type val(detail::forward_impl(args)...); + insert_commit_data data; + std::pair ret = + priv_insert_unique_prepare(val, data); + if(ret.second){ + ret.first = priv_insert_commit(data, detail::move_impl(val)); + } + return ret.first; + } + + template + iterator emplace_hint_unique(const_iterator hint, Args&&... args) + { + value_type val(detail::forward_impl(args)...); + insert_commit_data data; + std::pair ret = priv_insert_unique_prepare(hint, val, data); + if(ret.second){ + ret.first = priv_insert_commit(data, detail::move_impl(val)); + } + return ret.first; + } + + template + iterator emplace_equal(Args&&... args) + { + value_type val(detail::forward_impl(args)...); + iterator i = this->upper_bound(KeyOfValue()(val)); + i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + return i; + } + + template + iterator emplace_hint_equal(const_iterator hint, Args&&... args) + { + value_type val(detail::forward_impl(args)...); + insert_commit_data data; + priv_insert_equal_prepare(hint, val, data); + return priv_insert_commit(data, detail::move_impl(val)); + } + + #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + iterator emplace_unique() + { + detail::value_init vval; + value_type &val = vval.m_t; + insert_commit_data data; + std::pair ret = + priv_insert_unique_prepare(val, data); + if(ret.second){ + ret.first = priv_insert_commit(data, detail::move_impl(val)); + } + return ret.first; + } + + iterator emplace_hint_unique(const_iterator hint) + { + detail::value_init vval; + value_type &val = vval.m_t; + insert_commit_data data; + std::pair ret = priv_insert_unique_prepare(hint, val, data); + if(ret.second){ + ret.first = priv_insert_commit(data, detail::move_impl(val)); + } + return ret.first; + } + + iterator emplace_equal() + { + detail::value_init vval; + value_type &val = vval.m_t; + iterator i = this->upper_bound(KeyOfValue()(val)); + i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + return i; + } + + iterator emplace_hint_equal(const_iterator hint) + { + detail::value_init vval; + value_type &val = vval.m_t; + insert_commit_data data; + priv_insert_equal_prepare(hint, val, data); + return priv_insert_commit(data, detail::move_impl(val)); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + 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 ret = priv_insert_unique_prepare(val, data); \ + if(ret.second){ \ + ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + } \ + return ret.first; \ + } \ + \ + template \ + 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 ret = priv_insert_unique_prepare(hint, val, data); \ + if(ret.second){ \ + ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + } \ + return ret.first; \ + } \ + \ + template \ + 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, detail::move_impl(val)); \ + return i; \ + } \ + \ + template \ + 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, detail::move_impl(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); } @@ -435,14 +581,13 @@ class flat_tree private: struct insert_commit_data { - iterator position; + const_iterator position; }; // insert/erase void priv_insert_equal_prepare - (const_iterator p, const value_type& val, insert_commit_data &data) + (const_iterator pos, const value_type& val, insert_commit_data &data) { - iterator &pos = (iterator &)(const_iterator &)p; // N1780 // To insert val at pos: // if pos == end || val <= *pos @@ -456,13 +601,13 @@ class flat_tree // insert val before lower_bound(val) const value_compare &value_comp = this->m_data; - if(pos == this->end() || !value_comp(*pos, val)){ - if (pos == this->begin() || !value_comp(val, pos[-1])){ + 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->begin(), pos, KeyOfValue()(val)); + this->priv_upper_bound(this->cbegin(), pos, KeyOfValue()(val)); } } //Works, but increases code complexity @@ -471,17 +616,17 @@ class flat_tree //} else{ data.position = - this->priv_lower_bound(pos, this->end(), KeyOfValue()(val)); + this->priv_lower_bound(pos, this->cend(), KeyOfValue()(val)); } } std::pair priv_insert_unique_prepare - (iterator beg, iterator end, const value_type& val, insert_commit_data &commit_data) + (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 - ( commit_data.position + ( *reinterpret_cast(&commit_data.position) , commit_data.position == end || value_comp(val, *commit_data.position)); } @@ -490,9 +635,8 @@ class flat_tree { return priv_insert_unique_prepare(this->begin(), this->end(), val, commit_data); } std::pair priv_insert_unique_prepare - (const_iterator p, const value_type& val, insert_commit_data &commit_data) + (const_iterator pos, const value_type& val, insert_commit_data &commit_data) { - iterator &pos = (iterator &)(const_iterator &)p; //N1780. Props to Howard Hinnant! //To insert val at pos: //if pos == end || val <= *pos @@ -506,17 +650,17 @@ class flat_tree // insert val before lower_bound(val) const value_compare &value_comp = this->m_data; - if(pos == this->end() || value_comp(val, *pos)){ - if(pos != this->begin() && !value_comp(val, pos[-1])){ + if(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 = iterator(pos); - return std::pair(pos, true); + commit_data.position = pos; + return std::pair(*reinterpret_cast(&pos), true); } else{ - return std::pair(pos, false); + return std::pair(*reinterpret_cast(&pos), false); } } - return this->priv_insert_unique_prepare(this->begin(), pos, val, commit_data); + return this->priv_insert_unique_prepare(this->cbegin(), pos, val, commit_data); } // Works, but increases code complexity diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index 5eca3fe..dbb5377 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -54,7 +54,7 @@ struct node_compare { return static_cast(*this); } bool operator()(const Node &a, const Node &b) const - { return ValueCompare::operator()(a.m_data, b.m_data); } + { return ValueCompare::operator()(a.get_data(), b.get_data()); } }; template @@ -142,23 +142,9 @@ struct node_alloc_holder void deallocate_one(NodePtr p, allocator_v2) { this->node_alloc().deallocate_one(p); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static void construct(const NodePtr &ptr, const Convertible &value) - { new((void*)detail::get_pointer(ptr)) Node(value); } - #else - template - static void construct(const NodePtr &ptr, Convertible &&value) - { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(value)); } - #endif - - static void construct(const NodePtr &ptr) - { new((void*)detail::get_pointer(ptr)) Node(); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - static void construct(const NodePtr &ptr, - const detail::moved_object > &value) + static void construct(const NodePtr &ptr, const detail::moved_object > &value) { typedef typename Node::hook_type hook_type; typedef typename Node::value_type::first_type first_type; @@ -168,7 +154,7 @@ struct node_alloc_holder //Hook constructor does not throw new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder - value_type *valueptr = &nodeptr->m_data; + value_type *valueptr = &nodeptr->get_data(); new((void*)&valueptr->first) first_type(detail::move_impl(value.get().first)); BOOST_TRY{ new((void*)&valueptr->second) second_type(detail::move_impl(value.get().second)); @@ -182,8 +168,7 @@ struct node_alloc_holder } #else template - static void construct(const NodePtr &ptr, - std::pair &&value) + static void construct(const NodePtr &ptr, std::pair &&value) { typedef typename Node::hook_type hook_type; typedef typename Node::value_type::first_type first_type; @@ -193,7 +178,7 @@ struct node_alloc_holder //Hook constructor does not throw new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder - value_type *valueptr = &nodeptr->m_data; + value_type *valueptr = &nodeptr->get_data(); new((void*)&valueptr->first) first_type(detail::move_impl(value.first)); BOOST_TRY{ new((void*)&valueptr->second) second_type(detail::move_impl(value.second)); @@ -210,27 +195,75 @@ struct node_alloc_holder static void destroy(const NodePtr &ptr) { detail::get_pointer(ptr)->~Node(); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - NodePtr create_node(const Convertible& x) - { - NodePtr p = this->allocate_one(); - Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, x); - node_deallocator.release(); - return (p); - } + + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + Deallocator #else - template - NodePtr create_node(Convertible &&x) + move_return + #endif + create_node_and_deallocator() { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, detail::forward_impl(x)); + return node_deallocator; + } + + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + template + static void construct(const NodePtr &ptr, Args &&...args) + { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(args)...); } + + template + NodePtr create_node(Args &&...args) + { + NodePtr p = this->allocate_one(); + Deallocator node_deallocator(p, this->node_alloc()); + self_t::construct(p, detail::forward_impl(args)...); node_deallocator.release(); return (p); } - #endif + + #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 \ + 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 \ + 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 NodePtr create_node_from_it(It it) @@ -242,15 +275,6 @@ struct node_alloc_holder return (p); } - NodePtr create_node() - { - NodePtr p = this->allocate_one(); - Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p); - node_deallocator.release(); - return (p); - } - void destroy_node(NodePtr node) { self_t::destroy(node); @@ -339,7 +363,7 @@ struct node_alloc_holder {} NodePtr operator()(const Node &other) const - { return m_holder.create_node(other.m_data); } + { return m_holder.create_node(other.get_data()); } node_alloc_holder &m_holder; }; diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/detail/tree.hpp index 2bd77bb..7ede6b1 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/detail/tree.hpp @@ -52,7 +52,11 @@ #include #include #include +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#endif +#include //std::pair #include #include @@ -84,39 +88,79 @@ struct value_compare_impl { return key_compare::operator()(KeyOfValue()(a), KeyOfValue()(b)); } }; -template -struct rbtree_node - : public bi::make_set_base_hook - < bi::void_pointer - , bi::link_mode - , bi::optimize_size - >::type +template +struct rbtree_hook { typedef typename bi::make_set_base_hook < bi::void_pointer , bi::link_mode , bi::optimize_size - >::type hook_type; + >::type type; +}; + +template +struct rbtree_type +{ + typedef T type; +}; + +template +struct rbtree_type< std::pair > +{ + typedef detail::pair type; +}; + +template +struct rbtree_node + : public rbtree_hook::type +{ + typedef typename rbtree_hook::type hook_type; typedef T value_type; + typedef typename rbtree_type::type internal_type; typedef rbtree_node node_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - rbtree_node(const Convertible &conv) - : m_data(conv){} - #else - template - rbtree_node(Convertible &&conv) - : m_data(detail::forward_impl(conv)){} - #endif + #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + + rbtree_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + 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 + rbtree_node(Args &&...args) + : m_data(detail::forward_impl(args)...) + {} + #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING rbtree_node &operator=(const rbtree_node &other) { do_assign(other.m_data); return *this; } - T m_data; - private: + T &get_data() + { + T* ptr = reinterpret_cast(&this->m_data); + return *ptr; + } + + const T &get_data() const + { + const T* ptr = reinterpret_cast(&this->m_data); + return *ptr; + } + + private: + internal_type m_data; template void do_assign(const std::pair &p) @@ -125,49 +169,27 @@ struct rbtree_node m_data.second = p.second; } + template + void do_assign(const detail::pair &p) + { + const_cast(m_data.first) = p.first; + m_data.second = p.second; + } + template void do_assign(const V &v) { m_data = v; } public: + template + + static void construct(node_type *ptr #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) - - template - static void construct(node_type *ptr, const Convertible &value) - { new(ptr) node_type(value); } - - template - static void construct(node_type *ptr, - const detail::moved_object > &value) - { - //std::pair is not movable so we define our own type and overwrite it - typedef detail::pair hack_pair_t; - - typedef rbtree_node hack_node_t; - - new((void*)ptr) hack_node_t(value); - } - - #elif !defined(BOOST_INTERPROCESS_RVALUE_PAIR) - - template - static void construct(node_type *ptr, Convertible &&value) - { new(ptr) node_type(detail::forward_impl(value)); } - - template - static void construct(node_type *ptr, - std::pair &&value) - { - //std::pair is not movable so we define our own type and overwrite it - typedef detail::pair hack_pair_t; - - typedef rbtree_node hack_node_t; - - new((void*)ptr) hack_node_t(value); - } + , const Convertible &value) + #else + , Convertible &&value) #endif + { new(ptr) node_type(detail::forward_impl(value)); } }; }//namespace detail { @@ -193,7 +215,7 @@ struct intrusive_rbtree_type typedef typename bi::make_rbtree - ,bi::base_hook + ,bi::base_hook::type> ,bi::constant_time_size ,bi::size_type >::type container_type; @@ -302,11 +324,11 @@ class rbtree template bool operator()(const Node &n, const KeyType &k) const - { return KeyValueCompare::operator()(n.m_data, k); } + { return KeyValueCompare::operator()(n.get_data(), k); } template bool operator()(const KeyType &k, const Node &n) const - { return KeyValueCompare::operator()(k, n.m_data); } + { return KeyValueCompare::operator()(k, n.get_data()); } }; typedef key_node_compare KeyNodeCompare; @@ -341,10 +363,10 @@ class rbtree //Pointer like operators const_reference operator*() const - { return m_it->m_data; } + { return m_it->get_data(); } const_pointer operator->() const - { return const_pointer(&m_it->m_data); } + { return const_pointer(&m_it->get_data()); } //Increment / Decrement const_iterator& operator++() @@ -387,8 +409,8 @@ class rbtree iterator(){} //Pointer like operators - reference operator*() const { return this->m_it->m_data; } - pointer operator->() const { return pointer(&this->m_it->m_data); } + reference operator*() const { return this->m_it->get_data(); } + pointer operator->() const { return pointer(&this->m_it->get_data()); } //Increment / Decrement iterator& operator++() @@ -495,25 +517,59 @@ class rbtree { return iterator(this->icont().begin()); } const_iterator begin() const - { return const_iterator(this->non_const_icont().begin()); } + { return this->cbegin(); } iterator end() { return iterator(this->icont().end()); } const_iterator end() const - { return const_iterator(this->non_const_icont().end()); } + { return this->cend(); } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const - { return const_reverse_iterator(end()); } + { return this->crbegin(); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const - { return const_reverse_iterator(begin()); } + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(cend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(cbegin()); } bool empty() const { return !this->size(); } @@ -621,6 +677,113 @@ class rbtree } #endif + private: + iterator emplace_unique_impl(NodePtr p) + { + value_type &v = p->get_data(); + insert_commit_data data; + std::pair 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 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 + iterator emplace_unique(Args&&... args) + { return this->emplace_unique_impl(AllocHolder::create_node(detail::forward_impl(args)...)); } + + template + iterator emplace_hint_unique(const_iterator hint, Args&&... args) + { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(detail::forward_impl(args)...)); } + + template + iterator emplace_equal(Args&&... args) + { + NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + return iterator(this->icont().insert_equal(this->icont().end(), *p)); + } + + template + iterator emplace_hint_equal(const_iterator hint, Args&&... args) + { + NodePtr p(AllocHolder::create_node(detail::forward_impl(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 \ + 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 \ + 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 \ + 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 \ + 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; @@ -663,7 +826,7 @@ class rbtree if(this->empty()){ //Insert with end hint, to achieve linear //complexity if [first, last) is ordered - iterator end(this->end()); + const_iterator end(this->end()); for( ; first != last; ++first) this->insert_unique(end, *first); } @@ -722,7 +885,7 @@ class rbtree { //Insert with end hint, to achieve linear //complexity if [first, last) is ordered - iterator end(this->end()); + const_iterator end(this->cend()); for( ; first != last; ++first) this->insert_equal(end, *first); } @@ -815,7 +978,6 @@ class rbtree class insertion_functor { Icont &icont_; - typename Icont::iterator pos_; public: insertion_functor(Icont &icont) @@ -823,7 +985,7 @@ class rbtree {} void operator()(Node &n) - { this->icont_.insert_equal(this->icont_.end(), n); } + { this->icont_.insert_equal(this->icont_.cend(), n); } }; diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 56e265d..62fab5e 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -77,7 +77,7 @@ class flat_map Pred, Alloc> tree_t; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE //This is the real tree stored here. It's based on a movable pair typedef detail::flat_tree, @@ -85,10 +85,11 @@ class flat_map Pred, typename Alloc::template rebind >::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; @@ -106,20 +107,17 @@ class flat_map typedef detail::moved_object impl_moved_value_type; #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static D &force(const S &s) - { return *((D*)(void*)(const void*)(&s)); } - #else - //For rvalue-aware compilers, just forward - template - static const Type &force(const Type &t) - { return t; } + { return *const_cast(reinterpret_cast(&s)); } - template - static Type &force(Type &t) - { return t; } - #endif + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } /// @endcond @@ -235,7 +233,7 @@ class flat_map //! //! Complexity: Constant. iterator begin() - { return force(m_flat_tree.begin()); } + { return force_copy(m_flat_tree.begin()); } //! Effects: Returns a const_iterator to the first element contained in the container. //! @@ -245,13 +243,21 @@ class flat_map const_iterator begin() const { return force(m_flat_tree.begin()); } + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return force(m_flat_tree.cbegin()); } + //! Effects: Returns an iterator to the end of the container. //! //! Throws: Nothing. //! //! Complexity: Constant. iterator end() - { return force(m_flat_tree.end()); } + { return force_copy(m_flat_tree.end()); } //! Effects: Returns a const_iterator to the end of the container. //! @@ -261,6 +267,14 @@ class flat_map const_iterator end() const { return force(m_flat_tree.end()); } + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return force(m_flat_tree.cend()); } + //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed container. //! @@ -279,6 +293,15 @@ class flat_map const_reverse_iterator rbegin() const { return force(m_flat_tree.rbegin()); } + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return force(m_flat_tree.crbegin()); } + //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed container. //! @@ -297,6 +320,15 @@ class flat_map const_reverse_iterator rend() const { return force(m_flat_tree.rend()); } + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return force(m_flat_tree.crend()); } + //! Effects: Returns true if the container contains no elements. //! //! Throws: Nothing. @@ -425,7 +457,8 @@ class flat_map m_flat_tree.insert_unique(force(x))); } #else std::pair insert(value_type &&x) - { return m_flat_tree.insert_unique(detail::move_impl(x)); } + { return force >( + m_flat_tree.insert_unique(detail::move_impl(force(x)))); } #endif //! Effects: Inserts a copy of x in the container if and only if there is @@ -439,9 +472,9 @@ class flat_map //! right before p) plus insertion linear to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - iterator insert(iterator position, const value_type& x) - { return force( - m_flat_tree.insert_unique(force(position), force(x))); } + iterator insert(const_iterator position, const value_type& x) + { return force_copy( + m_flat_tree.insert_unique(force(position), force(x))); } //! Effects: Inserts an element move constructed from x in the container. //! p is a hint pointing to where the insert should start to search. @@ -453,12 +486,13 @@ class flat_map //! //! Note: If an element it's inserted it might invalidate elements. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object& x) - { return force( - m_flat_tree.insert_unique(force(position), force(x))); } + iterator insert(const_iterator position, const detail::moved_object& x) + { return force_copy( + m_flat_tree.insert_unique(force(position), force(x))); } #else - iterator insert(iterator position, value_type &&x) - { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } + iterator insert(const_iterator position, value_type &&x) + { return force_copy( + m_flat_tree.insert_unique(force(position), detail::move_impl(force(x)))); } #endif //! Requires: i, j are not iterators into *this. @@ -472,7 +506,70 @@ class flat_map //! Note: If an element it's inserted it might invalidate elements. template void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } + { m_flat_tree.insert_unique(first, last); } + + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_unique(detail::forward_impl(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), detail::forward_impl(args)...)); } + + #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_unique()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_unique \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_unique \ + (force(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 //! Effects: Erases the element pointed to by position. //! @@ -485,7 +582,7 @@ class flat_map //! Note: Invalidates elements with keys //! not less than the erased element. iterator erase(const_iterator position) - { return force(m_flat_tree.erase(force(position))); } + { return force_copy(m_flat_tree.erase(force(position))); } //! Effects: Erases all elements in the container with key equivalent to x. //! @@ -505,7 +602,7 @@ class flat_map //! Complexity: Logarithmic search time plus erasure time //! linear to the elements with bigger keys. iterator erase(const_iterator first, const_iterator last) - { return force(m_flat_tree.erase(force(first), force(last))); } + { return force_copy(m_flat_tree.erase(force(first), force(last))); } //! Effects: erase(a.begin(),a.end()). //! @@ -529,7 +626,7 @@ class flat_map //! //! Complexity: Logarithmic. iterator find(const key_type& x) - { return force(m_flat_tree.find(x)); } + { return force_copy(m_flat_tree.find(x)); } //! Returns: A const_iterator pointing to an element with the key //! equivalent to x, or end() if such an element is not found. @@ -549,7 +646,7 @@ class flat_map //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x) - { return force(m_flat_tree.lower_bound(x)); } + { return force_copy(m_flat_tree.lower_bound(x)); } //! Returns: A const iterator pointing to the first element with key not //! less than k, or a.end() if such an element is not found. @@ -563,7 +660,7 @@ class flat_map //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x) - { return force(m_flat_tree.upper_bound(x)); } + { return force_copy(m_flat_tree.upper_bound(x)); } //! Returns: A const iterator pointing to the first element with key not //! less than x, or end() if such an element is not found. @@ -725,7 +822,7 @@ class flat_multimap detail::select1st< std::pair >, Pred, Alloc> tree_t; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE //This is the real tree stored here. It's based on a movable pair typedef detail::flat_tree, @@ -733,10 +830,11 @@ class flat_multimap Pred, typename Alloc::template rebind >::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; @@ -754,20 +852,17 @@ class flat_multimap typedef detail::moved_object impl_moved_value_type; #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template static D &force(const S &s) { return *const_cast((reinterpret_cast(&s))); } - #else - //For rvalue-aware compilers, just forward - template - static const Type &force(const Type &t) - { return t; } - template - static Type &force(Type &t) - { return t; } - #endif + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } /// @endcond public: @@ -882,7 +977,7 @@ class flat_multimap //! //! Complexity: Constant. iterator begin() - { return force(m_flat_tree.begin()); } + { return force_copy(m_flat_tree.begin()); } //! Effects: Returns a const_iterator to the first element contained in the container. //! @@ -898,7 +993,7 @@ class flat_multimap //! //! Complexity: Constant. iterator end() - { return force(m_flat_tree.end()); } + { return force_copy(m_flat_tree.end()); } //! Effects: Returns a const_iterator to the end of the container. //! @@ -999,7 +1094,7 @@ class flat_multimap //! //! Note: If an element it's inserted it might invalidate elements. iterator insert(const value_type& x) - { return force(m_flat_tree.insert_equal(force(x))); } + { return force_copy(m_flat_tree.insert_equal(force(x))); } //! Effects: Inserts a new value move-constructed from x and returns //! the iterator pointing to the newly inserted element. @@ -1010,10 +1105,10 @@ class flat_multimap //! Note: If an element it's inserted it might invalidate elements. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE iterator insert(const detail::moved_object& x) - { return force(m_flat_tree.insert_equal(force(x))); } + { return force_copy(m_flat_tree.insert_equal(force(x))); } #else iterator insert(value_type &&x) - { return m_flat_tree.insert_equal(detail::move_impl(x)); } + { return force_copy(m_flat_tree.insert_equal(detail::move_impl(x))); } #endif //! Effects: Inserts a copy of x in the container. @@ -1027,8 +1122,8 @@ class flat_multimap //! to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - iterator insert(iterator position, const value_type& x) - { return force(m_flat_tree.insert_equal(force(position), force(x))); } + iterator insert(const_iterator position, const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } //! Effects: Inserts a value move constructed from x in the container. //! p is a hint pointing to where the insert should start to search. @@ -1042,11 +1137,11 @@ class flat_multimap //! //! Note: If an element it's inserted it might invalidate elements. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object& x) - { return force(m_flat_tree.insert_equal(force(position), force(x))); } + iterator insert(const_iterator position, const detail::moved_object& x) + { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } #else - iterator insert(iterator position, value_type &&x) - { return m_flat_tree.insert_equal(force(position), detail::move_impl(x)); } + iterator insert(const_iterator position, value_type &&x) + { return force_copy(m_flat_tree.insert_equal(force(position), detail::move_impl(x))); } #endif //! Requires: i, j are not iterators into *this. @@ -1061,6 +1156,68 @@ class flat_multimap void insert(InputIterator first, InputIterator last) { m_flat_tree.insert_equal(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_equal(detail::forward_impl(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { + return force_copy(m_flat_tree.emplace_hint_equal + (force(hint), detail::forward_impl(args)...)); + } + + #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_equal()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_equal \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_equal \ + (force(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 + //! Effects: Erases the element pointed to by position. //! //! Returns: Returns an iterator pointing to the element immediately @@ -1072,7 +1229,7 @@ class flat_multimap //! Note: Invalidates elements with keys //! not less than the erased element. iterator erase(const_iterator position) - { return force(m_flat_tree.erase(force(position))); } + { return force_copy(m_flat_tree.erase(force(position))); } //! Effects: Erases all elements in the container with key equivalent to x. //! @@ -1092,7 +1249,7 @@ class flat_multimap //! Complexity: Logarithmic search time plus erasure time //! linear to the elements with bigger keys. iterator erase(const_iterator first, const_iterator last) - { return force(m_flat_tree.erase(force(first), force(last))); } + { return force_copy(m_flat_tree.erase(force(first), force(last))); } //! Effects: erase(a.begin(),a.end()). //! @@ -1116,7 +1273,7 @@ class flat_multimap //! //! Complexity: Logarithmic. iterator find(const key_type& x) - { return force(m_flat_tree.find(x)); } + { return force_copy(m_flat_tree.find(x)); } //! Returns: An const_iterator pointing to an element with the key //! equivalent to x, or end() if such an element is not found. @@ -1136,7 +1293,7 @@ class flat_multimap //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x) - {return force(m_flat_tree.lower_bound(x)); } + {return force_copy(m_flat_tree.lower_bound(x)); } //! Returns: A const iterator pointing to the first element with key //! not less than k, or a.end() if such an element is not found. @@ -1150,7 +1307,7 @@ class flat_multimap //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x) - {return force(m_flat_tree.upper_bound(x)); } + {return force_copy(m_flat_tree.upper_bound(x)); } //! Returns: A const iterator pointing to the first element with key //! not less than x, or end() if such an element is not found. @@ -1163,14 +1320,14 @@ class flat_multimap //! //! Complexity: Logarithmic std::pair equal_range(const key_type& x) - { return force >(m_flat_tree.equal_range(x)); } + { return force_copy >(m_flat_tree.equal_range(x)); } //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! //! Complexity: Logarithmic std::pair equal_range(const key_type& x) const - { return force >(m_flat_tree.equal_range(x)); } + { return force_copy >(m_flat_tree.equal_range(x)); } //! Effects: Number of elements for which memory has been allocated. //! capacity() is always greater than or equal to size(). diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index bdffbf5..9c2cb9e 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -185,6 +185,14 @@ class flat_set const_iterator begin() const { return m_flat_tree.begin(); } + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + //! Effects: Returns an iterator to the end of the container. //! //! Throws: Nothing. @@ -201,6 +209,14 @@ class flat_set const_iterator end() const { return m_flat_tree.end(); } + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed container. //! @@ -219,6 +235,15 @@ class flat_set const_reverse_iterator rbegin() const { return m_flat_tree.rbegin(); } + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed container. //! @@ -237,6 +262,15 @@ class flat_set const_reverse_iterator rend() const { return m_flat_tree.rend(); } + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + //! Effects: Returns true if the container contains no elements. //! //! Throws: Nothing. @@ -328,7 +362,7 @@ class flat_set //! right before p) plus insertion linear to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - iterator insert(iterator position, const value_type& x) + iterator insert(const_iterator position, const value_type& x) { return m_flat_tree.insert_unique(position, x); } //! Effects: Inserts an element move constructed from x in the container. @@ -341,10 +375,10 @@ class flat_set //! //! Note: If an element it's inserted it might invalidate elements. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object& x) + iterator insert(const_iterator position, const detail::moved_object& x) { return m_flat_tree.insert_unique(position, x); } #else - iterator insert(iterator position, value_type && x) + iterator insert(const_iterator position, value_type && x) { return m_flat_tree.insert_unique(position, detail::move_impl(x)); } #endif @@ -361,6 +395,62 @@ class flat_set void insert(InputIterator first, InputIterator last) { m_flat_tree.insert_unique(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_unique(detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_unique(hint, detail::forward_impl(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 \ + 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 \ + 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 + //! Effects: Erases the element pointed to by position. //! //! Returns: Returns an iterator pointing to the element immediately @@ -704,6 +794,14 @@ class flat_multiset const_iterator begin() const { return m_flat_tree.begin(); } + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + //! Effects: Returns an iterator to the end of the container. //! //! Throws: Nothing. @@ -720,6 +818,14 @@ class flat_multiset const_iterator end() const { return m_flat_tree.end(); } + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed container. //! @@ -738,6 +844,15 @@ class flat_multiset const_reverse_iterator rbegin() const { return m_flat_tree.rbegin(); } + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed container. //! @@ -756,6 +871,15 @@ class flat_multiset const_reverse_iterator rend() const { return m_flat_tree.rend(); } + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + //! Effects: Returns true if the container contains no elements. //! //! Throws: Nothing. @@ -838,7 +962,7 @@ class flat_multiset //! right before p) plus insertion linear to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - iterator insert(iterator position, const value_type& x) + iterator insert(const_iterator position, const value_type& x) { return m_flat_tree.insert_equal(position, x); } //! Effects: Inserts a new value move constructed from x in the container. @@ -852,10 +976,10 @@ class flat_multiset //! //! Note: If an element it's inserted it might invalidate elements. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object& x) + iterator insert(const_iterator position, const detail::moved_object& x) { return m_flat_tree.insert_equal(position, x); } #else - iterator insert(iterator position, value_type && x) + iterator insert(const_iterator position, value_type && x) { return m_flat_tree.insert_equal(position, detail::move_impl(x)); } #endif @@ -871,6 +995,57 @@ class flat_multiset void insert(InputIterator first, InputIterator last) { m_flat_tree.insert_equal(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_equal(detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_equal(hint, detail::forward_impl(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 \ + 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 \ + 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 + //! Effects: Erases the element pointed to by position. //! //! Returns: Returns an iterator pointing to the element immediately diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index 751408d..9f74caa 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -49,7 +49,6 @@ #include #include - #include #include #include @@ -60,6 +59,11 @@ #include #include +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + #include #include #include @@ -73,29 +77,40 @@ namespace interprocess { /// @cond namespace detail { -template -struct list_node - : public bi::make_list_base_hook - , bi::link_mode >::type +template +struct list_hook { typedef typename bi::make_list_base_hook - , bi::link_mode >::type hook_type; + , bi::link_mode >::type type; +}; + +template +struct list_node + : public list_hook::type +{ + + #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING list_node() : m_data() {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - list_node(const Convertible &conv) - : m_data(conv) + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + 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 + list_node(Args &&...args) + : m_data(detail::forward_impl(args)...) {} - #else - template - list_node(Convertible &&conv) - : m_data(detail::forward_impl(conv)) - {} - #endif + #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING T m_data; }; @@ -110,7 +125,7 @@ struct intrusive_list_type node_type; typedef typename bi::make_list < node_type - , bi::base_hook + , bi::base_hook::type> , bi::constant_time_size , bi::size_type >::type container_type; @@ -335,7 +350,7 @@ class list //! Complexity: Linear to n. list(size_type n, const T& value = T(), const A& a = A()) : AllocHolder(a) - { this->insert(begin(), n, value); } + { this->insert(this->cbegin(), n, value); } //! Effects: Copy constructs a list. //! @@ -346,7 +361,7 @@ class list //! Complexity: Linear to the elements x contains. list(const list& x) : AllocHolder(x) - { this->insert(begin(), x.begin(), x.end()); } + { this->insert(this->cbegin(), x.begin(), x.end()); } //! Effects: Move constructor. Moves mx's resources to *this. //! @@ -373,7 +388,7 @@ class list template list(InpIt first, InpIt last, const A &a = A()) : AllocHolder(a) - { insert(begin(), first, last); } + { this->insert(this->cbegin(), first, last); } //! Effects: Destroys the list. All stored values are destroyed //! and used memory is deallocated. @@ -420,7 +435,7 @@ class list //! //! Complexity: Constant. const_iterator begin() const - { return const_iterator(this->non_const_icont().begin()); } + { return this->cbegin(); } //! Effects: Returns an iterator to the end of the list. //! @@ -436,7 +451,7 @@ class list //! //! Complexity: Constant. const_iterator end() const - { return const_iterator(this->non_const_icont().end()); } + { return this->cend(); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed list. @@ -454,7 +469,7 @@ class list //! //! Complexity: Constant. const_reverse_iterator rbegin() const - { return const_reverse_iterator(end()); } + { return this->crbegin(); } //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed list. @@ -472,7 +487,41 @@ class list //! //! Complexity: Constant. const_reverse_iterator rend() const - { return const_reverse_iterator(begin()); } + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->cend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->cbegin()); } //! Effects: Returns true if the list contains no elements. //! @@ -505,7 +554,7 @@ class list //! //! Complexity: Amortized constant time. void push_front(const T& x) - { this->insert(this->begin(), x); } + { this->insert(this->cbegin(), x); } //! Effects: Constructs a new element in the beginning of the list //! and moves the resources of t to this new element. @@ -515,10 +564,10 @@ class list //! Complexity: Amortized constant time. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void push_front(const detail::moved_object& x) - { this->insert(this->begin(), x); } + { this->insert(this->cbegin(), x); } #else void push_front(T &&x) - { this->insert(this->begin(), detail::move_impl(x)); } + { this->insert(this->cbegin(), detail::move_impl(x)); } #endif //! Effects: Removes the last element from the list. @@ -527,7 +576,7 @@ class list //! //! Complexity: Amortized constant time. void push_back (const T& x) - { this->insert(this->end(), x); } + { this->insert(this->cend(), x); } //! Effects: Removes the first element from the list. //! @@ -536,10 +585,10 @@ class list //! Complexity: Amortized constant time. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void push_back (const detail::moved_object& x) - { this->insert(this->end(), x); } + { this->insert(this->cend(), x); } #else void push_back (T &&x) - { this->insert(this->end(), detail::move_impl(x)); } + { this->insert(this->cend(), detail::move_impl(x)); } #endif //! Effects: Removes the first element from the list. @@ -548,7 +597,7 @@ class list //! //! Complexity: Amortized constant time. void pop_front() - { this->erase(this->begin()); } + { this->erase(this->cbegin()); } //! Effects: Removes the last element from the list. //! @@ -556,7 +605,7 @@ class list //! //! Complexity: Amortized constant time. void pop_back() - { iterator tmp = this->end(); this->erase(--tmp); } + { const_iterator tmp = this->cend(); this->erase(--tmp); } //! Requires: !empty() //! @@ -610,7 +659,7 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - iterator iend = this->end(); + const_iterator iend = this->cend(); size_type len = this->size(); if(len > new_size){ @@ -618,7 +667,7 @@ class list while(to_erase--){ --iend; } - this->erase(iend, this->end()); + this->erase(iend, this->cend()); } else{ this->priv_create_and_insert_nodes(iend, new_size - len, x); @@ -633,12 +682,12 @@ class list //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - iterator iend = this->end(); + const_iterator iend = this->end(); size_type len = this->size(); if(len > new_size){ size_type to_erase = len - new_size; - iterator ifirst; + const_iterator ifirst; if(to_erase < len/2u){ ifirst = iend; while(to_erase--){ @@ -655,7 +704,7 @@ class list this->erase(ifirst, iend); } else{ - this->priv_create_and_insert_nodes(this->end(), new_size - len); + this->priv_create_and_insert_nodes(this->cend(), new_size - len); } } @@ -726,7 +775,7 @@ class list //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - void insert(iterator p, size_type n, const T& x) + void insert(const_iterator p, size_type n, const T& x) { this->priv_create_and_insert_nodes(p, n, x); } //! Requires: p must be a valid iterator of *this. @@ -738,7 +787,7 @@ class list //! //! Complexity: Linear to std::distance [first, last). template - void insert(iterator p, InpIt first, InpIt last) + void insert(const_iterator p, InpIt first, InpIt last) { const bool aux_boolean = detail::is_convertible::value; typedef detail::bool_ Result; @@ -752,7 +801,7 @@ class list //! Throws: If memory allocation throws or x's copy constructor throws. //! //! Complexity: Amortized constant time. - iterator insert(iterator p, const T& x) + iterator insert(const_iterator p, const T& x) { NodePtr tmp = AllocHolder::create_node(x); return iterator(this->icont().insert(p.get(), *tmp)); @@ -766,19 +815,109 @@ class list //! //! Complexity: Amortized constant time. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator p, const detail::moved_object& x) + iterator insert(const_iterator p, const detail::moved_object& x) { NodePtr tmp = AllocHolder::create_node(x); return iterator(this->icont().insert(p.get(), *tmp)); } #else - iterator insert(iterator p, T &&x) + iterator insert(const_iterator p, T &&x) { NodePtr tmp = AllocHolder::create_node(detail::move_impl(x)); return iterator(this->icont().insert(p.get(), *tmp)); } #endif + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_back(Args&&... args) + { + this->emplace(this->cend(), detail::forward_impl(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_front(Args&&... args) + { + this->emplace(this->cbegin(), detail::forward_impl(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace(const_iterator p, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)detail::get_pointer(d.get())) Node(detail::forward_impl(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 \ + 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 \ + 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 \ + 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 + //! Requires: p must be a valid iterator of *this. //! //! Effects: Erases the element at p p. @@ -786,7 +925,7 @@ class list //! Throws: Nothing. //! //! Complexity: Amortized constant time. - iterator erase(iterator p) + iterator erase(const_iterator p) { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } //! Requires: first and last must be valid iterator to elements in *this. @@ -796,7 +935,7 @@ class list //! Throws: Nothing. //! //! Complexity: Linear to the distance between first and last. - iterator erase(iterator first, iterator last) + iterator erase(const_iterator first, const_iterator last) { return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } //! Effects: Assigns the n copies of val to *this. @@ -861,7 +1000,7 @@ class list //! //! Note: 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. - void splice(iterator p, ThisType &x, iterator i) + void splice(const_iterator p, ThisType &x, const_iterator i) { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().splice(p.get(), x.icont(), i.get()); @@ -871,7 +1010,7 @@ class list } } -// void splice(iterator p, const detail::moved_object &x, iterator i) +// void splice(const_iterator p, const detail::moved_object &x, const_iterator i) // { this->splice(p, x.get(), i); } //! Requires: p must point to an element contained @@ -887,7 +1026,7 @@ class list //! //! Note: 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. - void splice(iterator p, ThisType &x, iterator first, iterator last) + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().splice(p.get(), x.icont(), first.get(), last.get()); @@ -897,7 +1036,7 @@ class list } } -// void splice(iterator p, detail::moved_object &x, iterator first, iterator last) +// void splice(const_iterator p, detail::moved_object &x, const_iterator first, const_iterator last) // { return this->splice(p, x.get(), first, last); } //! Requires: p must point to an element contained @@ -914,7 +1053,7 @@ class list //! //! Note: 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. - void splice(iterator p, ThisType &x, iterator first, iterator last, size_type n) + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().splice(p.get(), x.icont(), first.get(), last.get(), n); @@ -924,7 +1063,7 @@ class list } } -// void splice(iterator p, detail::moved_object &x, iterator first, iterator last, size_type n) +// void splice(const_iterator p, detail::moved_object &x, const_iterator first, const_iterator last, size_type n) // { return this->splice(p, x.get(), first, last, n); } //! Effects: Reverses the order of elements in the list. @@ -1128,10 +1267,10 @@ class list class insertion_functor { Icont &icont_; - typename Icont::iterator pos_; + typename Icont::const_iterator pos_; public: - insertion_functor(Icont &icont, typename Icont::iterator pos) + insertion_functor(Icont &icont, typename Icont::const_iterator pos) : icont_(icont), pos_(pos) {} @@ -1165,13 +1304,13 @@ class list //Dispatch to detect iterator range or integer overloads template - void priv_insert_dispatch(iterator p, + void priv_insert_dispatch(const_iterator p, InputIter first, InputIter last, detail::false_) { this->priv_create_and_insert_nodes(p, first, last); } template - void priv_insert_dispatch(iterator p, Integer n, Integer x, detail::true_) + 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) @@ -1181,10 +1320,10 @@ class list for ( ; i != iend && n > 0; ++i, --n) *i = val; if (n > 0){ - this->priv_create_and_insert_nodes(this->end(), n, val); + this->priv_create_and_insert_nodes(this->cend(), n, val); } else{ - this->erase(i, end()); + this->erase(i, cend()); } } @@ -1193,8 +1332,7 @@ class list { this->priv_fill_assign((size_type) n, (T) val); } template - void priv_assign_dispatch(InputIter first2, InputIter last2, - detail::false_) + void priv_assign_dispatch(InputIter first2, InputIter last2, detail::false_) { iterator first1 = this->begin(); iterator last1 = this->end(); diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index bfd6333..b793cc0 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -530,6 +530,58 @@ class map void insert(InputIterator first, InputIterator last) { m_tree.insert_unique(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, detail::forward_impl(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 \ + 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 \ + 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 + //! Effects: Erases the element pointed to by position. //! //! Returns: Returns an iterator pointing to the element immediately @@ -1056,6 +1108,56 @@ class multimap void insert(InputIterator first, InputIterator last) { m_tree.insert_equal(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, detail::forward_impl(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 \ + 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 \ + 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 + //! Effects: Erases the element pointed to by position. //! //! Returns: Returns an iterator pointing to the element immediately diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index a0a3a52..a3aec9d 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -59,6 +59,9 @@ #include #include #include +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#endif namespace boost { namespace interprocess { @@ -263,6 +266,40 @@ class set const_reverse_iterator rend() const { return m_tree.rend(); } + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + //! Effects: Returns true if the container contains no elements. //! //! Throws: Nothing. @@ -373,6 +410,57 @@ class set void insert(InputIterator first, InputIterator last) { m_tree.insert_unique(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, detail::forward_impl(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 \ + 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 \ + 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 + //! Effects: Erases the element pointed to by p. //! //! Returns: Returns an iterator pointing to the element immediately @@ -752,6 +840,40 @@ class multiset const_reverse_iterator rend() const { return m_tree.rend(); } + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + //! Effects: Returns true if the container contains no elements. //! //! Throws: Nothing. @@ -857,6 +979,51 @@ class multiset void insert(InputIterator first, InputIterator last) { m_tree.insert_equal(first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, detail::forward_impl(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 \ + 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 \ + 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 + //! Effects: Erases the element pointed to by p. //! //! Returns: Returns an iterator pointing to the element immediately diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index a0724e2..2082b0e 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -59,6 +59,12 @@ #include #include + +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + #include #include #include @@ -67,28 +73,43 @@ namespace boost{ namespace interprocess{ -namespace detail { /// @cond -template -struct slist_node - : public bi::make_slist_base_hook - , bi::link_mode >::type + +namespace detail { + +template +struct slist_hook { typedef typename bi::make_slist_base_hook - , bi::link_mode >::type hook_type; + , bi::link_mode >::type type; +}; + +template +struct slist_node + : public slist_hook::type +{ + #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING slist_node() : m_data() {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - slist_node(const Convertible &value) - : m_data(value){} - #else - template - slist_node(Convertible &&value) - : m_data(detail::forward_impl(value)){} - #endif + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + 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 + slist_node(Args &&...args) + : m_data(detail::forward_impl(args)...) + {} + #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING T m_data; }; @@ -104,16 +125,17 @@ struct intrusive_slist_type typedef typename bi::make_slist + ,bi::base_hook::type> ,bi::constant_time_size ,bi::size_type >::type container_type; typedef container_type type ; }; -/// @endcond } //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 @@ -480,7 +502,7 @@ class slist //! //! Complexity: Constant. const_iterator begin() const - { return const_iterator(this->non_const_icont().begin()); } + { return this->cbegin(); } //! Effects: Returns an iterator to the end of the list. //! @@ -496,7 +518,7 @@ class slist //! //! Complexity: Constant. const_iterator end() const - { return const_iterator(this->non_const_icont().end()); } + { return this->cend(); } //! Effects: Returns a non-dereferenceable iterator that, //! when incremented, yields begin(). This iterator may be used @@ -516,6 +538,32 @@ class slist //! //! Complexity: Constant. const_iterator before_begin() const + { return this->cbefore_begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbefore_begin() const { return const_iterator(end()); } //! Effects: Returns the number of the elements contained in the list. @@ -638,7 +686,7 @@ class slist //! //! Note: Does not affect the validity of iterators and references of //! previous values. - iterator insert_after(iterator prev_pos, const value_type& x) + iterator insert_after(const_iterator prev_pos, const value_type& x) { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } //! Requires: prev_pos must be a valid iterator of *this. @@ -655,10 +703,10 @@ class slist //! Note: Does not affect the validity of iterators and references of //! previous values. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_after(iterator prev_pos, const detail::moved_object& x) + iterator insert_after(const_iterator prev_pos, const detail::moved_object& x) { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(x))); } #else - iterator insert_after(iterator prev_pos, value_type && x) + iterator insert_after(const_iterator prev_pos, value_type && x) { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(detail::move_impl(x)))); } #endif @@ -672,7 +720,7 @@ class slist //! //! Note: Does not affect the validity of iterators and references of //! previous values. - void insert_after(iterator prev_pos, size_type n, const value_type& x) + void insert_after(const_iterator prev_pos, size_type n, const value_type& x) { this->priv_create_and_insert_nodes(prev_pos, n, x); } //! Requires: prev_pos must be a valid iterator of *this. @@ -688,7 +736,7 @@ class slist //! Note: Does not affect the validity of iterators and references of //! previous values. template - void insert_after(iterator prev_pos, InIter first, InIter last) + void insert_after(const_iterator prev_pos, InIter first, InIter last) { const bool aux_boolean = detail::is_convertible::value; typedef detail::bool_ Result; @@ -702,7 +750,7 @@ class slist //! Throws: If memory allocation throws or x's copy constructor throws. //! //! Complexity: Linear to the elements before p. - iterator insert(iterator p, const value_type& x) + iterator insert(const_iterator p, const value_type& x) { return this->insert_after(previous(p), x); } //! Requires: p must be a valid iterator of *this. @@ -713,10 +761,10 @@ class slist //! //! Complexity: Linear to the elements before p. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator p, const detail::moved_object& x) + iterator insert(const_iterator p, const detail::moved_object& x) { return this->insert_after(previous(p), x); } #else - iterator insert(iterator p, value_type && x) + iterator insert(const_iterator p, value_type && x) { return this->insert_after(previous(p), detail::move_impl(x)); } #endif @@ -727,7 +775,7 @@ class slist //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n plus linear to the elements before p. - void insert(iterator p, size_type n, const value_type& x) + void insert(const_iterator p, size_type n, const value_type& x) { return this->insert_after(previous(p), n, x); } //! Requires: p must be a valid iterator of *this. @@ -740,9 +788,101 @@ class slist //! Complexity: Linear to std::distance [first, last) plus //! linear to the elements before p. template - void insert(iterator p, InIter first, InIter last) + void insert(const_iterator p, InIter first, InIter last) { return this->insert_after(previous(p), first, last); } + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the front of the list + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_front(Args&&... args) + { this->emplace_after(this->cbefore_begin(), detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Linear to the elements before p + template + iterator emplace(const_iterator p, Args&&... args) + { return this->emplace_after(this->previous(p), detail::forward_impl(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... after prev + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + 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(detail::forward_impl(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 \ + 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 \ + 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 \ + 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 + //! Effects: Erases the element after the element pointed by prev_pos //! of the list. //! @@ -754,7 +894,7 @@ class slist //! Complexity: Constant. //! //! Note: Does not invalidate iterators or references to non erased elements. - iterator erase_after(iterator prev_pos) + iterator erase_after(const_iterator prev_pos) { return iterator(this->icont().erase_after_and_dispose(prev_pos.get(), Destroyer(this->node_alloc()))); } @@ -770,7 +910,7 @@ class slist //! Complexity: Linear to the number of erased elements. //! //! Note: Does not invalidate iterators or references to non erased elements. - iterator erase_after(iterator before_first, iterator last) + 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()))); } @@ -782,7 +922,7 @@ class slist //! Throws: Nothing. //! //! Complexity: Linear to the number of elements before p. - iterator erase(iterator p) + iterator erase(const_iterator p) { return iterator(this->erase_after(previous(p))); } //! Requires: first and last must be valid iterator to elements in *this. @@ -793,7 +933,7 @@ class slist //! //! Complexity: Linear to the distance between first and last plus //! linear to the elements before first. - iterator erase(iterator first, iterator last) + iterator erase(const_iterator first, const_iterator last) { return iterator(this->erase_after(previous(first), last)); } //! Effects: Inserts or erases elements at the end such that @@ -810,9 +950,9 @@ class slist cur = cur_next; } if (cur_next != end_n) - this->erase_after(iterator(cur), iterator(end_n)); + this->erase_after(const_iterator(cur), const_iterator(end_n)); else - this->insert_after(iterator(cur), new_size, x); + this->insert_after(const_iterator(cur), new_size, x); } //! Effects: Inserts or erases elements at the end such that @@ -832,10 +972,10 @@ class slist cur = cur_next; } if (cur_next != end_n){ - this->erase_after(iterator(cur), iterator(end_n)); + this->erase_after(const_iterator(cur), const_iterator(end_n)); } else{ - this->priv_create_and_insert_nodes(iterator(cur), new_size - len); + this->priv_create_and_insert_nodes(const_iterator(cur), new_size - len); } } @@ -860,7 +1000,7 @@ class slist //! //! Note: 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. - void splice_after(iterator prev_pos, slist& x) + void splice_after(const_iterator prev_pos, slist& x) { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().splice_after(prev_pos.get(), x.icont()); @@ -870,7 +1010,7 @@ class slist } } - //void splice_after(iterator prev_pos, const detail::moved_object& x) + //void splice_after(const_iterator prev_pos, const detail::moved_object& x) //{ this->splice_after(prev_pos, x.get()); } // Moves the element that follows prev to *this, inserting it immediately @@ -890,7 +1030,7 @@ class slist //! //! Note: 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. - void splice_after(iterator prev_pos, slist& x, iterator prev) + void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().splice_after(prev_pos.get(), x.icont(), prev.get()); @@ -900,7 +1040,7 @@ class slist } } - //void splice_after(iterator prev_pos, const detail::moved_object& x, iterator prev) + //void splice_after(const_iterator prev_pos, const detail::moved_object& x, iterator prev) //{ return splice_after(prev_pos, x.get(), prev); } // Moves the range [before_first + 1, before_last + 1) to *this, @@ -921,8 +1061,8 @@ class slist //! //! Note: 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. - void splice_after(iterator prev_pos, slist& x, - iterator before_first, iterator before_last) + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last) { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().splice_after @@ -933,8 +1073,8 @@ class slist } } - //void splice_after(iterator prev_pos, const detail::moved_object& x, - // iterator before_first, iterator before_last) + //void splice_after(const_iterator prev_pos, const detail::moved_object& x, + // const_iterator before_first, const_iterator before_last) //{ this->splice_after(prev_pos, x.get(), before_first, before_last); } //! Requires: prev_pos must be a valid iterator of this. @@ -952,8 +1092,8 @@ class slist //! //! Note: 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. - void splice_after(iterator prev_pos, slist& x, - iterator before_first, iterator before_last, + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last, size_type n) { if((NodeAlloc&)*this == (NodeAlloc&)x){ @@ -965,8 +1105,8 @@ class slist } } - //void splice_after(iterator prev_pos, const detail::moved_object& x, - // iterator before_first, iterator before_last, size_type n) + //void splice_after(const_iterator prev_pos, const detail::moved_object& x, + // const_iterator before_first, const_iterator before_last, size_type n) //{ this->splice_after(prev_pos, x.get(), before_first, before_last, n); } //! Requires: p must point to an element contained @@ -982,10 +1122,10 @@ class slist //! //! Note: 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. - void splice(iterator p, slist& x) + void splice(const_iterator p, slist& x) { this->splice_after(this->previous(p), x); } - //void splice(iterator p, const detail::moved_object& x) + //void splice(const_iterator p, const detail::moved_object& x) //{ return this->splice(p, x.get()); } //! Requires: p must point to an element contained @@ -1002,10 +1142,10 @@ class slist //! //! Note: 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. - void splice(iterator p, slist& x, iterator i) + void splice(const_iterator p, slist& x, const_iterator i) { this->splice_after(previous(p), x, i); } - //void splice(iterator p, const detail::moved_object& x, iterator i) + //void splice(const_iterator p, const detail::moved_object& x, const_iterator i) //{ this->splice(p, x.get(), i); } //! Requires: p must point to an element contained @@ -1022,10 +1162,10 @@ class slist //! //! Note: 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. - void splice(iterator p, slist& x, iterator first, iterator last) + void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) { this->splice_after(previous(p), x, previous(first), previous(last)); } - //void splice(iterator p, const detail::moved_object& x, iterator first, iterator last) + //void splice(const_iterator p, const detail::moved_object& x, const_iterator first, const_iterator last) //{ this->splice(p, x.get(), first, last); } //! Effects: Reverses the order of elements in the list. @@ -1205,10 +1345,10 @@ class slist class insertion_functor { Icont &icont_; - typename Icont::iterator prev_; + typename Icont::const_iterator prev_; public: - insertion_functor(Icont &icont, typename Icont::iterator prev) + insertion_functor(Icont &icont, typename Icont::const_iterator prev) : icont_(icont), prev_(prev) {} @@ -1241,13 +1381,13 @@ class slist //Dispatch to detect iterator range or integer overloads template - void priv_insert_dispatch(iterator prev, + void priv_insert_dispatch(const_iterator prev, InputIter first, InputIter last, detail::false_) { this->priv_create_and_insert_nodes(prev, first, last); } template - void priv_insert_dispatch(iterator prev, Integer n, Integer x, detail::true_) + 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) @@ -1271,8 +1411,7 @@ class slist { this->priv_fill_assign((size_type) n, (T)val); } template - void priv_assign_dispatch(InpIt first, InpIt last, - detail::false_) + void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) { iterator end_n(this->end()); iterator prev(this->before_begin()); @@ -1290,11 +1429,11 @@ class slist } template - void priv_insert_after_range_dispatch(iterator prev_pos, Int n, Int x, detail::true_) + 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 - void priv_insert_after_range_dispatch(iterator prev_pos, InIter first, InIter last, detail::false_) + 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 diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index b1bf30d..b0666a4 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 5372eda..0a7d188 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -68,6 +68,7 @@ #include #include #include +#include namespace boost { namespace interprocess { @@ -233,6 +234,63 @@ class vector_iterator { return static_cast&>(*this) - right; } }; +template +struct vector_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::value; + + //This is the anti-exception array destructor + //to deallocate values already constructed + typedef typename detail::if_c + + ,detail::scoped_destructor_n + >::type OldArrayDestructor; + //This is the anti-exception array destructor + //to destroy objects created with copy construction + typedef typename detail::if_c + + ,detail::scoped_destructor_n + >::type UCopiedArrayDestructor; + //This is the anti-exception array deallocator + typedef typename detail::if_c + + ,detail::scoped_array_deallocator + >::type UCopiedArrayDeallocator; + + //This is the optimized move iterator for copy constructors + //so that std::copy and similar can use memcpy + typedef typename detail::if_c + ::value + #endif + ,const T* + ,detail::move_iterator + >::type copy_move_it; + + //This is the optimized move iterator for assignments + //so that std::uninitialized_copy and similar can use memcpy + typedef typename detail::if_c + ::value + #endif + ,const T* + ,detail::move_iterator + >::type assign_move_it; +}; + //!This struct deallocates and allocated memory template struct vector_alloc_holder @@ -240,14 +298,7 @@ struct vector_alloc_holder typedef typename A::pointer pointer; typedef typename A::size_type size_type; typedef typename A::value_type value_type; - - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::value; + typedef vector_value_traits value_traits; //Constructor, does not throw vector_alloc_holder(const A &a) @@ -336,13 +387,13 @@ struct vector_alloc_holder void destroy(value_type* p) { - if(!trivial_dctr) + if(!value_traits::trivial_dctr) detail::get_pointer(p)->~value_type(); } void destroy_n(value_type* p, size_type n) { - if(!trivial_dctr) + if(!value_traits::trivial_dctr) for(; n--; ++p) p->~value_type(); } @@ -398,10 +449,12 @@ class vector : private detail::vector_alloc_holder typedef std::reverse_iterator const_reverse_iterator; //! The stored allocator type - typedef allocator_type stored_allocator_type; + typedef allocator_type stored_allocator_type; /// @cond private: + typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef detail::vector_value_traits value_traits; typedef typename base_t::allocator_v1 allocator_v1; typedef typename base_t::allocator_v2 allocator_v2; @@ -410,48 +463,6 @@ class vector : private detail::vector_alloc_holder typedef constant_iterator cvalue_iterator; typedef repeat_iterator repeat_it; typedef detail::move_iterator repeat_move_it; - //This is the anti-exception array destructor - //to deallocate values already constructed - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type OldArrayDestructor; - //This is the anti-exception array destructor - //to destroy objects created with copy construction - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type UCopiedArrayDestructor; - //This is the anti-exception array deallocator - typedef typename detail::if_c - - ,detail::scoped_array_deallocator - >::type UCopiedArrayDeallocator; - - //This is the optimized move iterator for copy constructors - //so that std::copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,T* - ,detail::move_iterator - >::type copy_move_it; - - //This is the optimized move iterator for assignments - //so that std::uninitialized_copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,T* - ,detail::move_iterator - >::type assign_move_it; /// @endcond public: @@ -475,7 +486,7 @@ class vector : private detail::vector_alloc_holder vector(size_type n, const T& value = T(), const allocator_type& a = allocator_type()) : base_t(a) - { this->insert(this->end(), n, value); } + { this->insert(this->cend(), n, value); } //! Effects: Copy constructs a vector. //! @@ -552,7 +563,7 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: Constant. const_iterator end() const - { return const_iterator(this->members_.m_start + this->members_.m_size); } + { return this->cend(); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed vector. @@ -570,7 +581,7 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: Constant. const_reverse_iterator rbegin()const - { return const_reverse_iterator(this->end());} + { return this->crbegin(); } //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed vector. @@ -588,6 +599,40 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: Constant. const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin()const + { return const_reverse_iterator(this->end());} + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const { return const_reverse_iterator(this->begin()); } //! Requires: !empty() @@ -623,8 +668,6 @@ class vector : private detail::vector_alloc_holder reference back() { return this->members_.m_start[this->members_.m_size - 1]; } - //! Requires: !empty() - //! //! Effects: Returns a const reference to the first element //! from the beginning of the container. //! @@ -634,6 +677,24 @@ class vector : private detail::vector_alloc_holder const_reference back() const { return this->members_.m_start[this->members_.m_size - 1]; } + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + pointer data() + { return this->members_.m_start; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_pointer data() const + { return this->members_.m_start; } + //! Effects: Returns the number of the elements contained in the vector. //! //! Throws: Nothing. @@ -754,7 +815,9 @@ class vector : private detail::vector_alloc_holder //If there is no forward expansion, move objects else{ //We will reuse insert code, so create a dummy input iterator - copy_move_it dummy_it(detail::get_pointer(this->members_.m_start)); + typename value_traits::copy_move_it dummy_it(detail::get_pointer(this->members_.m_start)); + detail::advanced_insert_aux_proxy + proxy(dummy_it, dummy_it); //Backwards (and possibly forward) expansion if(ret.second){ #ifdef BOOST_INTERPROCESS_VECTOR_ALLOC_STATS @@ -764,9 +827,8 @@ class vector : private detail::vector_alloc_holder ( detail::get_pointer(ret.first) , real_cap , detail::get_pointer(this->members_.m_start) - , dummy_it - , dummy_it - , 0); + , 0 + , proxy); } //New buffer else{ @@ -777,8 +839,8 @@ class vector : private detail::vector_alloc_holder ( detail::get_pointer(ret.first) , real_cap , detail::get_pointer(this->members_.m_start) - , dummy_it - , dummy_it); + , 0 + , proxy); } } } @@ -812,25 +874,16 @@ class vector : private detail::vector_alloc_holder vector& operator=(const detail::moved_object >& mx) { vector &x = mx.get(); - - if (&x != this){ - this->swap(x); - x.clear(); - } - return *this; - } #else - vector& operator=(vector && mx) + vector& operator=(vector && x) { - vector &x = mx; - + #endif if (&x != this){ this->swap(x); x.clear(); } return *this; } - #endif //! Effects: Assigns the n copies of val to *this. //! @@ -869,7 +922,7 @@ class vector : private detail::vector_alloc_holder ++this->members_.m_size; } else{ - this->insert(this->end(), x); + this->insert(this->cend(), x); } } @@ -882,28 +935,122 @@ class vector : private detail::vector_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void push_back(const detail::moved_object & mx) { - 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(mx); - ++this->members_.m_size; - } - else{ - this->insert(this->end(), mx); - } - } + value_type &x = mx.get(); #else - void push_back(T && mx) + 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(detail::move_impl(mx)); + new((void*)detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(detail::move_impl(x)); ++this->members_.m_size; } else{ - this->insert(this->end(), detail::move_impl(mx)); + this->insert(this->cend(), detail::move_impl(x)); } } - #endif + + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + 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(detail::forward_impl(args)...); + ++this->members_.m_size; + } + else{ + detail::advanced_insert_aux_emplace proxy + (detail::forward_impl(args)...); + priv_range_insert(back_pos, 1, proxy); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + 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 proxy + (detail::forward_impl(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 proxy; + priv_range_insert(back_pos, 1, proxy); + } + } + + iterator emplace(const_iterator position) + { + size_type pos_n = position - cbegin(); + detail::advanced_insert_aux_emplace 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 \ + 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) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(back_pos, 1, proxy); \ + } \ + } \ + \ + template \ + 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) \ + \ + 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 //! Effects: Swaps the contents of *this and x. //! If this->allocator_type() != x.allocator_type() @@ -912,7 +1059,11 @@ class vector : private detail::vector_alloc_holder //! Throws: Nothing. //! //! Complexity: Constant. + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void swap(vector& x) + #else + void swap(vector && x) + #endif { allocator_type &this_al = this->alloc(), &other_al = x.alloc(); //Just swap internals @@ -925,6 +1076,7 @@ class vector : private detail::vector_alloc_holder } } + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE //! Effects: Swaps the contents of *this and x. //! If this->allocator_type() != x.allocator_type() //! allocators are also swapped. @@ -932,18 +1084,11 @@ class vector : private detail::vector_alloc_holder //! Throws: Nothing. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE void swap(const detail::moved_object >& mx) { vector &x = mx.get(); this->swap(x); } - #else - void swap(vector && mx) - { - vector &x = mx; - this->swap(x); - } #endif //! Requires: position must be a valid iterator of *this. @@ -952,14 +1097,14 @@ class vector : private detail::vector_alloc_holder //! //! Throws: If memory allocation throws or x's copy constructor throws. //! - //! Complexity: If position is begin() or end(), amortized constant time + //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. - iterator insert(iterator position, const T& x) + iterator insert(const_iterator position, const T& x) { //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); + size_type pos_n = position - cbegin(); this->insert(position, (size_type)1, x); - return iterator(this->members_.m_start + n); + return iterator(this->members_.m_start + pos_n); } //! Requires: position must be a valid iterator of *this. @@ -968,29 +1113,23 @@ class vector : private detail::vector_alloc_holder //! //! Throws: If memory allocation throws. //! - //! Complexity: If position is begin() or end(), amortized constant time + //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object &mx) + iterator insert(const_iterator position, const detail::moved_object &mx) { - //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); - this->insert(position - ,repeat_move_it(repeat_it(mx.get(), 1)) - ,repeat_move_it(repeat_it())); - return iterator(this->members_.m_start + n); - } + value_type &x = mx.get(); #else - iterator insert(iterator position, T &&mx) + iterator insert(const_iterator position, T &&x) { - //Just call more general insert(pos, size, value) and return iterator - size_type n = position - begin(); - this->insert(position - ,repeat_move_it(repeat_it(mx, 1)) - ,repeat_move_it(repeat_it())); - return iterator(this->members_.m_start + n); - } #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); + } //! Requires: pos must be a valid iterator of *this. //! @@ -1001,7 +1140,7 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: Linear to std::distance [first, last). template - void insert(iterator pos, InIt first, InIt last) + void insert(const_iterator pos, InIt first, InIt last) { //Dispatch depending on integer/iterator const bool aux_boolean = detail::is_convertible::value; @@ -1016,7 +1155,7 @@ class vector : private detail::vector_alloc_holder //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to n. - void insert (iterator p, size_type n, const T& x) + void insert(const_iterator p, size_type n, const T& x) { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } //! Effects: Removes the last element from the vector. @@ -1041,7 +1180,7 @@ class vector : private detail::vector_alloc_holder { T *pos = detail::get_pointer(position.get_ptr()); T *beg = detail::get_pointer(this->members_.m_start); - + typedef typename value_traits::assign_move_it assign_move_it; std::copy(assign_move_it(pos + 1), assign_move_it(beg + this->members_.m_size), pos); --this->members_.m_size; //Destroy last element @@ -1056,6 +1195,7 @@ class vector : private detail::vector_alloc_holder //! Complexity: Linear to the distance between first and last. iterator erase(const_iterator first, const_iterator last) { + typedef typename value_traits::assign_move_it assign_move_it; 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(std::copy @@ -1081,11 +1221,11 @@ class vector : private detail::vector_alloc_holder pointer finish = this->members_.m_start + this->members_.m_size; if (new_size < size()){ //Destroy last elements - this->erase(iterator(this->members_.m_start + new_size), this->end()); + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); } else{ //Insert new elements at the end - this->insert(iterator(finish), new_size - this->size(), x); + this->insert(const_iterator(finish), new_size - this->size(), x); } } @@ -1099,17 +1239,13 @@ class vector : private detail::vector_alloc_holder { if (new_size < this->size()){ //Destroy last elements - this->erase(iterator(this->members_.m_start + new_size), this->end()); + this->erase(const_iterator(this->members_.m_start + new_size), this->end()); } else{ size_type n = new_size - this->size(); this->reserve(new_size); - T *ptr = detail::get_pointer(this->members_.m_start + this->members_.m_size); - while(n--){ - //Default construct - new((void*)ptr++)T(); - ++this->members_.m_size; - } + detail::default_construct_aux_proxy proxy(n); + priv_range_insert(this->cend().get_ptr(), n, proxy); } } @@ -1174,76 +1310,86 @@ class vector : private detail::vector_alloc_holder } template - void priv_range_insert(pointer pos, FwdIt first, - FwdIt last, std::forward_iterator_tag) + void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) { - if (first != last){ - size_type n = std::distance(first, last); - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair 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), first, last, n); - } - //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) - , first - , last - , n); - } - //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) - , first - , last); - } + if(first != last){ + const size_type n = std::distance(first, last); + detail::advanced_insert_aux_proxy proxy(first, last); + priv_range_insert(pos, n, proxy); } } - template - void priv_range_insert_expand_forward - (T* pos, FwdIt first, FwdIt last, size_type n) + void priv_range_insert(pointer pos, const size_type n, + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + advanced_insert_aux_int_t &&interf + #else + advanced_insert_aux_int_t &interf + #endif + ) { + //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 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) + { + typedef typename value_traits::copy_move_it copy_move_it; + typedef typename value_traits::assign_move_it assign_move_it; //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; @@ -1256,35 +1402,32 @@ class vector : private detail::vector_alloc_holder //Copy previous to last objects to the initialized end std::copy_backward(assign_move_it(pos), assign_move_it(old_finish - n), old_finish); //Insert new objects in the pos - std::copy(first, last, 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. - FwdIt mid = first; - std::advance(mid, elems_after); - std::uninitialized_copy(mid, last, old_finish); + 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 std::uninitialized_copy - ( copy_move_it(pos) - , copy_move_it(old_finish) + ( copy_move_it(pos), copy_move_it(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 - std::copy(first, mid, pos); + interf.copy_all_to(pos); } } - template void priv_range_insert_new_allocation - (T* new_start, size_type new_cap, T* pos, FwdIt first, FwdIt last) + (T* new_start, size_type new_cap, T* pos, size_type n, advanced_insert_aux_int_t &interf) { + typedef typename value_traits::copy_move_it copy_move_it; T* new_finish = new_start; T *old_finish; //Anti-exception rollbacks - UCopiedArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); - UCopiedArrayDestructor construted_values_destroyer(new_start, 0u); + 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 @@ -1292,11 +1435,11 @@ class vector : private detail::vector_alloc_holder ( copy_move_it(detail::get_pointer(this->members_.m_start)) , copy_move_it(pos) , old_finish = new_finish); - construted_values_destroyer.increment_size(new_finish - old_finish); + constructed_values_destroyer.increment_size(new_finish - old_finish); //Initialize new objects, starting from previous point - new_finish = std::uninitialized_copy - (first, last, old_finish = new_finish); - construted_values_destroyer.increment_size(new_finish - old_finish); + 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 = std::uninitialized_copy @@ -1305,12 +1448,12 @@ class vector : private detail::vector_alloc_holder , new_finish); //All construction successful, disable rollbacks - construted_values_destroyer.release(); + 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(!base_t::trivial_dctr_after_move) + 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); } @@ -1319,11 +1462,13 @@ class vector : private detail::vector_alloc_holder this->members_.m_capacity = new_cap; } - template void priv_range_insert_expand_backwards (T* new_start, size_type new_capacity, - T* pos, FwdIt first, FwdIt last, size_type n) + T* pos, const size_type n, advanced_insert_aux_int_t &interf) { + typedef typename value_traits::copy_move_it copy_move_it; + typedef typename value_traits::assign_move_it assign_move_it; + //Backup old data T* old_start = detail::get_pointer(this->members_.m_start); T* old_finish = old_start + this->members_.m_size; @@ -1340,74 +1485,70 @@ class vector : private detail::vector_alloc_holder //If anything goes wrong, this object will destroy //all the old objects to fulfill previous vector state - OldArrayDestructor old_values_destroyer(old_start, old_size); - - //Check if s_before is so big that even copying the old data + new data - //there is a gap between the new data and the old data - if(s_before >= (old_size + n)){ - //Old situation: - // _________________________________________________________ - //| raw_mem | old_begin | old_end | - //| __________________________________|___________|_________| - // - //New situation: - // _________________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|________________________| - // - //Copy first old values before pos, after that the - //new objects - boost::interprocess::uninitialized_copy_copy - (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); - UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); - //Now initialize the rest of memory with the last old values - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(old_finish), new_start + elemsbefore + n); - //All new elements correctly constructed, avoid new element destruction - new_values_destroyer.release(); - 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(base_t::trivial_dctr_after_move) + 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 + std::uninitialized_copy(copy_move_it(old_start), copy_move_it(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 + std::uninitialized_copy + (copy_move_it(pos), copy_move_it(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 + std::uninitialized_copy + (copy_move_it(pos), copy_move_it(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(); - } - //Check if s_before is so big that divides old_end - else if(difference_type(s_before) >= difference_type(elemsbefore + n)){ - //Old situation: - // __________________________________________________ - //| raw_mem | old_begin | old_end | - //| ___________________________|___________|_________| - // - //New situation: - // __________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|_________________| - // - //Copy first old values before pos, after that the - //new objects - boost::interprocess::uninitialized_copy_copy - (copy_move_it(old_start), copy_move_it(pos), first, last, new_start); - UCopiedArrayDestructor new_values_destroyer(new_start, elemsbefore); - size_type raw_gap = s_before - (elemsbefore + n); - //Now initialize the rest of s_before memory with the - //first of elements after new values - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(pos + raw_gap), new_start + elemsbefore + n); - //All new elements correctly constructed, avoid new element destruction - new_values_destroyer.release(); - //All new elements correctly constructed, avoid old element destruction - old_values_destroyer.release(); - //Update size since we have a contiguous buffer - this->members_.m_size = old_size + s_before; - //Now copy remaining last objects in the old buffer begin - T *to_destroy = std::copy(assign_move_it(pos + raw_gap), assign_move_it(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(!base_t::trivial_dctr_after_move) - this->destroy_n(to_destroy, n_destroy); - this->members_.m_size -= n_destroy; + //Now copy remaining last objects in the old buffer begin + T *to_destroy = std::copy(assign_move_it(pos + raw_gap), assign_move_it(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 @@ -1430,13 +1571,6 @@ class vector : private detail::vector_alloc_holder //|____________________________|____________________| // bool do_after = n > s_before; - FwdIt before_end = first; - //If we have to expand both sides, - //we will play if the first new values so - //calculate the upper bound of new values - if(do_after){ - std::advance(before_end, s_before); - } //Now we can have two situations: the raw_mem of the //beginning divides the old_begin, or the new elements: @@ -1466,8 +1600,7 @@ class vector : private detail::vector_alloc_holder // //Copy the first part of old_begin to raw_mem T *start_n = old_start + difference_type(s_before); - std::uninitialized_copy - (copy_move_it(old_start), copy_move_it(start_n), new_start); + std::uninitialized_copy(copy_move_it(old_start), copy_move_it(start_n), new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); @@ -1476,22 +1609,27 @@ class vector : private detail::vector_alloc_holder T* next = std::copy(assign_move_it(start_n), assign_move_it(pos), old_start); if(do_after){ //Now copy the new_beg elements - std::copy(first, before_end, next); + interf.copy_some_and_update(next, s_before, true); } else{ //Now copy the all the new elements - T* move_start = std::copy(first, last, next); + interf.copy_all_to(next); + T* move_start = next + n; //Now displace old_end elements T* move_end = std::copy(assign_move_it(pos), assign_move_it(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(!base_t::trivial_dctr_after_move) + 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) @@ -1514,29 +1652,30 @@ class vector : private detail::vector_alloc_holder //|___________|_____|_________|__________________________| // //First copy whole old_begin and part of new to raw_mem - FwdIt mid = first; - size_type n_new_init = difference_type(s_before) - elemsbefore; - std::advance(mid, n_new_init); - boost::interprocess::uninitialized_copy_copy - (copy_move_it(old_start), copy_move_it(pos), first, mid, new_start); + std::uninitialized_copy(copy_move_it(old_start), copy_move_it(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(); - this->members_.m_size = old_size + s_before; if(do_after){ //Copy new_beg part - std::copy(mid, before_end, old_start); + interf.copy_some_and_update(old_start, s_before - mid_n, true); } else{ //Copy all new elements - T* move_start = std::copy(mid, last, old_start); + interf.copy_all_to(old_start); + T* move_start = old_start + (n-mid_n); //Displace old_end T* move_end = std::copy(copy_move_it(pos), copy_move_it(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(!base_t::trivial_dctr_after_move) + if(!value_traits::trivial_dctr_after_move) this->destroy_n(move_end, n_destroy); this->members_.m_size -= n_destroy; } @@ -1567,9 +1706,6 @@ class vector : private detail::vector_alloc_holder const size_type n_after = n - s_before; const difference_type elemsafter = old_size - elemsbefore; - //The new_end part is [first + (n - n_after), last) - std::advance(first, n - n_after); - //We can have two situations: if (elemsafter > difference_type(n_after)){ //The raw_mem from end will divide displaced old_end @@ -1592,7 +1728,8 @@ class vector : private detail::vector_alloc_holder //Displace the rest of old_end to the new position std::copy_backward(assign_move_it(pos), assign_move_it(finish_n), old_finish); //Now overwrite with new_end - std::copy(first, last, pos); + //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 @@ -1607,45 +1744,44 @@ class vector : private detail::vector_alloc_holder //| old_begin + new_beg | new_end |old_end | raw_mem | //|__________________________|_______________|________|_________| // - FwdIt mid = first; - std::advance(mid, elemsafter); + size_type mid_last_dist = n_after - elemsafter; //First initialize data in raw memory - boost::interprocess::uninitialized_copy_copy - ( mid, last, copy_move_it(pos), copy_move_it(old_finish), old_finish); - this->members_.m_size += n_after; + //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; + std::uninitialized_copy(copy_move_it(pos), copy_move_it(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 - std::copy(first, mid, pos); + interf.copy_all_to(pos); } } } } template - void priv_range_insert(iterator pos, - InIt first, InIt last, - std::input_iterator_tag) + void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) { - //Insert range before the pos position - std::copy(std::inserter(*this, pos), first, last); + for(;first != last; ++first){ + this->insert(pos, detail::move_impl(value_type(*first))); + } } template - void priv_assign_aux(InIt first, InIt last, - std::input_iterator_tag) + void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) { //Overwrite all elements we can from [first, last) iterator cur = begin(); for ( ; first != last && cur != end(); ++cur, ++first){ *cur = *first; } - + if (first == last){ //There are no more elements in the sequence, erase remaining - this->erase(cur, end()); + this->erase(cur, cend()); } else{ //There are more elements in the range, insert the remaining ones - this->insert(this->end(), first, last); + this->insert(this->cend(), first, last); } } @@ -1697,7 +1833,7 @@ class vector : private detail::vector_alloc_holder } } else if(!ret.second){ - UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); + typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); std::uninitialized_copy(first, last, detail::get_pointer(ret.first)); scoped_alloc.release(); //Destroy and deallocate old buffer @@ -1711,11 +1847,10 @@ class vector : private detail::vector_alloc_holder } else{ //Backwards expansion - //If anything goes wrong, this object will destroy - //all old objects + //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; - OldArrayDestructor old_values_destroyer(old_start, old_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; @@ -1725,9 +1860,10 @@ class vector : private detail::vector_alloc_holder //Backup old buffer data size_type old_offset = old_start - detail::get_pointer(ret.first); size_type first_count = min_value(n, old_offset); - boost::interprocess::uninitialized_copy_n - (first, first_count, detail::get_pointer(ret.first)); - FwdIt mid = first + first_count; + + FwdIt mid = first; + std::advance(mid, first_count); + std::uninitialized_copy(first, mid, detail::get_pointer(ret.first)); if(old_offset > n){ //All old elements will be destroyed by "old_values_destroyer" @@ -1741,16 +1877,14 @@ class vector : private detail::vector_alloc_holder this->members_.m_size = first_count + old_size; //Now overwrite the old values size_type second_count = min_value(old_size, n - first_count); - copy_n(mid, second_count, old_start); - mid += second_count; + FwdIt mid2 = mid; + std::advance(mid2, second_count); + std::copy(mid, mid2, old_start); //Check if we still have to append elements in the //uninitialized end if(second_count == old_size){ - boost::interprocess::uninitialized_copy_n - ( mid - , n - first_count - second_count - , old_start + old_size); + std::copy(mid2, last, old_start + old_size); } else{ //We have to destroy some old values @@ -1777,11 +1911,11 @@ class vector : private detail::vector_alloc_holder } template - void priv_insert_dispatch( iterator pos, Integer n, Integer val, detail::true_) + void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, detail::true_) { this->insert(pos, (size_type)n, (T)val); } template - void priv_insert_dispatch(iterator pos, InIt first, + void priv_insert_dispatch(const_iterator pos, InIt first, InIt last, detail::false_) { //Dispatch depending on integer/iterator diff --git a/include/boost/interprocess/detail/advanced_insert_int.hpp b/include/boost/interprocess/detail/advanced_insert_int.hpp new file mode 100644 index 0000000..42b2f31 --- /dev/null +++ b/include/boost/interprocess/detail/advanced_insert_int.hpp @@ -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 +#include +#include +#include //std::iterator_traits +#include //std::copy, std::uninitialized_copy +#include //placement new +#include + +namespace boost { namespace interprocess { namespace detail { + +//This class will be interface for operations dependent on FwdIt types used advanced_insert_aux_impl +template +struct advanced_insert_aux_int +{ + typedef typename std::iterator_traits::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 +struct advanced_insert_aux_proxy + : public advanced_insert_aux_int +{ + typedef typename advanced_insert_aux_int::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) + { std::uninitialized_copy(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){ + std::uninitialized_copy(first_, mid, pos); + first_ = mid; + } + else{ + std::uninitialized_copy(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 +struct default_construct_aux_proxy + : public advanced_insert_aux_int +{ + typedef typename advanced_insert_aux_int::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 +#include +#include +//#include //For debugging purposes + +namespace boost { +namespace interprocess { +namespace detail { + +//This class template will adapt each FwIt types to advanced_insert_aux_int +template +struct advanced_insert_aux_emplace + : public advanced_insert_aux_int +{ + typedef typename advanced_insert_aux_int::difference_type difference_type; + typedef typename build_number_seq::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 + void priv_copy_all_to(const index_tuple&, Iterator p) + { + if(!used_){ + T object(detail::forward_impl(get(args_))...); + *p = detail::move_impl(object); + used_ = true; + } + } + + template + void priv_uninitialized_copy_all_to(const index_tuple&, Iterator p) + { + if(!used_){ + new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + used_ = true; + } + } + + template + void priv_uninitialized_copy_some_and_update(const index_tuple&, 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(detail::forward_impl(get(args_))...); + used_ = true; + } + } + } + + template + void priv_copy_some_and_update(const index_tuple&, 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(detail::forward_impl(get(args_))...); + *p = detail::move_impl(object); + used_ = true; + } + } + } + tuple args_; + bool used_; +}; + +}}} //namespace boost { namespace interprocess { namespace detail { + +#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +#include + +namespace boost { +namespace interprocess { +namespace detail { + +template +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 +struct advanced_insert_aux_emplace + : public advanced_insert_aux_int +{ + typedef typename advanced_insert_aux_int::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_helperv; + *p = detail::move_impl(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_helperv; + *p = detail::move_impl(v.m_t); + used_ = true; + } + } + } + private: + bool used_; +}; + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + struct BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + : public advanced_insert_aux_int \ + { \ + typedef typename advanced_insert_aux_int::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 = detail::move_impl(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 = detail::move_impl(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 + +#endif //#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/detail/algorithms.hpp index 62e3637..534dfef 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/detail/algorithms.hpp @@ -73,7 +73,6 @@ inline void construct_in_place(T *dest, default_construct_iterator) new((void*)dest)T(); } - template struct optimize_assign { @@ -108,7 +107,6 @@ struct optimize_copy : public optimize_copy {}; - template inline OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, detail::bool_) { @@ -121,7 +119,7 @@ template inline T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) { std::size_t size = length*sizeof(T); - return ((T*)std::memmove(dest, first, size)) + size; + return (static_cast(std::memmove(dest, first, size))) + size; } template inline @@ -159,13 +157,11 @@ FwdIt uninitialized_copy_n_dispatch BOOST_CATCH_END return dest; } - - template inline T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) { std::size_t size = length*sizeof(T); - return ((T*)std::memmove(dest, first, size)) + size; + return (static_cast(std::memmove(dest, first, size))) + size; } template inline @@ -178,7 +174,6 @@ FwdIt uninitialized_copy_n return uninitialized_copy_n_dispatch(first, count, dest, detail::bool_()); } - // uninitialized_copy_copy // Copies [first1, last1) into [result, result + (last1 - first1)), and // copies [first2, last2) into @@ -194,7 +189,7 @@ FwdIt uninitialized_copy_copy } BOOST_CATCH(...){ for(;result != mid; ++result){ - result->~value_type(); + detail::get_pointer(&*result)->~value_type(); } BOOST_RETHROW } diff --git a/include/boost/interprocess/detail/atomic.hpp b/include/boost/interprocess/detail/atomic.hpp index 944d1a8..094bc0c 100644 --- a/include/boost/interprocess/detail/atomic.hpp +++ b/include/boost/interprocess/detail/atomic.hpp @@ -60,13 +60,13 @@ namespace detail{ //! "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((volatile long*)mem) + 1; } +{ return winapi::interlocked_decrement(reinterpret_cast(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((volatile long*)mem)-1; } +{ return winapi::interlocked_increment(reinterpret_cast(mem))-1; } //! Atomically read an boost::uint32_t from memory inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) @@ -76,7 +76,7 @@ inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) //! "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((volatile long*)mem, val); } +{ winapi::interlocked_exchange(reinterpret_cast(mem), val); } //! Compare an boost::uint32_t's value with "cmp". //! If they are the same swap the value with "with" @@ -86,7 +86,7 @@ inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) //! 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((volatile long*)mem, with, cmp); } +{ return winapi::interlocked_compare_exchange(reinterpret_cast(mem), with, cmp); } } //namespace detail{ } //namespace interprocess{ diff --git a/include/boost/interprocess/detail/config_begin.hpp b/include/boost/interprocess/detail/config_begin.hpp index 0273a8e..adea2a6 100644 --- a/include/boost/interprocess/detail/config_begin.hpp +++ b/include/boost/interprocess/detail/config_begin.hpp @@ -40,4 +40,8 @@ #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 diff --git a/include/boost/interprocess/detail/intersegment_ptr.hpp b/include/boost/interprocess/detail/intersegment_ptr.hpp index 6b885b0..1537fca 100644 --- a/include/boost/interprocess/detail/intersegment_ptr.hpp +++ b/include/boost/interprocess/detail/intersegment_ptr.hpp @@ -128,13 +128,13 @@ struct intersegment_base { const std::size_t mask = ~(align - 1); std::size_t beg = this->members.relative.beg; - return (void*)((((std::size_t)this) & mask) - (beg << align_bits)); + return reinterpret_cast((((std::size_t)this) & mask) - (beg << align_bits)); } void relative_set_begin_from_base(void *addr) { - assert(addr < (void*)this); - std::size_t off = (char*)this - (char*)addr; + assert(addr < static_cast(this)); + std::size_t off = reinterpret_cast(this) - reinterpret_cast(addr); members.relative.beg = off >> align_bits; } @@ -222,7 +222,7 @@ struct flat_map_intersegment typedef flat_map_intersegment self_t; void set_from_pointer(const volatile void *ptr) - { this->set_from_pointer((const void *)ptr); } + { this->set_from_pointer(const_cast(ptr)); } //!Obtains the address pointed //!by the object @@ -233,7 +233,7 @@ struct flat_map_intersegment } switch(this->get_mode()){ case is_relative: - return (char*)this + members.relative.off; + return const_cast(reinterpret_cast(this)) + members.relative.off; break; case is_segmented: { @@ -241,7 +241,7 @@ struct flat_map_intersegment std::size_t offset; void *this_base; get_segment_info_and_offset(this, segment_info, offset, this_base); - char *base = (char*)segment_info.group->address_of(this->members.segmented.segment); + char *base = static_cast(segment_info.group->address_of(this->members.segmented.segment)); return base + this->members.segmented.off; } break; @@ -259,7 +259,7 @@ struct flat_map_intersegment //!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 (char*)this->get_pointer() - (char*)other.get_pointer(); } + { return static_cast(this->get_pointer()) - static_cast(other.get_pointer()); } //!Returns true if both point to //!the same object @@ -291,14 +291,14 @@ struct flat_map_intersegment std::size_t mode = this->get_mode(); if(mode == is_in_stack){ - members.direct.addr = (void*)ptr; + members.direct.addr = const_cast(ptr); return; } if(mode == is_relative){ - char *beg_addr = (char*)this->relative_calculate_begin_addr(); + char *beg_addr = static_cast(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 = (char*)ptr - (char*)this; + members.relative.off = static_cast(ptr) - reinterpret_cast(this); return; } } @@ -312,21 +312,22 @@ struct flat_map_intersegment if(!this_info.group){ this->set_mode(is_in_stack); - this->members.direct.addr = (void*)ptr; + this->members.direct.addr = const_cast(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 = (void*)ptr; + this->members.direct.addr = const_cast(ptr); } else if(ptr_info.id == this_info.id){ this->set_mode(is_relative); - members.relative.off = ((char*)ptr - (char*)this); + members.relative.off = (static_cast(ptr) - reinterpret_cast(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; @@ -350,14 +351,14 @@ struct flat_map_intersegment //!offset void inc_offset(std::ptrdiff_t bytes) { - this->set_from_pointer((char*)this->get_pointer()+bytes); + this->set_from_pointer(static_cast(this->get_pointer()) + bytes); } //!Decrements internal //!offset void dec_offset(std::ptrdiff_t bytes) { - this->set_from_pointer((char*)this->get_pointer()-bytes); + this->set_from_pointer(static_cast(this->get_pointer()) - bytes); } ////////////////////////////////////// @@ -471,7 +472,7 @@ struct flat_map_intersegment base = 0; if(s_map.m_ptr_to_segment_info.empty()){ segment = segment_info_t(); - offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + offset = reinterpret_cast(ptr) - static_cast(0); return; } //Find the first base address greater than ptr @@ -479,22 +480,22 @@ struct flat_map_intersegment = 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 = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + offset = reinterpret_cast(ptr) - static_cast(0); } //Go to the previous one --it; - char * segment_base = detail::char_ptr_cast(it->first); + char * segment_base = const_cast(reinterpret_cast(it->first)); std::size_t segment_size = it->second.size; - if(segment_base <= detail::char_ptr_cast(ptr) && - (segment_base + segment_size) >= detail::char_ptr_cast(ptr)){ + if(segment_base <= reinterpret_cast(ptr) && + (segment_base + segment_size) >= reinterpret_cast(ptr)){ segment = it->second; - offset = detail::char_ptr_cast(ptr) - segment_base; + offset = reinterpret_cast(ptr) - segment_base; base = segment_base; } else{ segment = segment_info_t(); - offset = detail::char_ptr_cast(ptr) - detail::char_ptr_cast(); + offset = reinterpret_cast(ptr) - static_cast(0); } } @@ -535,6 +536,7 @@ struct flat_map_intersegment 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; } @@ -635,21 +637,6 @@ class intersegment_ptr : public flat_map_intersegment template intersegment_ptr(const intersegment_ptr &r, detail::static_cast_tag) { base_t::set_from_pointer(static_cast(r.get())); } -/* - { - if(r.is_null()){ - base_t::set_from_pointer(0); - } - else{ - //Some dirty tricks to safe segment operations. - //Calculate pointer adjustment and adjust offset. - pointer ptr = reinterpret_cast(this); - std::ptrdiff_t difference = detail::char_ptr_cast(static_cast(ptr)) - - detail::char_ptr_cast(ptr); - base_t::set_from_other(r); - base_t::inc_offset(difference*sizeof(T)); - } - }*/ //!Emulates const_cast operator. //!Never throws. @@ -672,7 +659,7 @@ class intersegment_ptr : public flat_map_intersegment //!Obtains raw pointer from offset. //!Never throws. pointer get()const - { return (pointer)base_t::get_pointer(); } + { return static_cast(base_t::get_pointer()); } //!Pointer-like -> operator. It can return 0 pointer. //!Never throws. @@ -1001,11 +988,11 @@ void *get_pointer() const return raw_address(); } else if(this->is_relative()){ - return ((char*)this) + this->relative_pointee_offset(); + return (const_cast(reinterpret_cast(this))) + this->relative_pointee_offset(); } else{ group_manager *m = get_segment_group_manager(addr); - char *base = (char*)m->get_id_address(this->segmented_id()); + char *base = static_cast(m->get_id_address(this->segmented_id())); return base + this->segmented_offset(); } } @@ -1039,7 +1026,7 @@ void set_from_pointer(const void *ptr) else if(ptr_info.segment_id == this_info.segment_id){ set_relative(); this->relative_size (ptr_info.size); - this->relative_offset((char*)ptr - (char*)this); + this->relative_offset(static_cast(ptr) - reinterpret_cast(this)); this->relative_start (ptr_info.base); } } diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index fee200e..ab0744c 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -225,7 +225,7 @@ class basic_managed_memory_impl //!Returns the base address of the memory in this process. Never throws. void * get_address () const - { return (char*)mp_header - Offset; } + { return reinterpret_cast(mp_header) - Offset; } //!Returns the size of memory segment. Never throws. std::size_t get_size () const @@ -255,21 +255,21 @@ class basic_managed_memory_impl //!The address must belong to the memory segment. Never throws. handle_t get_handle_from_address (const void *ptr) const { - return detail::char_ptr_cast(ptr) - - detail::char_ptr_cast(this->get_address()); + return reinterpret_cast(ptr) - + reinterpret_cast(this->get_address()); } //!Returns true if the address belongs to the managed memory segment bool belongs_to_segment (const void *ptr) const { return ptr >= this->get_address() && - ptr < (detail::char_ptr_cast(ptr) + this->get_size()); + ptr < (reinterpret_cast(ptr) + this->get_size()); } //!Transforms previously obtained offset into an absolute address in the //!process space of the current process. Never throws.*/ void * get_address_from_handle (handle_t offset) const - { return detail::char_ptr_cast(this->get_address()) + offset; } + { return reinterpret_cast(this->get_address()) + offset; } //!Searches for nbytes of free memory in the segment, marks the //!memory as used and return the pointer to the memory. If no diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp index 03aaa85..3a3b0c9 100644 --- a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -117,7 +117,7 @@ class basic_managed_multi_shared_memory 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((void *)0, 0); + return result_type(static_cast(0), 0); } virtual bool update_segments () @@ -169,7 +169,7 @@ class basic_managed_multi_shared_memory //segment id = 0 of this group void_pointer::insert_mapping ( group - , (char*)addr - managed_impl::ManagedOpenOrCreateUserOffset + , static_cast(addr) - managed_impl::ManagedOpenOrCreateUserOffset , size + managed_impl::ManagedOpenOrCreateUserOffset); //Check if this is the master segment if(!m_segment_number){ diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index 2f498b4..caa7741 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -189,13 +189,13 @@ class managed_open_or_create_impl { return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; } void *get_user_address() const - { return (char*)m_mapped_region.get_address() + ManagedOpenOrCreateUserOffset; } + { return static_cast(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; } std::size_t get_real_size() const { return m_mapped_region.get_size(); } void *get_real_address() const - { return (char*)m_mapped_region.get_address(); } + { return m_mapped_region.get_address(); } void swap(managed_open_or_create_impl &other) { @@ -360,7 +360,7 @@ class managed_open_or_create_impl if(previous == UninitializedSegment){ try{ write_whole_device(dev, size, file_like_t()); - construct_func((char*)region.get_address() + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true); + construct_func(static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset, size - ManagedOpenOrCreateUserOffset, true); //All ok, just move resources to the external mapped region m_mapped_region.swap(region); } @@ -413,7 +413,7 @@ class managed_open_or_create_impl if(value != InitializedSegment) throw interprocess_exception(error_info(corrupted_error)); - construct_func( (char*)region.get_address() + ManagedOpenOrCreateUserOffset + construct_func( static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset , region.get_size() - ManagedOpenOrCreateUserOffset , false); //All ok, just move resources to the external mapped region diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index 6159df9..ca5c0e2 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -119,6 +119,18 @@ typename detail::move_type::type move_impl(const Object &object) return type(object); } +template +inline const T& forward_impl(const T &t) +{ return t; } + +template +inline T& forward_impl(T &t) +{ return t; } + +template +inline detail::moved_object forward_impl(detail::moved_object &t) +{ return t; } + } //namespace detail { //!A function that converts an object to a moved object so that diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index be6ee84..b4df4da 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -19,14 +19,16 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include + +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#else +#include +#include +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING //!\file //!Describes a proxy class that implements named allocation syntax. @@ -35,6 +37,101 @@ namespace boost { namespace interprocess { namespace detail { +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + +template +struct CtorNArg : public placement_destroy +{ + typedef detail::bool_ IsIterator; + typedef CtorNArg self_t; + typedef typename build_number_seq::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(mem); + for(constructed = 0; constructed < num; ++constructed){ + this->construct(memory++, IsIterator(), index_tuple_t()); + this->do_increment(IsIterator(), index_tuple_t()); + } + } + + private: + template + void construct(void *mem, detail::true_, const index_tuple&) + { new((void*)mem)T(*detail::forward_impl(get(args_))...); } + + template + void construct(void *mem, detail::false_, const index_tuple&) + { new((void*)mem)T(detail::forward_impl(get(args_))...); } + + template + void do_increment(detail::true_, const index_tuple&) + { + this->expansion_helper(++get(args_)...); + } + + template + void expansion_helper(ExpansionArgs &&...) + {} + + template + void do_increment(detail::false_, const index_tuple&) + {} + + tuple 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 + T *operator()(Args &&...args) const + { + CtorNArg ctor_obj(detail::forward_impl(args)...); + return mp_mngr->template + generic_construct(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 @@ -52,21 +149,18 @@ struct Ctor0Arg : public placement_destroy virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) { - T* memory = (T*)(mem); + T* memory = static_cast(mem); for(constructed = 0; constructed < num; ++constructed) new((void*)memory++)T; } }; -#ifndef BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS -# define BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS 10 -#endif - //////////////////////////////////////////////////////////////// // What the macro should generate (n == 2): // // template // struct Ctor2Arg +// : public placement_destroy // { // typedef detail::bool_ IsIterator; // typedef Ctor2Arg self_t; @@ -94,7 +188,7 @@ struct Ctor0Arg : public placement_destroy // , std::size_t num // , std::size_t &constructed) // { -// T* memory = (T*)(mem); +// T* memory = static_cast(mem); // for(constructed = 0; constructed < num; ++constructed){ // this->construct(memory++, IsIterator()); // this->do_increment(IsIterator()); @@ -118,22 +212,6 @@ struct Ctor0Arg : public placement_destroy //This cast is ugly but it is necessary until "perfect forwarding" //is achieved in C++0x. Meanwhile, if we want to be able to //bind rvalues with non-const references, we have to be ugly -#define BOOST_INTERPROCESS_AUX_PARAM_LIST(z, n, data) \ - const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ -//! - -#define BOOST_INTERPROCESS_AUX_PARAM_INIT(z, n, data) \ - BOOST_PP_CAT(m_p, n) (const_cast(BOOST_PP_CAT(p, n))) \ -//! - -#define BOOST_INTERPROCESS_AUX_PARAM_INC(z, n, data) \ - BOOST_PP_CAT(++m_p, n) \ -//! - -#define BOOST_INTERPROCESS_AUX_PARAM_DEFINE(z, n, data) \ - BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ -//! - #define BOOST_PP_LOCAL_MACRO(n) \ template \ struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ @@ -156,14 +234,14 @@ struct Ctor0Arg : public placement_destroy self_t operator++(int) { return ++*this; *this; } \ \ BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ - ( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_AUX_PARAM_LIST, _) ) \ + ( BOOST_PP_ENUM(n, BOOST_INTERPROCESS_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 = (T*)(mem); \ + T* memory = static_cast(mem); \ for(constructed = 0; constructed < num; ++constructed){ \ this->construct(memory++, IsIterator()); \ this->do_increment(IsIterator()); \ @@ -172,24 +250,23 @@ struct Ctor0Arg : public placement_destroy \ private: \ void construct(void *mem, detail::true_) \ - { new((void*)mem)T(BOOST_PP_ENUM_PARAMS(n, *m_p)); } \ + { \ + 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_PARAMS(n, m_p)); } \ + { \ + new((void*)mem) T \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ + } \ \ - BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ + BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ }; \ //! - - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() -#undef BOOST_INTERPROCESS_AUX_PARAM_LIST -#undef BOOST_INTERPROCESS_AUX_PARAM_INIT -#undef BOOST_INTERPROCESS_AUX_PARAM_DEFINE -#undef BOOST_INTERPROCESS_AUX_PARAM_INC - //!Describes a proxy class that implements named //!allocation syntax. template @@ -222,32 +299,22 @@ class named_proxy } //! - // Boost preprocessor used to create operator() overloads - #define BOOST_INTERPROCESS_AUX_TYPE_LIST(z, n, data) \ - BOOST_PP_CAT(P, n) \ - //! - - #define BOOST_INTERPROCESS_AUX_PARAM_LIST(z, n, data) \ - const BOOST_PP_CAT(P, n) BOOST_PP_CAT(&p, n) \ - //! - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_AUX_PARAM_LIST, _)) const \ - { \ - typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ - \ - ctor_obj_t; \ - ctor_obj_t ctor_obj (BOOST_PP_ENUM_PARAMS(n, p)); \ - return mp_mngr->template generic_construct \ - (mp_name, m_num, m_find, m_dothrow, ctor_obj); \ - } \ + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + T *operator()(BOOST_PP_ENUM (n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) const\ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ + \ + ctor_obj_t; \ + ctor_obj_t ctor_obj \ + (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + return mp_mngr->template generic_construct \ + (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() - #undef BOOST_INTERPROCESS_AUX_PARAM_LIST - #undef BOOST_INTERPROCESS_AUX_TYPE_LIST //////////////////////////////////////////////////////////////////////// // What the macro should generate (n == 2) @@ -272,6 +339,8 @@ class named_proxy { m_num *= num; return *this; } }; +#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + }}} //namespace boost { namespace interprocess { namespace detail { #include diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp index 35e7e72..83f8c7e 100644 --- a/include/boost/interprocess/detail/os_file_functions.hpp +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -101,6 +101,9 @@ inline file_handle_t open_existing_file inline bool delete_file(const char *name) { return winapi::delete_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)){ @@ -260,6 +263,12 @@ inline file_handle_t open_existing_file 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); } @@ -274,11 +283,11 @@ inline bool get_file_size(file_handle_t hnd, offset_t &size) } inline bool set_file_pointer(file_handle_t hnd, offset_t off, file_pos_t pos) -{ return off == lseek(hnd, off, (int)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); + off = ::lseek(hnd, 0, SEEK_CUR); return off != ((off_t)-1); } diff --git a/include/boost/interprocess/detail/preprocessor.hpp b/include/boost/interprocess/detail/preprocessor.hpp new file mode 100644 index 0000000..45afb67 --- /dev/null +++ b/include/boost/interprocess/detail/preprocessor.hpp @@ -0,0 +1,113 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#include + +#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif + +#include +#include +#include +#include +#include + +#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_INTERPROCESS_RVALUE_REFERENCE + #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_INTERPROCESS_RVALUE_REFERENCE + #define BOOST_INTERPROCESS_PARAM(U, u) \ + U && u \ + //! +#else + #define BOOST_INTERPROCESS_PARAM(U, u) \ + const U & u \ + //! +#endif + +#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#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))) \ +//! +#endif + +#define BOOST_INTERPROCESS_AUX_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ +//! + +#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#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 + +#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ + detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ + //! +#else + #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ + BOOST_PP_CAT(p, n) \ + //! +#endif + +#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ + detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ + //! +#else + #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ + BOOST_PP_CAT(m_p, n) \ + //! +#endif + +#define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ +BOOST_PP_CAT(*m_p, n) \ +//! + +#include + +#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 diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 08a6e79..89478d8 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -123,8 +123,8 @@ struct block_header template CharType *name() const { - return reinterpret_cast - (detail::char_ptr_cast(this) + name_offset()); + return const_cast(reinterpret_cast + (reinterpret_cast(this) + name_offset())); } std::size_t name_length() const @@ -137,7 +137,7 @@ struct block_header void *value() const { - return detail::char_ptr_cast(this) + value_offset(); + return const_cast((reinterpret_cast(this) + value_offset())); } std::size_t value_offset() const @@ -169,8 +169,9 @@ struct block_header static block_header *block_header_from_value(const void *value, std::size_t sz, std::size_t algn) { block_header * hdr = - reinterpret_cast(detail::char_ptr_cast(value) - - get_rounded_size(sizeof(block_header), algn)); + const_cast + (reinterpret_cast(reinterpret_cast(value) - + get_rounded_size(sizeof(block_header), algn))); (void)sz; //Some sanity checks assert(hdr->m_value_alignment == algn); @@ -182,8 +183,8 @@ struct block_header static block_header *from_first_header(Header *header) { block_header * hdr = - reinterpret_cast(detail::char_ptr_cast(header) + - get_rounded_size(sizeof(Header), detail::alignment_of::value)); + reinterpret_cast(reinterpret_cast(header) + + get_rounded_size(sizeof(Header), detail::alignment_of::value)); //Some sanity checks return hdr; } @@ -192,7 +193,7 @@ struct block_header static Header *to_first_header(block_header *bheader) { Header * hdr = - reinterpret_cast(detail::char_ptr_cast(bheader) - + reinterpret_cast(reinterpret_cast(bheader) - get_rounded_size(sizeof(Header), detail::alignment_of::value)); //Some sanity checks return hdr; @@ -269,8 +270,9 @@ struct intrusive_value_type_impl block_header *get_block_header() const { - return (block_header *)(detail::char_ptr_cast(this) + - get_rounded_size(sizeof(*this), BlockHdrAlignment)); + return const_cast + (reinterpret_cast(reinterpret_cast(this) + + get_rounded_size(sizeof(*this), BlockHdrAlignment))); } bool operator <(const intrusive_value_type_impl & other) const @@ -281,7 +283,7 @@ struct intrusive_value_type_impl static intrusive_value_type_impl *get_intrusive_value_type(block_header *hdr) { - return (intrusive_value_type_impl *)(detail::char_ptr_cast(hdr) - + return reinterpret_cast(reinterpret_cast(hdr) - get_rounded_size(sizeof(intrusive_value_type_impl), BlockHdrAlignment)); } @@ -304,11 +306,11 @@ class char_ptr_holder {} char_ptr_holder(const detail::anonymous_instance_t *) - : m_name((CharType*)0) + : m_name(static_cast(0)) {} char_ptr_holder(const detail::unique_instance_t *) - : m_name((CharType*)-1) + : m_name(reinterpret_cast(-1)) {} operator const CharType *() @@ -380,7 +382,7 @@ struct index_data index_data(void *ptr) : m_ptr(ptr){} void *value() const - { return (void*)detail::get_pointer(m_ptr); } + { return static_cast(detail::get_pointer(m_ptr)); } }; template diff --git a/include/boost/interprocess/detail/type_traits.hpp b/include/boost/interprocess/detail/type_traits.hpp index d06d041..44066b7 100644 --- a/include/boost/interprocess/detail/type_traits.hpp +++ b/include/boost/interprocess/detail/type_traits.hpp @@ -128,6 +128,15 @@ struct add_reference { typedef const nat& type; }; + +template +struct add_const_reference +{ typedef const T &type; }; + +template +struct add_const_reference +{ typedef T& type; }; + template struct is_same { @@ -146,38 +155,6 @@ struct is_same static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u)); }; -/* -template typename T, template 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)); -};*/ -/* -template< typename T > -struct is_pointer_impl -{ - static const bool value = - (::boost::type_traits::ice_and< - ::boost::detail::is_pointer_helper::type>::value - , ::boost::type_traits::ice_not< - ::boost::is_member_pointer::value - >::value - >::value) - ); -};*/ } // namespace detail } //namespace interprocess { diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index f4043de..aedbfac 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -28,6 +28,9 @@ #include #include #include +#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING +#include +#endif #include #include @@ -115,6 +118,9 @@ struct scoped_deallocator void priv_deallocate(allocator_v2) { m_alloc.deallocate_one(m_ptr); } + scoped_deallocator(const scoped_deallocator &); + scoped_deallocator& operator=(const scoped_deallocator &); + public: pointer m_ptr; Allocator& m_alloc; @@ -125,10 +131,36 @@ struct scoped_deallocator ~scoped_deallocator() { if (m_ptr)priv_deallocate(alloc_version()); } + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + scoped_deallocator(scoped_deallocator &&o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { + #else + scoped_deallocator(moved_object 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; } }; +} //namespace detail { + +template +struct is_movable > +{ + static const bool value = true; +}; + +namespace detail { + //!A deleter for scoped_ptr that deallocates the memory //!allocated for an array of objects using a STL allocator. template @@ -353,20 +385,6 @@ struct multiallocation_destroy_dealloc { m_itbeg = multiallocation_iterator(); } }; -//!Forces a cast from any pointer to char *pointer -template -inline char* char_ptr_cast(T *ptr) -{ - //This is nasty, but we like it a lot! - return (char*)(ptr); -} - -inline char* char_ptr_cast() -{ - //This is nasty, but we like it a lot! - return (char*)(0); -} - //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) { @@ -510,19 +528,18 @@ struct pair T1 first; T2 second; - pair() - : first(), second() - {} - - pair(const T1& x, const T2& y) - : first(x), second(y) - {} - + //std::pair compatibility template pair(const std::pair& p) : first(p.first), second(p.second) {} + //To resolve ambiguity with the variadic constructor of 1 argument + //and the previous constructor + pair(std::pair& x) + : first(x.first), second(x.second) + {} + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object >& p) @@ -535,6 +552,30 @@ struct pair {} #endif + pair() + : first(), second() + {} + + pair(const pair& x) + : first(x.first), second(x.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the copy constructor + pair(pair& x) + : first(x.first), second(x.second) + {} + + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + pair(const detail::moved_object >& p) + : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) + {} + #else + pair(pair && p) + : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) + {} + #endif + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template pair(const detail::moved_object >& p) @@ -547,37 +588,42 @@ struct pair {} #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(const detail::moved_object &x, const detail::moved_object &y) - : first(detail::move_impl(x.get())), second(detail::move_impl(y.get())) + #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + + template + pair(U &&u, Args &&... args) + : first(detail::forward_impl(u)) + , second(detail::forward_impl(args)...) {} + #else - template - pair(U &&x, V &&y) - : first(detail::move_impl(x)), second(detail::move_impl(y)) - {} + + template + pair(BOOST_INTERPROCESS_PARAM(U, u)) + : first(detail::forward_impl(u)) + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + pair(BOOST_INTERPROCESS_PARAM(U, u) \ + ,BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + : first(detail::forward_impl(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_INTERPROCESS_RVALUE_REFERENCE - pair(const detail::moved_object &p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - pair(pair &&p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(const detail::moved_object &p) + pair& operator=(const detail::moved_object > &p) { first = detail::move_impl(p.get().first); second = detail::move_impl(p.get().second); return *this; } #else - pair& operator=(pair &&p) + pair& operator=(pair &&p) { first = detail::move_impl(p.first); second = detail::move_impl(p.second); @@ -585,12 +631,21 @@ struct pair } #endif - pair& operator=(const pair &p) + #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + pair& operator=(const detail::moved_object > &p) { - first = p.first; - second = p.second; + first = detail::move_impl(p.get().first); + second = detail::move_impl(p.get().second); return *this; } + #else + pair& operator=(std::pair &&p) + { + first = detail::move_impl(p.first); + second = detail::move_impl(p.second); + return *this; + } + #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template @@ -737,6 +792,16 @@ class multiallocation_chain_adaptor { return chain_.size(); } }; +template +struct value_init +{ + value_init() + : m_t() + {} + + T m_t; +}; + } //namespace detail { //!The pair is movable if any of its members is movable diff --git a/include/boost/interprocess/detail/variadic_templates_tools.hpp b/include/boost/interprocess/detail/variadic_templates_tools.hpp new file mode 100644 index 0000000..358b682 --- /dev/null +++ b/include/boost/interprocess/detail/variadic_templates_tools.hpp @@ -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 +#include +#include +#include //std::size_t + +namespace boost { +namespace interprocess { +namespace detail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::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 +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace interprocess { namespace detail { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index 2860bda..fa26ee9 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -63,6 +63,13 @@ 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 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; @@ -95,7 +102,7 @@ static const unsigned long format_message_max_width_mask 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 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; @@ -228,6 +235,7 @@ extern "C" __declspec(dllimport) void * __stdcall MapViewOfFileEx (void *, unsig 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); @@ -361,6 +369,9 @@ static inline void *create_file(const char *name, unsigned long access, unsigned 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); } @@ -401,10 +412,10 @@ static inline long interlocked_compare_exchange(long volatile *addr, long val1, { return BOOST_INTERLOCKED_COMPARE_EXCHANGE(addr, val1, val2); } static inline long interlocked_exchange_add(long volatile* addend, long value) -{ return BOOST_INTERLOCKED_EXCHANGE_ADD((long*)addend, value); } +{ return BOOST_INTERLOCKED_EXCHANGE_ADD(const_cast(addend), value); } static inline long interlocked_exchange(long volatile* addend, long value) -{ return BOOST_INTERLOCKED_EXCHANGE((long*)addend, value); } +{ return BOOST_INTERLOCKED_EXCHANGE(const_cast(addend), value); } } //namespace winapi } //namespace interprocess diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index ecf3698..8c17c2c 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -71,7 +71,7 @@ inline void fill_system_message(int sys_err_code, std::string &str) 0, sys_err_code, winapi::make_lang_id(winapi::lang_neutral, winapi::sublang_default), // Default language - (char *) &lpMsgBuf, + reinterpret_cast(&lpMsgBuf), 0, 0 ); diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index acab048..c4cd9a6 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -181,7 +181,7 @@ struct is_movable ///@endcond -//!A class that stores the name of a a file +//!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 diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index 0681782..aca3960 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -391,6 +391,11 @@ template > class vector; +//vector class +template > +class deque; + //list class template > diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index 757a367..5c049f8 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -52,7 +52,7 @@ class message_queue //!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". + //!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, @@ -62,15 +62,15 @@ class message_queue //!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. + //!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, the - //!function returns false. + //!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); @@ -302,11 +302,11 @@ class mq_hdr_t //Pointer to the index msg_hdr_ptr_t *index = reinterpret_cast - (detail::char_ptr_cast(this)+r_hdr_size); + (reinterpret_cast(this)+r_hdr_size); //Pointer to the first message header detail::msg_hdr_t *msg_hdr = reinterpret_cast - (detail::char_ptr_cast(this)+r_hdr_size+r_index_size); + (reinterpret_cast(this)+r_hdr_size+r_index_size); //Initialize the pointer to the index mp_index = index; @@ -315,7 +315,7 @@ class mq_hdr_t for(std::size_t i = 0; i < m_max_num_msg; ++i){ index[i] = msg_hdr; msg_hdr = reinterpret_cast - (detail::char_ptr_cast(msg_hdr)+r_max_msg_size); + (reinterpret_cast(msg_hdr)+r_max_msg_size); } } @@ -385,7 +385,7 @@ inline message_queue::message_queue(create_only_t create_only, name, get_mem_size(max_msg_size, max_num_msg), read_write, - (void*)0, + static_cast(0), //Prepare initialization functor detail::initialization_func_t (max_num_msg, max_msg_size)) {} @@ -399,7 +399,7 @@ inline message_queue::message_queue(open_or_create_t open_or_create, name, get_mem_size(max_msg_size, max_num_msg), read_write, - (void*)0, + static_cast(0), //Prepare initialization functor detail::initialization_func_t (max_num_msg, max_msg_size)) {} @@ -410,7 +410,7 @@ inline message_queue::message_queue(open_only_t open_only, : m_shmem(open_only, name, read_write, - (void*)0, + static_cast(0), //Prepare initialization functor detail::initialization_func_t ()) {} @@ -426,7 +426,13 @@ inline bool message_queue::try_send inline bool message_queue::timed_send (const void *buffer, std::size_t buffer_size ,unsigned int priority, const boost::posix_time::ptime &abs_time) -{ return this->do_send(timed, buffer, buffer_size, priority, 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, @@ -508,7 +514,13 @@ 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) -{ return this->do_receive(timed, buffer, buffer_size, recvd_size, priority, 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, diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index b3808a0..384e624 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -109,7 +109,7 @@ class mapped_region //!mapped memory. Never throws. offset_t get_offset() const; - //!Returns the mode of the mapping used to contruct the mapped file. + //!Returns the mode of the mapping used to construct the mapped file. //!Never throws. mode_t get_mode() const; @@ -327,7 +327,7 @@ inline mapped_region::mapped_region foffset_high, foffset_low, m_size ? static_cast(m_extra_offset + m_size) : 0, - (void*)address); + const_cast(address)); if(!mhandle.is_shm){ //For files we don't need the file mapping anymore @@ -482,8 +482,7 @@ inline mapped_region::mapped_region } //Map it to the address space -// m_base = mmap64( (void*)address - m_base = mmap ( (void*)address + m_base = mmap ( const_cast(address) , static_cast(m_extra_offset + m_size) , prot , flags @@ -498,13 +497,13 @@ inline mapped_region::mapped_region } //Calculate new base for the user - void *old_base = m_base; + const void *old_base = m_base; m_base = static_cast(m_base) + m_extra_offset; m_offset = offset; m_size = size; //Check for fixed mapping error - if(address && (old_base != (void*)address)){ + if(address && (old_base != address)){ error_info err = system_error_code(); this->priv_close(); throw interprocess_exception(err); diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index bd6b89b..2cdc2ce 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -95,7 +95,7 @@ class basic_multiallocation_iterator { return !operator== (other); } reference operator*() const - { return *((char*)detail::get_pointer(next_alloc_.next_)); } + { return *reinterpret_cast(detail::get_pointer(next_alloc_.next_)); } operator unspecified_bool_type() const { return next_alloc_.next_? &basic_multiallocation_iterator::unspecified_bool_type_func : 0; } @@ -113,6 +113,9 @@ class basic_multiallocation_iterator return it; } + multi_allocation_next &get_multi_allocation_next() + { return *next_alloc_.next_; } + private: multi_allocation_next next_alloc_; }; @@ -170,7 +173,7 @@ class basic_multiallocation_chain this->last_mem_ = tmp_mem; } else{ - next_impl_t * old_first = (next_impl_t*)(&*this->it_); + next_impl_t * old_first = &this->it_.get_multi_allocation_next(); tmp_mem->next_ = old_first; this->it_ = basic_multiallocation_iterator(tmp_mem); } @@ -197,7 +200,7 @@ class basic_multiallocation_chain } else{ static_cast(detail::get_pointer(this->last_mem_))->next_ - = (next_impl_t*)&*other_chain.it_; + = &other_chain.it_.get_multi_allocation_next(); this->last_mem_ = other_chain.last_mem_; this->num_mem_ += other_chain.num_mem_; } @@ -438,8 +441,8 @@ class memory_algorithm_common 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 = new((char*)first + Alignment*first_min_units) block_ctrl; - block_ctrl *second = (block_ctrl *)((char*)first + Alignment*first_min_units); + block_ctrl *second = reinterpret_cast + (reinterpret_cast(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); @@ -458,8 +461,8 @@ class memory_algorithm_common // ----------------------------------------------------- // | MBU +more | ACB | // ----------------------------------------------------- - char *pos = (char*) - ((std::size_t)((char*)buffer + + char *pos = reinterpret_cast + (reinterpret_cast(static_cast(buffer) + //This is the minimum size of (2) (MinBlockUnits*Alignment - AllocatedCtrlBytes) + //This is the next MBU for the aligned memory @@ -470,12 +473,13 @@ class memory_algorithm_common //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 <= ((char*)first + first->m_size*Alignment)); + assert(pos <= (reinterpret_cast(first) + first->m_size*Alignment)); assert(first->m_size >= 2*MinBlockUnits); - assert((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <= ((char*)first + first->m_size*Alignment)); + assert((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <= + (reinterpret_cast(first) + first->m_size*Alignment)); //Set the new size of the first block std::size_t old_size = first->m_size; - first->m_size = ((char*)second - (char*)first)/Alignment; + first->m_size = (reinterpret_cast(second) - reinterpret_cast(first))/Alignment; memory_algo->priv_mark_new_allocated_block(first); //Now check if we can create a new buffer in the end @@ -494,7 +498,7 @@ class memory_algorithm_common //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 ((char*)second + Alignment*second_min_units)block_ctrl; + block_ctrl *third = new (reinterpret_cast(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); @@ -591,10 +595,8 @@ class memory_algorithm_common BOOST_ASSERT(block->m_size >= BlockCtrlUnits); //We create the new block -// block_ctrl *new_block = new(reinterpret_cast -// (detail::char_ptr_cast(block) + block->m_size*Alignment)) block_ctrl; block_ctrl *new_block = reinterpret_cast - (detail::char_ptr_cast(block) + block->m_size*Alignment); + (reinterpret_cast(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; @@ -650,7 +652,7 @@ class memory_algorithm_common block_ctrl *block = memory_algo->priv_get_block(ret.first); std::size_t received_units = block->m_size; - char *block_address = (char*)block; + char *block_address = reinterpret_cast(block); std::size_t total_used_units = 0; // block_ctrl *prev_block = 0; @@ -663,10 +665,7 @@ class memory_algorithm_common break; total_request_units -= elem_units; //This is the position where the new block must be created -// if(prev_block) -// memory_algo->priv_mark_new_allocated_block(prev_block); - block_ctrl *new_block = (block_ctrl *)(block_address); -// block_ctrl *new_block = new(block_address)block_ctrl; + block_ctrl *new_block = reinterpret_cast(block_address); assert_alignment(new_block); //The last block should take all the remaining space diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp index 2393d1e..b196faf 100644 --- a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp @@ -88,13 +88,13 @@ class simple_seq_fit_impl static block_ctrl *get_block_from_addr(void *addr) { return reinterpret_cast - (detail::char_ptr_cast(addr) - BlockCtrlBytes); + (reinterpret_cast(addr) - BlockCtrlBytes); } void *get_addr() const { return reinterpret_cast - (detail::char_ptr_cast(this) + BlockCtrlBytes); + (reinterpret_cast(this) + BlockCtrlBytes); } }; @@ -235,7 +235,7 @@ inline simple_seq_fit_impl:: //Initialize pointers std::size_t block1_off = detail::get_rounded_size(sizeof(*this)+extra_hdr_bytes, Alignment); m_header.m_root.m_next = reinterpret_cast - (detail::char_ptr_cast(this) + block1_off); + (reinterpret_cast(this) + block1_off); m_header.m_root.m_next->m_size = (size - block1_off)/Alignment; m_header.m_root.m_next->m_next = &m_header.m_root; } @@ -264,12 +264,12 @@ inline void simple_seq_fit_impl::grow(std::size_t extr //We'll create a new free block with extra_size bytes block_ctrl *new_block = reinterpret_cast - (detail::char_ptr_cast(this) + old_end); + (reinterpret_cast(this) + old_end); new_block->m_next = 0; new_block->m_size = (m_header.m_size - old_end)/Alignment; m_header.m_allocated += new_block->m_size*Alignment; - this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes); + this->priv_deallocate(reinterpret_cast(new_block) + BlockCtrlBytes); } template @@ -286,7 +286,7 @@ inline void simple_seq_fit_impl::priv_add_segment(void //Simulate this block was previously allocated m_header.m_allocated += new_block->m_size*Alignment; //Return block and insert it in the free block list - this->priv_deallocate(detail::char_ptr_cast(new_block) + BlockCtrlBytes); + this->priv_deallocate(reinterpret_cast(new_block) + BlockCtrlBytes); } template @@ -324,7 +324,7 @@ inline void simple_seq_fit_impl::clear_free_memory() //Iterate through all free portions do{ //Just clear user the memory part reserved for the user - std::memset( detail::char_ptr_cast(block) + BlockCtrlBytes + std::memset( reinterpret_cast(block) + BlockCtrlBytes , 0 , block->m_size*Alignment - BlockCtrlBytes); block = detail::get_pointer(block->m_next); @@ -412,7 +412,7 @@ inline std::size_t simple_seq_fit_impl:: //to be modified //Obtain the real size of the block block_ctrl *block = reinterpret_cast - (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + (reinterpret_cast(ptr) - BlockCtrlBytes); return block->m_size*Alignment - BlockCtrlBytes; } @@ -505,7 +505,7 @@ void* simple_seq_fit_impl:: //We need a minimum size to split the previous one if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){ block_ctrl *new_block = reinterpret_cast - (detail::char_ptr_cast(reuse) - needs_backwards - BlockCtrlBytes); + (reinterpret_cast(reuse) - needs_backwards - BlockCtrlBytes); new_block->m_next = 0; new_block->m_size = BlockCtrlSize + (needs_backwards + extra_forward)/Alignment; @@ -615,10 +615,10 @@ inline typename simple_seq_fit_impl::block_ctrl * { //Take the address where the next block should go block_ctrl *next_block = reinterpret_cast - (detail::char_ptr_cast(ptr) + ptr->m_size*Alignment); + (reinterpret_cast(ptr) + ptr->m_size*Alignment); //Check if the adjacent block is in the managed segment - std::size_t distance = (detail::char_ptr_cast(next_block) - detail::char_ptr_cast(this))/Alignment; + std::size_t distance = (reinterpret_cast(next_block) - reinterpret_cast(this))/Alignment; if(distance >= (m_header.m_size/Alignment)){ //"next_block" does not exist so we can't expand "block" return 0; @@ -643,8 +643,8 @@ inline block_ctrl *root = &m_header.m_root; block_ctrl *prev_2_block = root; block_ctrl *prev_block = detail::get_pointer(root->m_next); - while((detail::char_ptr_cast(prev_block) + prev_block->m_size*Alignment) - != (detail::char_ptr_cast(ptr)) + while((reinterpret_cast(prev_block) + prev_block->m_size*Alignment) + != (reinterpret_cast(ptr)) && prev_block != root){ prev_2_block = prev_block; prev_block = detail::get_pointer(prev_block->m_next); @@ -654,7 +654,7 @@ inline return prev_pair_t(0, 0); //Check if the previous block is in the managed segment - std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment; + std::size_t distance = (reinterpret_cast(prev_block) - reinterpret_cast(this))/Alignment; if(distance >= (m_header.m_size/Alignment)){ //"previous_block" does not exist so we can't expand "block" return prev_pair_t(0, 0); @@ -672,7 +672,7 @@ inline bool simple_seq_fit_impl:: { //Obtain the real size of the block block_ctrl *block = reinterpret_cast - (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + (reinterpret_cast(ptr) - BlockCtrlBytes); std::size_t old_block_size = block->m_size; //All used blocks' next is marked with 0 so check it @@ -747,7 +747,7 @@ inline bool simple_seq_fit_impl:: { //Obtain the real size of the block block_ctrl *block = reinterpret_cast - (detail::char_ptr_cast(ptr) - BlockCtrlBytes); + (reinterpret_cast(ptr) - BlockCtrlBytes); std::size_t block_size = block->m_size; //All used blocks' next is marked with 0 so check it @@ -785,14 +785,14 @@ inline bool simple_seq_fit_impl:: //We create the new block block = reinterpret_cast - (detail::char_ptr_cast(block) + block->m_size*Alignment); + (reinterpret_cast(block) + block->m_size*Alignment); //Write control data to simulate this new block was previously allocated block->m_next = 0; block->m_size = data_size - preferred_size; //Now deallocate the new block to insert it in the free list - this->priv_deallocate(detail::char_ptr_cast(block)+BlockCtrlBytes); + this->priv_deallocate(reinterpret_cast(block)+BlockCtrlBytes); return true; } @@ -820,30 +820,28 @@ inline void* simple_seq_fit_impl:: else if ((((std::size_t)(buffer)) % alignment) == 0) return buffer; - char *aligned_portion = (char*) - ((std::size_t)((char*)buffer + alignment - 1) & -alignment); + char *aligned_portion = reinterpret_cast + (reinterpret_cast(static_cast(buffer) + alignment - 1) & -alignment); - char *pos = ((aligned_portion - (char*)buffer) >= (MinBlockSize*Alignment)) ? + char *pos = ((aligned_portion - reinterpret_cast(buffer)) >= (MinBlockSize*Alignment)) ? aligned_portion : (aligned_portion + alignment); - block_ctrl *first = reinterpret_cast - (detail::char_ptr_cast(buffer) - BlockCtrlBytes); + (reinterpret_cast(buffer) - BlockCtrlBytes); - block_ctrl *second = reinterpret_cast - (detail::char_ptr_cast(pos) - BlockCtrlBytes); + block_ctrl *second = reinterpret_cast(pos - BlockCtrlBytes); std::size_t old_size = first->m_size; - first->m_size = ((char*)second - (char*)first)/Alignment; + first->m_size = (reinterpret_cast(second) - reinterpret_cast(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(detail::char_ptr_cast(first) + BlockCtrlBytes); - return detail::char_ptr_cast(second) + BlockCtrlBytes; + this->priv_deallocate(reinterpret_cast(first) + BlockCtrlBytes); + return reinterpret_cast(second) + BlockCtrlBytes; } template inline @@ -863,7 +861,7 @@ void* simple_seq_fit_impl::priv_check_and_allocate std::size_t total_size = block->m_size; block->m_size = nunits; block_ctrl *new_block = reinterpret_cast - (detail::char_ptr_cast(block) + Alignment*nunits); + (reinterpret_cast(block) + Alignment*nunits); new_block->m_size = total_size - nunits; new_block->m_next = block->m_next; prev->m_next = new_block; @@ -884,9 +882,9 @@ void* simple_seq_fit_impl::priv_check_and_allocate //Mark the block as allocated block->m_next = 0; //Check alignment - assert(((detail::char_ptr_cast(block) - detail::char_ptr_cast(this)) + assert(((reinterpret_cast(block) - reinterpret_cast(this)) % Alignment) == 0 ); - return detail::char_ptr_cast(block)+BlockCtrlBytes; + return reinterpret_cast(block) + BlockCtrlBytes; } return 0; } @@ -913,13 +911,13 @@ void simple_seq_fit_impl::priv_deallocate(void* addr) block_ctrl_ptr prev = &m_header.m_root; block_ctrl_ptr pos = m_header.m_root.m_next; block_ctrl_ptr block = reinterpret_cast - (detail::char_ptr_cast(addr) - BlockCtrlBytes); + (reinterpret_cast(addr) - BlockCtrlBytes); //All used blocks' next is marked with 0 so check it assert(block->m_next == 0); //Check if alignment and block size are right - assert((detail::char_ptr_cast(addr) - detail::char_ptr_cast(this)) + assert((reinterpret_cast(addr) - reinterpret_cast(this)) % Alignment == 0 ); std::size_t total_size = Alignment*block->m_size; @@ -938,9 +936,9 @@ void simple_seq_fit_impl::priv_deallocate(void* addr) } //Try to combine with upper block - if ((detail::char_ptr_cast(detail::get_pointer(block)) + if ((reinterpret_cast(detail::get_pointer(block)) + Alignment*block->m_size) == - detail::char_ptr_cast(detail::get_pointer(pos))){ + reinterpret_cast(detail::get_pointer(pos))){ block->m_size += pos->m_size; block->m_next = pos->m_next; @@ -950,9 +948,9 @@ void simple_seq_fit_impl::priv_deallocate(void* addr) } //Try to combine with lower block - if ((detail::char_ptr_cast(detail::get_pointer(prev)) + if ((reinterpret_cast(detail::get_pointer(prev)) + Alignment*prev->m_size) == - detail::char_ptr_cast(detail::get_pointer(block))){ + reinterpret_cast(detail::get_pointer(block))){ prev->m_size += block->m_size; prev->m_next = block->m_next; } diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index 3898d5f..bd0773a 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -313,8 +313,9 @@ inline simple_seq_fit_impl:: //Initialize pointers std::size_t block1_off = priv_first_block_offset(this, extra_hdr_bytes); + m_header.m_root.m_next = reinterpret_cast - (detail::char_ptr_cast(this) + block1_off); + ((reinterpret_cast(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; @@ -343,8 +344,9 @@ inline void simple_seq_fit_impl::grow(std::size_t extr } //We'll create a new free block with extra_size bytes + block_ctrl *new_block = reinterpret_cast - (detail::char_ptr_cast(this) + old_end); + (reinterpret_cast(this) + old_end); algo_impl_t::assert_alignment(new_block); new_block->m_next = 0; @@ -372,8 +374,8 @@ void simple_seq_fit_impl::shrink_to_fit() block = detail::get_pointer(block->m_next); } - char *last_free_end_address = (char*)last + last->m_size*Alignment; - if(last_free_end_address != ((char*)this + priv_block_end_offset())){ + char *last_free_end_address = reinterpret_cast(last) + last->m_size*Alignment; + if(last_free_end_address != (reinterpret_cast(this) + priv_block_end_offset())){ //there is an allocated block in the end of this block //so no shrinking is possible return; @@ -388,7 +390,7 @@ void simple_seq_fit_impl::shrink_to_fit() if(!unique_block) return; last = detail::get_pointer(m_header.m_root.m_next); - assert(last_free_end_address == ((char*)last + last->m_size*Alignment)); + assert(last_free_end_address == (reinterpret_cast(last) + last->m_size*Alignment)); } std::size_t last_units = last->m_size; @@ -420,14 +422,17 @@ inline typename simple_seq_fit_impl::block_ctrl * simple_seq_fit_impl::priv_get_block(const void *ptr) { - return reinterpret_cast(detail::char_ptr_cast(ptr) - AllocatedCtrlBytes); + return const_cast(reinterpret_cast + (reinterpret_cast(ptr) - AllocatedCtrlBytes)); } template inline void *simple_seq_fit_impl:: priv_get_user_buffer(const typename simple_seq_fit_impl::block_ctrl *block) -{ return detail::char_ptr_cast(block) + AllocatedCtrlBytes; } +{ + return const_cast(reinterpret_cast(block) + AllocatedCtrlBytes); +} template inline void simple_seq_fit_impl::priv_add_segment(void *addr, std::size_t size) @@ -564,7 +569,7 @@ inline std::pair simple_seq_fit_impl:: T *reuse_ptr) { std::pair ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, static_cast(reuse_ptr), sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); @@ -577,7 +582,7 @@ inline std::pair simple_seq_fit_impl:: void *reuse_ptr, std::size_t sizeof_object) { if(!sizeof_object) - return std::pair((void*)0, 0); + return std::pair(static_cast(0), 0); if(command & try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object @@ -596,7 +601,7 @@ inline std::pair simple_seq_fit_impl:: void *reuse_ptr, std::size_t sizeof_object) { command &= ~expand_bwd; - if(!command) return std::pair((void*)0, false); + if(!command) return std::pair(static_cast(0), false); std::pair ret; std::size_t max_count = m_header.m_size/sizeof_object; @@ -623,8 +628,7 @@ inline std::size_t simple_seq_fit_impl:: //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 - (priv_get_block(detail::char_ptr_cast(const_cast(ptr)))); + const block_ctrl *block = static_cast(priv_get_block(ptr)); return block->get_user_bytes(); } @@ -678,8 +682,9 @@ void* simple_seq_fit_impl:: //We need a minimum size to split the previous one if((prev->get_user_bytes() - needs_backwards) > 2*BlockCtrlBytes){ - block_ctrl *new_block = reinterpret_cast - (detail::char_ptr_cast(reuse) - needs_backwards - BlockCtrlBytes); + block_ctrl *new_block = reinterpret_cast + (reinterpret_cast(reuse) - needs_backwards - BlockCtrlBytes); + new_block->m_next = 0; new_block->m_size = BlockCtrlUnits + (needs_backwards + extra_forward)/Alignment; @@ -769,7 +774,7 @@ std::pair simple_seq_fit_impl:: received_size = 0; if(limit_size > preferred_size) - return return_type((void*)0, false); + return return_type(static_cast(0), false); //Number of units to request (including block_ctrl header) std::size_t nunits = detail::get_rounded_size(preferred_size, Alignment)/Alignment + BlockCtrlUnits; @@ -819,7 +824,7 @@ std::pair simple_seq_fit_impl:: 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((void*)0, false); + return return_type(static_cast(0), false); received_size = biggest_block->m_size*Alignment - BlockCtrlUnits; void *ret = this->priv_check_and_allocate @@ -836,7 +841,7 @@ std::pair simple_seq_fit_impl:: algo_impl_t::assert_alignment(ret.first); return ret; } - return return_type((void*)0, false); + return return_type(static_cast(0), false); } template inline @@ -852,10 +857,13 @@ inline typename simple_seq_fit_impl::block_ctrl * { //Take the address where the next block should go block_ctrl *next_block = reinterpret_cast - (detail::char_ptr_cast(ptr) + ptr->m_size*Alignment); + (reinterpret_cast(ptr) + ptr->m_size*Alignment); //Check if the adjacent block is in the managed segment - std::size_t distance = (detail::char_ptr_cast(next_block) - detail::char_ptr_cast(this))/Alignment; + char *this_char_ptr = reinterpret_cast(this); + char *next_char_ptr = reinterpret_cast(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; @@ -880,21 +888,25 @@ inline block_ctrl *root = &m_header.m_root; block_ctrl *prev_2_block = root; block_ctrl *prev_block = detail::get_pointer(root->m_next); - while((detail::char_ptr_cast(prev_block) + prev_block->m_size*Alignment) - != (detail::char_ptr_cast(ptr)) + + while((reinterpret_cast(prev_block) + prev_block->m_size*Alignment) + != reinterpret_cast(ptr) && prev_block != root){ prev_2_block = prev_block; prev_block = detail::get_pointer(prev_block->m_next); } if(prev_block == root || !prev_block->m_next) - return prev_pair_t((block_ctrl*)0, (block_ctrl*)0); + return prev_pair_t(static_cast(0), static_cast(0)); //Check if the previous block is in the managed segment - std::size_t distance = (detail::char_ptr_cast(prev_block) - detail::char_ptr_cast(this))/Alignment; + char *this_char_ptr = reinterpret_cast(this); + char *prev_char_ptr = reinterpret_cast(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((block_ctrl*)0, (block_ctrl*)0); + return prev_pair_t(static_cast(0), static_cast(0)); } return prev_pair_t(prev_2_block, prev_block); } @@ -990,8 +1002,9 @@ void* simple_seq_fit_impl::priv_check_and_allocate //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 - (detail::char_ptr_cast(block) + Alignment*nunits); + (reinterpret_cast(block) + Alignment*nunits); new_block->m_size = total_size - nunits; new_block->m_next = block->m_next; prev->m_next = new_block; @@ -1063,10 +1076,10 @@ void simple_seq_fit_impl::priv_deallocate(void* addr) } //Try to combine with upper block - if ((detail::char_ptr_cast(detail::get_pointer(block)) - + Alignment*block->m_size) == - detail::char_ptr_cast(detail::get_pointer(pos))){ + char *block_char_ptr = reinterpret_cast(detail::get_pointer(block)); + if ((block_char_ptr + Alignment*block->m_size) == + reinterpret_cast(detail::get_pointer(pos))){ block->m_size += pos->m_size; block->m_next = pos->m_next; } @@ -1075,9 +1088,11 @@ void simple_seq_fit_impl::priv_deallocate(void* addr) } //Try to combine with lower block - if ((detail::char_ptr_cast(detail::get_pointer(prev)) + if ((reinterpret_cast(detail::get_pointer(prev)) + Alignment*prev->m_size) == - detail::char_ptr_cast(detail::get_pointer(block))){ + block_char_ptr){ + + prev->m_size += block->m_size; prev->m_next = block->m_next; } diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 9634116..5379139 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -331,7 +331,7 @@ class rbtree_best_fit ; private: - //Due to embedded bits in size, Alignment must be at least 2 + //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::value)); @@ -380,7 +380,7 @@ inline rbtree_best_fit:: //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(detail::char_ptr_cast(this) + block1_off, size - block1_off); + priv_add_segment(reinterpret_cast(this) + block1_off, size - block1_off); } template @@ -399,11 +399,11 @@ void rbtree_best_fit::grow(std::size_t e priv_first_block_offset(this, m_header.m_extra_hdr_bytes); block_ctrl *first_block = reinterpret_cast - (detail::char_ptr_cast(this) + block1_off); + (reinterpret_cast(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 = (detail::char_ptr_cast(old_end_block) - - detail::char_ptr_cast(this)) + EndCtrlBlockBytes; + std::size_t old_border_offset = (reinterpret_cast(old_end_block) - + reinterpret_cast(this)) + EndCtrlBlockBytes; //Update managed buffer's size m_header.m_size += extra_size; @@ -417,9 +417,9 @@ void rbtree_best_fit::grow(std::size_t e //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 - (detail::char_ptr_cast(old_end_block) + align_offset*Alignment); - new_end_block->m_size = (detail::char_ptr_cast(first_block) - - detail::char_ptr_cast(new_end_block))/Alignment; + (reinterpret_cast(old_end_block) + align_offset*Alignment); + new_end_block->m_size = (reinterpret_cast(first_block) - + reinterpret_cast(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); @@ -428,8 +428,8 @@ void rbtree_best_fit::grow(std::size_t e //The old end block is the new block block_ctrl *new_block = old_end_block; - new_block->m_size = (detail::char_ptr_cast(new_end_block) - - detail::char_ptr_cast(new_block))/Alignment; + new_block->m_size = (reinterpret_cast(new_end_block) - + reinterpret_cast(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); @@ -448,7 +448,7 @@ void rbtree_best_fit::shrink_to_fit() priv_first_block_offset(this, m_header.m_extra_hdr_bytes); block_ctrl *first_block = reinterpret_cast - (detail::char_ptr_cast(this) + block1_off); + (reinterpret_cast(this) + block1_off); algo_impl_t::assert_alignment(first_block); block_ctrl *old_end_block = priv_end_block(first_block); @@ -485,8 +485,8 @@ void rbtree_best_fit::shrink_to_fit() //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 = (detail::char_ptr_cast(last_block) - - detail::char_ptr_cast(this)) + EndCtrlBlockBytes; + std::size_t shrunk_border_offset = (reinterpret_cast(last_block) - + reinterpret_cast(this)) + EndCtrlBlockBytes; block_ctrl *new_end_block = last_block; algo_impl_t::assert_alignment(new_end_block); @@ -521,13 +521,12 @@ void rbtree_best_fit:: //The "end" node is just a node of size 0 with the "end" bit set block_ctrl *end_block = static_cast - (new (reinterpret_cast - (detail::char_ptr_cast(addr) + first_big_block->m_size*Alignment))SizeHolder); + (new (reinterpret_cast(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 = - (detail::char_ptr_cast(first_big_block) - detail::char_ptr_cast(end_block))/Alignment; + (reinterpret_cast(first_big_block) - reinterpret_cast(end_block))/Alignment; priv_mark_as_allocated_block(end_block); assert(priv_next_block(first_big_block) == end_block); @@ -539,7 +538,8 @@ void rbtree_best_fit:: //to optimize the space wasted in bookkeeping: //Check that the sizes of the header are placed before the rbtree - assert((void*)(SizeHolder*)first_big_block < (void*)(TreeHook*)first_big_block); + assert(static_cast(static_cast(first_big_block)) + < static_cast(static_cast(first_big_block))); //Check that the alignment is power of two (we use some optimizations based on this) //assert((Alignment % 2) == 0); @@ -653,7 +653,7 @@ inline std::pair rbtree_best_fit ret = priv_allocation_command - (command, limit_size, preferred_size, received_size, (void*)reuse_ptr, sizeof(T)); + (command, limit_size, preferred_size, received_size, static_cast(reuse_ptr), sizeof(T)); BOOST_ASSERT(0 == ((std::size_t)ret.first % detail::alignment_of::value)); return std::pair(static_cast(ret.first), ret.second); @@ -666,7 +666,7 @@ inline std::pair rbtree_best_fit((void *)0, 0); + return std::pair(static_cast(0), 0); if(command & try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object @@ -724,7 +724,7 @@ inline void rbtree_best_fit::zero_free_m //Iterate through all blocks obtaining their size for(; ib != ie; ++ib){ //Just clear user the memory part reserved for the user - std::memset( detail::char_ptr_cast(&*ib) + BlockCtrlBytes + std::memset( reinterpret_cast(&*ib) + BlockCtrlBytes , 0 , ib->m_size*Alignment - BlockCtrlBytes); } @@ -801,7 +801,7 @@ void* rbtree_best_fit:: //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 - (detail::char_ptr_cast(reuse) - needs_backwards_aligned); + (reinterpret_cast(reuse) - needs_backwards_aligned); //Free old previous buffer new_block->m_size = @@ -809,8 +809,8 @@ void* rbtree_best_fit:: assert(new_block->m_size >= BlockCtrlUnits); priv_mark_new_allocated_block(new_block); - prev_block->m_size = (detail::char_ptr_cast(new_block) - - detail::char_ptr_cast(prev_block))/Alignment; + prev_block->m_size = (reinterpret_cast(new_block) - + reinterpret_cast(prev_block))/Alignment; assert(prev_block->m_size >= BlockCtrlUnits); priv_mark_as_free_block(prev_block); @@ -836,8 +836,8 @@ void* rbtree_best_fit:: //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 = detail::char_ptr_cast(p); - assert(((char*)reuse_ptr - (char*)user_ptr) % backwards_multiple == 0); + void *user_ptr = reinterpret_cast(p); + assert((static_cast(reuse_ptr) - static_cast(user_ptr)) % backwards_multiple == 0); algo_impl_t::assert_alignment(user_ptr); return user_ptr; } @@ -860,9 +860,8 @@ void* rbtree_best_fit:: //If the backwards expansion has remaining bytes in the //first bytes, fill them with a pattern - void *p = priv_get_user_buffer(prev_block); - void *user_ptr = detail::char_ptr_cast(p); - assert(((char*)reuse_ptr - (char*)user_ptr) % backwards_multiple == 0); + void *user_ptr = priv_get_user_buffer(prev_block); + assert((static_cast(reuse_ptr) - static_cast(user_ptr)) % backwards_multiple == 0); algo_impl_t::assert_alignment(user_ptr); return user_ptr; } @@ -932,7 +931,7 @@ std::pair rbtree_best_fit: received_size = 0; if(limit_size > preferred_size) - return return_type((void*)0, false); + return return_type(static_cast(0), false); //Number of units to request (including block_ctrl header) std::size_t preferred_units = priv_get_total_units(preferred_size); @@ -971,7 +970,7 @@ std::pair rbtree_best_fit: (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); } - return return_type((void*)0, false); + return return_type(static_cast(0), false); } template @@ -979,14 +978,16 @@ inline typename rbtree_best_fit::block_ctrl * rbtree_best_fit::priv_get_block(const void *ptr) { - return reinterpret_cast(detail::char_ptr_cast(ptr) - AllocatedCtrlBytes); + return const_cast + (reinterpret_cast + (reinterpret_cast(ptr) - AllocatedCtrlBytes)); } template inline void *rbtree_best_fit:: priv_get_user_buffer(const typename rbtree_best_fit::block_ctrl *block) -{ return detail::char_ptr_cast(block) + AllocatedCtrlBytes; } +{ return const_cast(reinterpret_cast(block) + AllocatedCtrlBytes); } template inline @@ -1077,7 +1078,7 @@ bool rbtree_best_fit:: } //This is the remaining block block_ctrl *rem_block = new(reinterpret_cast - (detail::char_ptr_cast(block) + intended_units*Alignment))block_ctrl; + (reinterpret_cast(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); @@ -1116,7 +1117,7 @@ typename rbtree_best_fit::block_ctrl * { assert(!ptr->m_prev_allocated); return reinterpret_cast - (detail::char_ptr_cast(ptr) - ptr->m_prev_size*Alignment); + (reinterpret_cast(ptr) - ptr->m_prev_size*Alignment); } template inline @@ -1141,7 +1142,7 @@ typename rbtree_best_fit::block_ctrl * { assert(first_segment_block->m_prev_allocated); block_ctrl *end_block = reinterpret_cast - (detail::char_ptr_cast(first_segment_block) - first_segment_block->m_prev_size*Alignment); + (reinterpret_cast(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); @@ -1154,7 +1155,7 @@ typename rbtree_best_fit::block_ctrl * (typename rbtree_best_fit::block_ctrl *ptr) { return reinterpret_cast - (detail::char_ptr_cast(ptr) + ptr->m_size*Alignment); + (reinterpret_cast(ptr) + ptr->m_size*Alignment); } template inline @@ -1162,8 +1163,8 @@ bool rbtree_best_fit::priv_is_allocated_ (typename rbtree_best_fit::block_ctrl *block) { bool allocated = block->m_allocated != 0; - block_ctrl *next_block = (block_ctrl *) - (detail::char_ptr_cast(block) + block->m_size*Alignment); + block_ctrl *next_block = reinterpret_cast + (reinterpret_cast(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); @@ -1176,7 +1177,8 @@ void rbtree_best_fit::priv_mark_as_alloc { //assert(!priv_is_allocated_block(block)); block->m_allocated = 1; - ((block_ctrl *)(((char*)block) + block->m_size*Alignment))->m_prev_allocated = 1; + reinterpret_cast + (reinterpret_cast(block)+ block->m_size*Alignment)->m_prev_allocated = 1; } template inline @@ -1184,7 +1186,8 @@ void rbtree_best_fit::priv_mark_as_free_ (typename rbtree_best_fit::block_ctrl *block) { block->m_allocated = 0; - ((block_ctrl *)(((char*)block) + block->m_size*Alignment))->m_prev_allocated = 0; + reinterpret_cast + (reinterpret_cast(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; } @@ -1209,7 +1212,7 @@ void* rbtree_best_fit::priv_check_and_al //This is the remaining block block_ctrl *rem_block = new(reinterpret_cast - (detail::char_ptr_cast(block) + Alignment*nunits))block_ctrl; + (reinterpret_cast(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); diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index 627c440..e89ef76 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -61,17 +61,17 @@ class offset_ptr __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 void*)ptr); } + { set_offset(const_cast(ptr)); } void set_offset(const void *ptr) { - const char *p = static_cast(const_cast(ptr)); + const char *p = static_cast(ptr); //offset == 1 && ptr != 0 is not legal for this pointer if(!ptr){ m_offset = 1; } else{ - m_offset = p - detail::char_ptr_cast(this); + m_offset = p - reinterpret_cast(this); BOOST_ASSERT(m_offset != 1); } } @@ -80,7 +80,7 @@ class offset_ptr __declspec(noinline) //this workaround is needed for msvc-8.0 and msvc-9.0 #endif void* get_pointer() const - { return (m_offset == 1) ? 0 : (detail::char_ptr_cast(this) + m_offset); } + { return (m_offset == 1) ? 0 : (const_cast(reinterpret_cast(this)) + m_offset); } void inc_offset(std::ptrdiff_t bytes) { m_offset += bytes; } @@ -149,7 +149,7 @@ class offset_ptr //!Obtains raw pointer from offset. //!Never throws. pointer get()const - { return (pointer)this->get_pointer(); } + { return static_cast(this->get_pointer()); } std::ptrdiff_t get_offset() { return m_offset; } @@ -425,13 +425,13 @@ struct pointer_plus_bits, NumBits> static const std::size_t Mask = ((std::size_t(1) << NumBits)-1)<<1u; static pointer get_pointer(const pointer &n) - { return (T*)(std::size_t(n.get()) & ~std::size_t(Mask)); } + { return reinterpret_cast(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 = (T*)(pint | (std::size_t(n.get()) & std::size_t(Mask))); + n = reinterpret_cast(pint | (std::size_t(n.get()) & std::size_t(Mask))); } static std::size_t get_bits(const pointer &n) @@ -440,7 +440,7 @@ struct pointer_plus_bits, NumBits> static void set_bits(pointer &n, std::size_t b) { assert(b < (std::size_t(1) << NumBits)); - n = (T*)(std::size_t(get_pointer(n).get()) | (b << 1u)); + n = reinterpret_cast(std::size_t(get_pointer(n).get()) | (b << 1u)); } }; diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index 545cf5d..a9836f6 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -305,7 +305,7 @@ class segment_manager_base //Call destructors and free memory //Build scoped ptr to avoid leaks with destructor exception std::size_t destroyed = 0; - table.destroy_n((void*)object, ctrl_data->m_value_bytes/table.size, destroyed); + table.destroy_n(const_cast(object), ctrl_data->m_value_bytes/table.size, destroyed); this->deallocate(ctrl_data); } /// @endcond @@ -410,40 +410,38 @@ class segment_manager segment_manager(std::size_t size) : Base(size, priv_get_reserved_bytes()) , m_header(static_cast(get_this_pointer())) - { (void) anonymous_instance; (void) unique_instance; } + { + (void) anonymous_instance; (void) unique_instance; + assert(static_cast(this) == static_cast(static_cast(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 std::pair find (const CharType* name) - { - //The name can't be null, no anonymous object can be found by name - assert(name != 0); - detail::placement_destroy table; - std::size_t size; - void *ret; - - if(name == reinterpret_cast(-1)){ - ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), true); - } - else{ - ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), true); - } - return std::pair(static_cast(ret), size); - } + { return this->priv_find_impl(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 std::pair find (const detail::unique_instance_t* name) - { - detail::placement_destroy table; - std::size_t size; - void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), true); - return std::pair(static_cast(ret), size); - } + { return this->priv_find_impl(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 + std::pair find_no_lock (const CharType* name) + { return this->priv_find_impl(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 + std::pair find_no_lock (const detail::unique_instance_t* name) + { return this->priv_find_impl(name, false); } //!Returns throwing "construct" proxy //!object @@ -690,11 +688,12 @@ class segment_manager (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 - std::pair find_no_lock (const CharType* name) + std::pair 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); @@ -703,10 +702,10 @@ class segment_manager void *ret; if(name == reinterpret_cast(-1)){ - ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), false); + ret = priv_generic_find (typeid(T).name(), m_header.m_unique_index, table, size, is_intrusive_t(), lock); } else{ - ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), false); + ret = priv_generic_find (name, m_header.m_named_index, table, size, is_intrusive_t(), lock); } return std::pair(static_cast(ret), size); } @@ -715,15 +714,14 @@ class segment_manager //!and the object count. On failure the first member of the //!returned pair is 0. template - std::pair find_no_lock (const detail::unique_instance_t* name) + std::pair priv_find__impl (const detail::unique_instance_t* name, bool lock) { detail::placement_destroy table; std::size_t size; - void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), false); + void *ret = priv_generic_find(name, m_header.m_unique_index, table, size, is_intrusive_t(), lock); return std::pair(static_cast(ret), size); } - private: void *priv_generic_construct(const CharType *name, std::size_t num, bool try2find, @@ -815,8 +813,7 @@ class segment_manager { //Get the number of bytes until the end of (*this) //beginning in the end of the Base base. - return (detail::char_ptr_cast((segment_manager*)0) + sizeof(segment_manager)) - - (detail::char_ptr_cast(static_cast((segment_manager*)0)) + sizeof(Base)); + return sizeof(segment_manager) - sizeof(Base); } template @@ -1014,7 +1011,7 @@ class segment_manager //Get allocation parameters block_header_t *ctrl_data = reinterpret_cast (detail::get_pointer(it->second.m_ptr)); - char *stored_name = detail::char_ptr_cast(it->first.name()); + char *stored_name = static_cast(static_cast(const_cast(it->first.name()))); (void)stored_name; //Check if the distance between the name pointer and the memory pointer @@ -1024,7 +1021,7 @@ class segment_manager //Sanity check assert((ctrl_data->m_value_bytes % table.size) == 0); - assert((void*)stored_name == ctrl_data->template name()); + assert(static_cast(stored_name) == static_cast(ctrl_data->template name())); assert(sizeof(CharT) == ctrl_data->sizeof_char()); //Erase node from index @@ -1113,7 +1110,12 @@ class segment_manager if(try2find){ return it->get_block_header()->value(); } - return 0; + if(dothrow){ + throw interprocess_exception(already_exists_error); + } + else{ + return 0; + } } //Allocates buffer for name + data, this can throw (it hurts) @@ -1153,22 +1155,23 @@ class segment_manager } BOOST_CATCH_END - //Initialize the node value_eraser to erase inserted node - //if something goes wrong - value_eraser v_eraser(index, it); - //Avoid constructions if constructor is trivial //Build scoped ptr to avoid leaks with constructor exception detail::mem_algo_deallocator mem (buffer_ptr, *static_cast(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 v_eraser(index, it); + //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 + //Release rollbacks since construction was successful v_eraser.release(); + mem.release(); return ptr; } @@ -1216,8 +1219,7 @@ class segment_manager //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))); + insert_ret = index.insert(value_type(key_type (name, namelen), mapped_type(0))); } //Ignore exceptions BOOST_CATCH(...){ diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index c07c79f..7866696 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -220,6 +220,7 @@ inline bool shared_memory_object::priv_open_or_create throw interprocess_exception(err); } + //detail::delete_file_on_reboot_if_possible(shmfile.c_str()); m_mode = mode; return true; } diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index ca5f1bd..4a73eaf 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -593,7 +593,7 @@ struct managed_unique_ptr > type; }; -//!Returns an instance of the a unique pointer constructed +//!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 diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index e43c519..d69e4fe 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -236,7 +236,7 @@ struct managed_weak_ptr > type; }; -//!Returns an instance of the a weak pointer constructed +//!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 diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index 05f6ff2..b40e3c7 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -53,12 +53,12 @@ inline void interprocess_condition::notify(boost::uint32_t command) } //Notify that all threads should execute wait logic - while(SLEEP != detail::atomic_cas32((boost::uint32_t*)&m_command, command, SLEEP)){ + while(SLEEP != detail::atomic_cas32(const_cast(&m_command), command, SLEEP)){ detail::thread_yield(); } /* //Wait until the threads are woken - while(SLEEP != detail::atomic_cas32((boost::uint32_t*)&m_command, 0)){ + while(SLEEP != detail::atomic_cas32(const_cast(&m_command), 0)){ detail::thread_yield(); } */ @@ -107,7 +107,7 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, //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((boost::uint32_t*)&m_num_waiters); + detail::atomic_inc32(const_cast(&m_num_waiters)); //We unlock the external interprocess_mutex atomically with the increment mut.unlock(); @@ -150,7 +150,7 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, //If a timeout occurred, the interprocess_mutex will not execute checking logic if(tout_enabled && timed_out){ //Decrement wait count - detail::atomic_dec32((boost::uint32_t*)&m_num_waiters); + detail::atomic_dec32(const_cast(&m_num_waiters)); unlock_enter_mut = true; break; } @@ -172,7 +172,7 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, return false; //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 - ((boost::uint32_t*)&m_command, SLEEP, NOTIFY_ONE); + (const_cast(&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 @@ -184,17 +184,17 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, //so no other thread will exit. //Decrement wait count. unlock_enter_mut = true; - detail::atomic_dec32((boost::uint32_t*)&m_num_waiters); + detail::atomic_dec32(const_cast(&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((boost::uint32_t*)&m_num_waiters); + unlock_enter_mut = 1 == detail::atomic_dec32(const_cast(&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((boost::uint32_t*)&m_command, SLEEP, NOTIFY_ALL); + detail::atomic_cas32(const_cast(&m_command), SLEEP, NOTIFY_ALL); } break; } diff --git a/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp index 4ef74c2..a2fa2aa 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_mutex.hpp @@ -30,7 +30,7 @@ inline interprocess_mutex::~interprocess_mutex() inline void interprocess_mutex::lock(void) { do{ - boost::uint32_t prev_s = detail::atomic_cas32((boost::uint32_t*)&m_s, 1, 0); + boost::uint32_t prev_s = detail::atomic_cas32(const_cast(&m_s), 1, 0); if (m_s == 1 && prev_s == 0){ break; @@ -42,12 +42,16 @@ inline void interprocess_mutex::lock(void) inline bool interprocess_mutex::try_lock(void) { - boost::uint32_t prev_s = detail::atomic_cas32((boost::uint32_t*)&m_s, 1, 0); + boost::uint32_t prev_s = detail::atomic_cas32(const_cast(&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(); @@ -70,7 +74,7 @@ inline bool interprocess_mutex::timed_lock(const boost::posix_time::ptime &abs_t } inline void interprocess_mutex::unlock(void) -{ detail::atomic_cas32((boost::uint32_t*)&m_s, 0, 1); } +{ detail::atomic_cas32(const_cast(&m_s), 0, 1); } } //namespace interprocess { diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp index 83235be..8cc7de2 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -75,6 +75,10 @@ inline bool interprocess_recursive_mutex::try_lock() 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; + } detail::OS_thread_id_t th_id = detail::get_current_thread_id(); if(detail::equal_thread_id(th_id, m_nOwner)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ diff --git a/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp b/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp index 6c75bfd..fb80991 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_semaphore.hpp @@ -52,6 +52,10 @@ inline bool interprocess_semaphore::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; + } scoped_lock lock(m_mut); while(m_count == 0){ if(!m_cond.timed_wait(lock, abs_time)) diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index d3f7e0b..dfef5ff 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -205,6 +205,10 @@ inline bool file_lock::try_lock() 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()); @@ -241,6 +245,10 @@ inline bool file_lock::try_lock_sharable() 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()); diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 59ebbdb..5c4a123 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -26,7 +26,7 @@ #include #include -#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) #include #include #include @@ -107,9 +107,12 @@ class interprocess_condition template 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()); } @@ -119,9 +122,12 @@ class interprocess_condition template 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(); diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index c7a1ee1..5717725 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -36,7 +36,7 @@ #include #include -#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) #include #include #include diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index d84be12..6f2eae9 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -36,7 +36,8 @@ #include #include -#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED && defined BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES)) #include #include #include diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp index ccd5ec4..b10eb89 100644 --- a/include/boost/interprocess/sync/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -21,8 +21,8 @@ #include #include -#if defined BOOST_INTERPROCESS_POSIX_PROCESS_SHARED &&\ - defined BOOST_INTERPROCESS_POSIX_SEMAPHORES +#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES)) #include //O_CREAT, O_*... #include //close #include //std::string diff --git a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp index 80c975d..5441805 100644 --- a/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @@ -322,6 +322,10 @@ inline bool interprocess_upgradable_mutex::try_lock() 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; @@ -399,6 +403,10 @@ inline bool interprocess_upgradable_mutex::try_lock_upgradable() 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; @@ -471,6 +479,10 @@ inline bool interprocess_upgradable_mutex::try_lock_sharable() 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; diff --git a/include/boost/interprocess/sync/lock_options.hpp b/include/boost/interprocess/sync/lock_options.hpp index dad8f67..65a7e32 100644 --- a/include/boost/interprocess/sync/lock_options.hpp +++ b/include/boost/interprocess/sync/lock_options.hpp @@ -41,7 +41,7 @@ namespace detail{ //!must be deferred. static const detail::defer_lock_type defer_lock = detail::defer_lock_type(); -//!An object indicating that the a try_lock() +//!An object indicating that a try_lock() //!operation must be executed. static const detail::try_to_lock_type try_to_lock = detail::try_to_lock_type(); diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index cc3b758..38ce368 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -259,6 +259,10 @@ template 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); @@ -268,6 +272,10 @@ template 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(); @@ -309,6 +317,10 @@ template 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()); @@ -318,6 +330,10 @@ template 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(); diff --git a/include/boost/interprocess/sync/named_mutex.hpp b/include/boost/interprocess/sync/named_mutex.hpp index a1f5e21..a4af3c3 100644 --- a/include/boost/interprocess/sync/named_mutex.hpp +++ b/include/boost/interprocess/sync/named_mutex.hpp @@ -150,7 +150,13 @@ inline bool named_mutex::try_lock() { return m_sem.try_wait(); } inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) -{ return m_sem.timed_wait(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); } @@ -203,7 +209,13 @@ inline bool named_mutex::try_lock() { return this->mutex()->try_lock(); } inline bool named_mutex::timed_lock(const boost::posix_time::ptime &abs_time) -{ return this->mutex()->timed_lock(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); } diff --git a/include/boost/interprocess/sync/named_recursive_mutex.hpp b/include/boost/interprocess/sync/named_recursive_mutex.hpp index 9f8b8f3..f19a3d1 100644 --- a/include/boost/interprocess/sync/named_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/named_recursive_mutex.hpp @@ -156,7 +156,13 @@ 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) -{ return this->mutex()->timed_lock(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); } diff --git a/include/boost/interprocess/sync/named_semaphore.hpp b/include/boost/interprocess/sync/named_semaphore.hpp index 7754750..607447a 100644 --- a/include/boost/interprocess/sync/named_semaphore.hpp +++ b/include/boost/interprocess/sync/named_semaphore.hpp @@ -154,7 +154,13 @@ inline bool named_semaphore::try_wait() { return m_sem.try_wait(); } inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) -{ return m_sem.timed_wait(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); } @@ -210,7 +216,13 @@ inline bool named_semaphore::try_wait() { return semaphore()->try_wait(); } inline bool named_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) -{ return semaphore()->timed_wait(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); } diff --git a/include/boost/interprocess/sync/named_upgradable_mutex.hpp b/include/boost/interprocess/sync/named_upgradable_mutex.hpp index 79c624f..27d9295 100644 --- a/include/boost/interprocess/sync/named_upgradable_mutex.hpp +++ b/include/boost/interprocess/sync/named_upgradable_mutex.hpp @@ -185,7 +185,7 @@ class named_upgradable_mutex //!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 releas it. + //! sharable ownership release it. //!Throws: An exception derived from interprocess_exception on error. void unlock_upgradable_and_lock(); @@ -285,7 +285,13 @@ inline bool named_upgradable_mutex::try_lock() inline bool named_upgradable_mutex::timed_lock (const boost::posix_time::ptime &abs_time) -{ return this->mutex()->timed_lock(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(); } @@ -298,7 +304,13 @@ inline bool named_upgradable_mutex::try_lock_upgradable() inline bool named_upgradable_mutex::timed_lock_upgradable (const boost::posix_time::ptime &abs_time) -{ return this->mutex()->timed_lock_upgradable(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(); } @@ -311,7 +323,13 @@ inline bool named_upgradable_mutex::try_lock_sharable() inline bool named_upgradable_mutex::timed_lock_sharable (const boost::posix_time::ptime &abs_time) -{ return this->mutex()->timed_lock_sharable(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(); } diff --git a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp index 692542f..398a154 100644 --- a/include/boost/interprocess/sync/posix/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_mutex.hpp @@ -63,6 +63,10 @@ inline bool interprocess_mutex::try_lock() 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); diff --git a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp index 0701a3e..ec82c42 100644 --- a/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_recursive_mutex.hpp @@ -64,6 +64,10 @@ inline bool interprocess_recursive_mutex::try_lock() 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); diff --git a/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp b/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp index e55b0fd..0266417 100644 --- a/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/posix/interprocess_semaphore.hpp @@ -32,7 +32,13 @@ inline bool interprocess_semaphore::try_wait() { return m_sem.try_wait(); } inline bool interprocess_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) -{ return m_sem.timed_wait(abs_time); } +{ + 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(); } diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp index 51d1e57..67b6998 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -22,7 +22,7 @@ #ifdef SEM_FAILED #define BOOST_INTERPROCESS_POSIX_SEM_FAILED SEM_FAILED #else -#define BOOST_INTERPROCESS_POSIX_SEM_FAILED ((sem_t*)(-1)) +#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(-1)) #endif #ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index 705f863..178140e 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -48,7 +48,7 @@ class upgradable_lock; //!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 trasfer_lock syntax.*/ +//!upgradable_lock and scoped_lock via transfer_lock syntax.*/ template class sharable_lock { diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 6b1340d..c541487 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -43,12 +43,12 @@ class sharable_lock; //!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 trasfer_lock syntax. The Mutex need not supply all of the functionality. +//!using transfer_lock syntax. The Mutex need not supply all of the functionality. //!If the client of upgradable_lock 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 trasfer_lock syntax. +//!a upgradable_locks or scoped_locks via transfer_lock syntax. template class upgradable_lock { From dc0eb8fe0e11359b3ca8d5d8a7b22c43beda45d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 11 Oct 2008 13:18:02 +0000 Subject: [PATCH 53/77] Changes and fixes for Boost 1.37 [SVN r49277] --- doc/interprocess.qbk | 214 ++++--- example/doc_contB.cpp | 2 +- example/doc_ipc_messageA.cpp | 2 +- example/doc_ipc_messageB.cpp | 2 +- example/doc_managed_aligned_allocation.cpp | 6 +- example/doc_managed_copy_on_write.cpp | 2 +- example/doc_managed_external_buffer.cpp | 2 +- example/doc_named_allocA.cpp | 2 +- example/doc_named_allocB.cpp | 2 +- example/doc_offset_ptr.cpp | 2 +- example/doc_shared_memory2.cpp | 1 + proj/to-do.txt | 54 ++ proj/vc7ide/Interprocess.sln | 10 +- proj/vc7ide/interprocesslib.vcproj | 21 + proj/vc7ide/named_construct_test.vcproj | 133 ++++ test/allocator_v1.hpp | 2 +- test/cached_node_allocator_test.cpp | 2 +- test/deque_test.cpp | 122 +++- test/emplace_test.hpp | 640 ++++++++++++++++++++ test/expand_bwd_test_template.hpp | 10 +- test/flat_tree_test.cpp | 38 +- test/intersegment_ptr_test.cpp | 15 +- test/list_test.cpp | 19 + test/list_test.hpp | 1 - test/managed_mapped_file_test.cpp | 3 +- test/memory_algorithm_test_template.hpp | 18 +- test/movable_int.hpp | 6 + test/mutex_test_template.hpp | 6 +- test/named_construct_test.cpp | 195 ++++++ test/node_allocator_test.cpp | 2 +- test/private_node_allocator_test.cpp | 2 +- test/semaphore_test_template.hpp | 6 +- test/sharable_mutex_test_template.hpp | 40 +- test/shared_memory_mapping_test.cpp | 4 +- test/shared_ptr_test.cpp | 2 +- test/slist_test.cpp | 31 + test/tree_test.cpp | 62 +- test/user_buffer_test.cpp | 2 +- test/vector_test.cpp | 18 + test/vector_test.hpp | 37 +- test/windows_shared_memory_mapping_test.cpp | 4 +- 41 files changed, 1536 insertions(+), 206 deletions(-) create mode 100644 proj/to-do.txt create mode 100644 proj/vc7ide/named_construct_test.vcproj create mode 100644 test/emplace_test.hpp create mode 100644 test/named_construct_test.cpp diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index e0bd4a0..2665ea2 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -146,7 +146,7 @@ list, map, so you can avoid these manual data structures just like with standard [*Boost.Interprocess] allows creating complex objects in shared memory and memory mapped files. For example, we can construct STL-like containers in shared memory. -To do this, we just need to create a an special (managed) shared memory segment, +To do this, we just need to create a special (managed) shared memory segment, declare a [*Boost.Interprocess] allocator and construct the vector in shared memory just if it was any other object. Just execute this first process: @@ -207,7 +207,7 @@ processes we have several alternatives: shared memory or memory mapped files. Once the processes set up the memory region, the processes can read/write the data like any other memory segment without calling the operating system's kernel. This - also requieres some kind of manual synchronization between processes. + also requires some kind of manual synchronization between processes. [endsect] @@ -264,7 +264,7 @@ so that two unrelated processes can use the same interprocess mechanism object. Examples of this are shared memory, named mutexes and named semaphores (for example, native windows CreateMutex/CreateSemaphore API family). -The name used to identify a interprocess mechanism is not portable, even between +The name used to identify an interprocess mechanism is not portable, even between UNIX systems. For this reason, [*Boost.Interprocess] limits this name to a C++ variable identifier or keyword: @@ -281,7 +281,7 @@ identifier or keyword: Named [*Boost.Interprocess] resources (shared memory, memory mapped files, named mutexes/conditions/semaphores) have kernel or filesystem persistency. This means that even if all processes that have opened those resources -end, the resource will still be accesible to be opened again and the resource +end, the resource will still be accessible to be opened again and the resource can only be destructed via an explicit to their static member `remove` function. This behavior can be easily understood, since it's the same mechanism used by functions controlling file opening/creation/erasure: @@ -332,7 +332,7 @@ processes, so that several processes can read and write in that memory segment without calling operating system functions. However, we need some kind of synchronization between processes that read and write shared memory. -Consider what happens when a server process wants to send a html file to a client process +Consider what happens when a server process wants to send an HTML file to a client process that resides in the same machine using network mechanisms: * The server must read the file to memory and pass it to the network functions, that @@ -457,7 +457,7 @@ For more details regarding `shared_memory_object` see the Once created or opened, a process just has to map the shared memory object in the process' address space. The user can map the whole shared memory or just part of it. The -mapping process is done using the the `mapped_region` class. The class represents +mapping process is done using the `mapped_region` class. The class represents a memory region that has been mapped from a shared memory or from other devices that have also mapping capabilities (for example, files). A `mapped_region` can be created from any `memory_mappable` object and as you might imagine, `shared_memory_object` @@ -533,7 +533,7 @@ has filesystem lifetime in those systems. [section:removing Removing shared memory] [classref boost::interprocess::shared_memory_object shared_memory_object] -provides an static `remove` function to remove a shared memory objects. +provides a static `remove` function to remove a shared memory objects. This function [*can] fail if the shared memory objects does not exist or it's opened by another process. Note that this function is similar to the @@ -567,7 +567,7 @@ behavior as the standard C (stdio.h) `int remove(const char *path)` function. Creating a shared memory segment and mapping it can be a bit tedious when several processes are involved. When processes are related via `fork()` operating system -call in UNIX sytems a simpler method is available using anonymous shared memory. +call in UNIX systems a simpler method is available using anonymous shared memory. This feature has been implemented in UNIX systems mapping the device `\dev\zero` or just using the `MAP_ANONYMOUS` in a POSIX conformant `mmap` system call. @@ -576,7 +576,7 @@ This feature is wrapped in [*Boost.Interprocess] using the `anonymous_shared_mem function, which returns a `mapped_region` object holding an anonymous shared memory segment that can be shared by related processes. -Here's is an example: +Here is an example: [import ../example/doc_anonymous_shared_memory.cpp] [doc_anonymous_shared_memory] @@ -615,7 +615,7 @@ Take in care that when the last process attached to a shared memory is destroyed shared memory. Native windows shared memory has also another limitation: a process can open and map the whole shared memory created by another process but it can't know which is the size of that memory. This limitation is imposed by the Windows API so -the user must somehow trasmit the size of the segment to processes opening the +the user must somehow transmit the size of the segment to processes opening the segment. Let's repeat the same example presented for the portable shared memory object: @@ -738,7 +738,7 @@ regarding this class see the After creating a file mapping, a process just has to map the shared memory in the process' address space. The user can map the whole shared memory or just part of it. -The mapping process is done using the the `mapped_region` class. as we have said before +The mapping process is done using the `mapped_region` class. as we have said before The class represents a memory region that has been mapped from a shared memory or from other devices that have also mapping capabilities: @@ -770,7 +770,7 @@ the mapped region covers from the offset until the end of the file. If several processes map the same file, and a process modifies a memory range from a mapped region that is also mapped by other process, the changes are inmedially visible to other processes. However, the file contents on disk are -not updated immediately, since that would hurt performance (writting to disk +not updated immediately, since that would hurt performance (writing to disk is several times slower than writing to memory). If the user wants to make sure that file's contents have been updated, it can flush a range from the view to disk. When the function returns, the data should have been written to disk: @@ -799,7 +799,7 @@ For more details regarding `mapped_region` see the Let's reproduce the same example described in the shared memory section, using memory mapped files. A server process creates a shared -memory segment, maps it and initializes all the bytes the a value. After that, +memory segment, maps it and initializes all the bytes to a value. After that, a client process opens the shared memory, maps it, and checks that the data is correctly initialized. This is the server process: @@ -892,7 +892,7 @@ to a multiple of a value called [*page size]. This is due to the fact that the If fixed mapping address is used, ['offset] and ['address] parameters should be multiples of that value. -This value is, tipically, 4KB or 8KB for 32 bit operating systems. +This value is, typically, 4KB or 8KB for 32 bit operating systems. [c++] @@ -929,7 +929,7 @@ more resources than necessary. If the user specifies the following 1 byte mappin The operating system will reserve a whole page that will not be reused by any other mapping so we are going to waste [*(page size - 1)] bytes. If we want -to use effiently operating system resources, we should create regions whose size +to use efficiently operating system resources, we should create regions whose size is a multiple of [*page size] bytes. If the user specifies the following two mapped regions for a file with which has `2*page_size` bytes: @@ -967,7 +967,7 @@ page size. The mapping with the minimum resource usage would be to map whole pag , page_size //Map the rest ); -How can we obtain the [*page size]? The `mapped_region` class has an static +How can we obtain the [*page size]? The `mapped_region` class has a static function that returns that value: [c++] @@ -997,7 +997,7 @@ When placing objects in a mapped region and mapping that region in different address in every process, raw pointers are a problem since they are only valid for the process that placed them there. To solve this, [*Boost.Interprocess] offers -an special smart pointer that can be used instead of a raw pointer. +a special smart pointer that can be used instead of a raw pointer. So user classes containing raw pointers (or Boost smart pointers, that internally own a raw pointer) can't be safely placed in a process shared mapped region. These pointers must be replaced with offset pointers, and @@ -1007,7 +1007,7 @@ if you want to use these shared objects from different processes. Of course, a pointer placed in a mapped region shared between processes should only point to an object of that mapped region. Otherwise, the pointer would point to an address that it's only valid one process and other -processes may crash when accesing to that address. +processes may crash when accessing to that address. [endsect] @@ -1040,7 +1040,7 @@ and they will crash. This problem is very difficult to solve, since each process needs a different virtual table pointer and the object that contains that pointer -is shared accross many processes. Even if we map the mapped region in +is shared across many processes. Even if we map the mapped region in the same address in every process, the virtual table can be in a different address in every process. To enable virtual functions for objects shared between processes, deep compiler changes are needed and virtual @@ -1099,7 +1099,7 @@ processes the memory segment can be mapped in a different address in each proces //This address can be different in each process void *addr = region.get_address(); -This difficults the creation of complex objects in mapped regions: a C++ +This makes the creation of complex objects in mapped regions difficult: a C++ class instance placed in a mapped region might have a pointer pointing to another object also placed in the mapped region. Since the pointer stores an absolute address, that address is only valid for the process that placed @@ -1107,9 +1107,9 @@ the object there unless all processes map the mapped region in the same address. To be able to simulate pointers in mapped regions, users must use [*offsets] -(distance between objets) instead of absolute addresses. The offset between +(distance between objects) instead of absolute addresses. The offset between two objects in a mapped region is the same for any process that maps the -mapped region, even if that region is placed in different base addreses. +mapped region, even if that region is placed in different base addresses. To facilitate the use of offsets, [*Boost.Interprocess] offers [classref boost::interprocess::offset_ptr offset_ptr]. @@ -1119,7 +1119,7 @@ needed to offer a pointer-like interface. The class interface is inspired in Boost Smart Pointers and this smart pointer stores the offset (distance in bytes) between the pointee's address and it's own `this` pointer. -Imagine an structure in a common +Imagine a structure in a common 32 bit processor: [c++] @@ -1209,7 +1209,7 @@ mapped files or shared memory objects is not very useful if the access to that memory can't be effectively synchronized. This is the same problem that happens with thread-synchronization mechanisms, where heap memory and global variables are shared between threads, but the access to these resources needs to be synchronized -tipically through mutex and condition variables. [*Boost.Threads] implements these +typically through mutex and condition variables. [*Boost.Threads] implements these synchronization utilities between threads inside the same process. [*Boost.Interprocess] implements similar mechanisms to synchronize threads from different processes. @@ -1223,7 +1223,7 @@ implements similar mechanisms to synchronize threads from different processes. a file with using a `fstream` with the name ['filename] and another process opens that file using another `fstream` with the same ['filename] argument. [*Each process uses a different object to access to the resource, but both processes - are using the the same underlying resource]. + are using the same underlying resource]. * [*Anonymous utilities]: Since these utilities have no name, two processes must share [*the same object] through shared memory or memory mapped files. This is @@ -1245,8 +1245,8 @@ Each type has it's own advantages and disadvantages: synchronization utilities. The main interface difference between named and anonymous utilities are the constructors. -Usually anonymous utilities have only one contructor, whereas the named utilities have -several constructors whose first argument is an special type that requests creation, +Usually anonymous utilities have only one constructor, whereas the named utilities have +several constructors whose first argument is a special type that requests creation, opening or opening or creation of the underlying resource: [c++] @@ -1403,7 +1403,7 @@ Boost.Interprocess offers the following mutex types: It's very important to unlock a mutex after the process has read or written the data. This can be difficult when dealing with exceptions, so usually mutexes are used with a scoped lock, a class that can guarantee that a mutex will always be unlocked -even when an exception occurs. To use an scoped lock just include: +even when an exception occurs. To use a scoped lock just include: [c++] @@ -1476,7 +1476,7 @@ will write a flag when ends writing the traces [doc_anonymous_mutex_shared_data] This is the process main process. Creates the shared memory, constructs -the the cyclic buffer and start writing traces: +the cyclic buffer and start writing traces: [import ../example/doc_anonymous_mutexA.cpp] [doc_anonymous_mutexA] @@ -1516,11 +1516,11 @@ In the previous example, a mutex is used to ['lock] but we can't use it to can do two things: * [*wait]: The thread is blocked until some other thread notifies that it can - continue because the condition that lead to waiting has dissapeared. + continue because the condition that lead to waiting has disapeared. * [*notify]: The thread sends a signal to one blocked thread or to all blocked threads to tell them that they the condition that provoked their wait has - dissapeared. + disapeared. Waiting in a condition variable is always associated with a mutex. The mutex must be locked prior to waiting on the condition. When waiting @@ -1649,7 +1649,7 @@ synchronization objects with the synchronized data: [section:semaphores_anonymous_example Anonymous semaphore example] -We will implement a integer array in shared memory that will be used to trasfer data +We will implement an integer array in shared memory that will be used to transfer data from one process to another process. The first process will write some integers to the array and the process will block if the array is full. @@ -1662,7 +1662,7 @@ This is the shared integer array (doc_anonymous_semaphore_shared_data.hpp): [doc_anonymous_semaphore_shared_data] This is the process main process. Creates the shared memory, places there -the interger array and starts integers one by one, blocking if the array +the integer array and starts integers one by one, blocking if the array is full: [import ../example/doc_anonymous_semaphoreA.cpp] @@ -1686,7 +1686,7 @@ efficient than a mutex/condition combination. [section:upgradable_whats_a_mutex What's An Upgradable Mutex?] -An upgradable mutex is an special mutex that offers more locking possibilities than +An upgradable mutex is a special mutex that offers more locking possibilities than a normal mutex. Sometimes, we can distinguish between [*reading] the data and [*modifying] the data. If just some threads need to modify the data, and a plain mutex is used to protect the data from concurrent access, concurrency is pretty limited: @@ -1937,7 +1937,7 @@ ownership. This operation is non-blocking. [*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 releas it. +ownership. This operation will block until all threads with sharable ownership release it. [*Throws:] An exception derived from *interprocess_exception* on error.[blurb ['[*bool try_unlock_upgradable_and_lock()]]] @@ -2176,9 +2176,9 @@ This is implemented by upgradable mutex operations like `unlock_and_lock_sharabl These operations can be managed more effectively using [*lock transfer operations]. A lock transfer operations explicitly indicates that a mutex owned by a lock is -trasferred to another lock executing atomic unlocking plus locking operations. +transferred to another lock executing atomic unlocking plus locking operations. -[section:lock_trasfer_simple_transfer Simple Lock Transfer] +[section:lock_trnasfer_simple_transfer Simple Lock Transfer] Imagine that a thread modifies some data in the beginning but after that, it has to just read it in a long time. The code can acquire the exclusive lock, modify the data @@ -2239,19 +2239,19 @@ We can use [*lock transfer] to simplify all this management: //Read data - //The lock is automatically unlocked calling the appropiate unlock + //The lock is automatically unlocked calling the appropriate unlock //function even in the presence of exceptions. //If the mutex was not locked, no function is called. As we can see, even if an exception is thrown at any moment, the mutex -will be automatically unlocked calling the appropiate `unlock()` or +will be automatically unlocked calling the appropriate `unlock()` or `unlock_sharable()` method. [endsect] -[section:lock_trasfer_summary Lock Transfer Summary] +[section:lock_transfer_summary Lock Transfer Summary] -There are many lock trasfer operations that we can classify according to +There are many lock transfer operations that we can classify according to the operations presented in the upgradable mutex operations: * [*Guaranteed to succeed and non-blocking:] Any transition from a more @@ -2306,7 +2306,7 @@ is permitted: [section:lock_transfer_summary_upgradable Transfers To Upgradable Lock] -A transfer to an `upgradable_lock` is guaranteed to succeed only from an `scoped_lock` +A transfer to an `upgradable_lock` is guaranteed to succeed only from a `scoped_lock` since scoped locking is a more restrictive locking than an upgradable locking. This operation is also non-blocking. @@ -2352,7 +2352,7 @@ These operations are also non-blocking: [endsect] -[section:lock_trasfer_not_locked Transferring Unlocked Locks] +[section:lock_transfer_not_locked Transferring Unlocked Locks] In the previous examples, the mutex used in the transfer operation was previously locked: @@ -2373,7 +2373,7 @@ unlocking, a try, timed or a `defer_lock` constructor: [c++] - //These operations can left the mutex unlocked! + //These operations can leave the mutex unlocked! { //Try might fail @@ -2400,7 +2400,7 @@ unlocking, a try, timed or a `defer_lock` constructor: If the source mutex was not locked: -* The target lock does not executes the atomic `unlock_xxx_and_lock_xxx` operation. +* The target lock does not execute the atomic `unlock_xxx_and_lock_xxx` operation. * The target lock is also unlocked. * The source lock is released() and the ownership of the mutex is transferred to the target. @@ -2418,7 +2418,7 @@ If the source mutex was not locked: [endsect] -[section:lock_trasfer_failure Transfer Failures] +[section:lock_transfer_failure Transfer Failures] When executing a lock transfer, the operation can fail: @@ -2554,7 +2554,7 @@ it waits until it can obtain the ownership. [*Effects:] The calling thread tries to acquire exclusive ownership of the file lock without waiting. If no other thread has exclusive or sharable ownership of -the file lock this succeeds. +the file lock, this succeeds. [*Returns:] If it can acquire exclusive ownership immediately returns true. If it has to wait, returns false. @@ -2595,7 +2595,7 @@ waits until it can obtain the ownership. [*Effects:] The calling thread tries to acquire sharable ownership of the file lock without waiting. If no other thread has has exclusive ownership of -the file lock this succeeds. +the file lock, this succeeds. [*Returns:] If it can acquire sharable ownership immediately returns true. If it has to wait, returns false. @@ -2851,7 +2851,7 @@ The message queue is explicitly removed calling the static `remove` function: using boost::interprocess; message_queue::remove("message_queue"); -The funtion can fail if the message queue is still being used by any process. +The function can fail if the message queue is still being used by any process. [endsect] @@ -2897,7 +2897,7 @@ However, managing those memory segments is not not easy for non-trivial tasks. A mapped region is a fixed-length memory buffer and creating and destroying objects of any type dynamically, requires a lot of work, since it would require programming a memory management algorithm to allocate portions of that segment. -Many times, we also want to associate a names to objects created in shared memory, so +Many times, we also want to associate names to objects created in shared memory, so all the processes can find the object using the name. [*Boost.Interprocess] offers 4 managed memory segment classes: @@ -2958,7 +2958,7 @@ These classes can be customized with the following template parameters: * The Pointer type (`MemoryAlgorithm::void_pointer`) to be used by the memory allocation algorithm or additional helper structures - (like a map to mantain object/name associations). All STL compatible + (like a map to maintain object/name associations). All STL compatible allocators and containers to be used with this managed memory segment will use this pointer type. The pointer type will define if the managed memory segment can be mapped between @@ -3016,8 +3016,8 @@ specializations: ,/*Default index type*/> wmanaged_shared_memory; -`managed_shared_memory` allocates objects in shared memory asociated with a c-string and -`wmanaged_shared_memory` allocates objects in shared memory asociated with a wchar_t null +`managed_shared_memory` allocates objects in shared memory associated with a c-string and +`wmanaged_shared_memory` allocates objects in shared memory associated with a wchar_t null terminated string. Both define the pointer type as `offset_ptr` so they can be used to map the shared memory at different base addresses in different processes. @@ -3108,7 +3108,7 @@ To use a managed shared memory, you must include the following header: //!! If anything fails, throws interprocess_exception // managed_shared_memory segment (open_or_create, "MySharedMemory", //Shared memory object name 65536); //Shared memory object size in bytes -When the a `managed_shared_memory` object is destroyed, the shared memory +When the `managed_shared_memory` object is destroyed, the shared memory object is automatically unmapped, and all the resources are freed. To remove the shared memory object from the system you must use the `shared_memory_object::remove` function. Shared memory object removing might fail if any @@ -3184,8 +3184,8 @@ specializations: flat_map_index > wmanaged_mapped_file; -`managed_mapped_file` allocates objects in a memory mapped files asociated with a c-string -and `wmanaged_mapped_file` allocates objects in a memory mapped file asociated with a wchar_t null +`managed_mapped_file` allocates objects in a memory mapped files associated with a c-string +and `wmanaged_mapped_file` allocates objects in a memory mapped file associated with a wchar_t null terminated string. Both define the pointer type as `offset_ptr` so they can be used to map the file at different base addresses in different processes. @@ -3244,7 +3244,7 @@ To use a managed mapped file, you must include the following header: //!! If anything fails, throws interprocess_exception // managed_mapped_file mfile (open_or_create, "MyMappedFile", //Mapped file name 65536); //Mapped file size -When the a `managed_mapped_file` object is destroyed, the file is +When the `managed_mapped_file` object is destroyed, the file is automatically unmapped, and all the resources are freed. To remove the file from the filesystem you can use standard C `std::remove` or [*Boost.Filesystem]'s `remove()` functions. File removing might fail @@ -3548,7 +3548,7 @@ object. The programmer can obtain the following information: * Length of the object: Returns the number of elements of the object (1 if it's a single value, >=1 if it's an array). -* The type of construction: Whether the object was construct using a named, +* The type of construction: Whether the object was constructed using a named, unique or anonymous construction. Here is an example showing this functionality: @@ -3676,7 +3676,7 @@ reallocations, if the index is a hash structure it can preallocate the bucket ar The following functions reserve memory to make the subsequent allocation of named or unique objects more efficient. These functions are only useful for pseudo-intrusive or non-node indexes (like `flat_map_index`, -`iunordered_set_index`). These functions has no effect with the +`iunordered_set_index`). These functions have no effect with the default index (`iset_index`) or other indexes (`map_index`): [c++] @@ -3735,7 +3735,7 @@ creation/erasure/reserve operation: Sometimes it's interesting to be able to allocate aligned fragments of memory because of some hardware or software restrictions. Sometimes, having -aligned memory is an feature that can be used to improve several +aligned memory is a feature that can be used to improve several memory algorithms. This allocation is similar to the previously shown raw memory allocation but @@ -3758,7 +3758,7 @@ of memory maximizing both the size of the request [*and] the possibilities of future aligned allocations. This information is stored in the PayloadPerAllocation constant of managed memory segments. -Here's is an small example showing how aligned allocation is used: +Here is a small example showing how aligned allocation is used: [import ../example/doc_managed_aligned_allocation.cpp] [doc_managed_aligned_allocation] @@ -3812,9 +3812,9 @@ pointers to memory the user can overwrite. A `multiallocation_iterator`: referencing the first byte user can overwrite in the memory buffer. * The iterator category depends on the memory allocation algorithm, - but it's a least a forward iterator. + but it's at least a forward iterator. -Here's an small example showing all this functionality: +Here is a small example showing all this functionality: [import ../example/doc_managed_multiple_allocation.cpp] [doc_managed_multiple_allocation] @@ -3867,7 +3867,7 @@ allocated buffer, because many times, due to alignment issues the allocated buffer a bit bigger than the requested size. Thus, the programmer can maximize the memory use using `allocation_command`. -Here's the declaration of the function: +Here is the declaration of the function: [c++] @@ -3992,12 +3992,12 @@ contain any of these values: `expand_fwd`, `expand_bwd`. performing backwards expansion, if you have already constructed objects in the old buffer, make sure to specify correctly the type.] -Here is an small example that shows the use of `allocation_command`: +Here is a small example that shows the use of `allocation_command`: [import ../example/doc_managed_allocation_command.cpp] [doc_managed_allocation_command] -`allocation_commmand` is a very powerful function that can lead to important +`allocation_command` is a very powerful function that can lead to important performance gains. It's specially useful when programming vector-like data structures where the programmer can minimize both the number of allocation requests and the memory waste. @@ -4016,7 +4016,7 @@ share an initial managed segment and make private changes to it. If many process open a managed segment in copy on write mode and not modified pages from the managed segment will be shared between all those processes, with considerable memory savings. -Opening managed shared memory and mapped files with [*open_read_only] maps the the +Opening managed shared memory and mapped files with [*open_read_only] maps the underlying device in memory with [*read-only] attributes. This means that any attempt to write that memory, either creating objects or locking any mutex might result in an page-fault error (and thus, program termination) from the OS. Read-only mode opens @@ -4034,7 +4034,7 @@ a managed memory segment without modifying it. Read-only mode operations are lim * Additionally, the `find<>` member function avoids using internal locks and can be used to look for named and unique objects. -Here's an example that shows the use of these two open modes: +Here is an example that shows the use of these two open modes: [import ../example/doc_managed_copy_on_write.cpp] [doc_managed_copy_on_write] @@ -4047,7 +4047,7 @@ Here's an example that shows the use of these two open modes: [*Boost.Interprocess] offers managed shared memory between processes using `managed_shared_memory` or `managed_mapped_file`. Two processes just map the same -the memory mappable resoure and read from and write to that object. +the memory mappable resource and read from and write to that object. Many times, we don't want to use that shared memory approach and we prefer to send serialized data through network, local socket or message queues. Serialization @@ -4093,7 +4093,7 @@ provided buffers that allow the same functionality as shared memory classes: [c++] //Named object creation managed memory segment - //All objects are constructed in a a user provided buffer + //All objects are constructed in a user provided buffer template < class CharType, class MemoryAlgorithm, @@ -4102,7 +4102,7 @@ provided buffers that allow the same functionality as shared memory classes: class basic_managed_external_buffer; //Named object creation managed memory segment - //All objects are constructed in a a user provided buffer + //All objects are constructed in a user provided buffer // Names are c-strings, // Default memory management algorithm // (rbtree_best_fit with no mutexes and relative pointers) @@ -4114,7 +4114,7 @@ provided buffers that allow the same functionality as shared memory classes: > managed_external_buffer; //Named object creation managed memory segment - //All objects are constructed in a a user provided buffer + //All objects are constructed in a user provided buffer // Names are wide-strings, // Default memory management algorithm // (rbtree_best_fit with no mutexes and relative pointers) @@ -4269,7 +4269,7 @@ memory mapped in different base addresses in several processes. [section:allocator_properties Properties of [*Boost.Interprocess] allocators] -Container allocators are normally default-contructible because the are stateless. +Container allocators are normally default-constructible because the are stateless. `std::allocator` and [*Boost.Pool's] `boost::pool_allocator`/`boost::fast_pool_allocator` are examples of default-constructible allocators. @@ -4403,7 +4403,7 @@ a fast and space-friendly allocator, as explained in the Segregate storage node allocators allocate large memory chunks from a general purpose memory -allocator and divide that chunk into several nodes. No bookeeping information +allocator and divide that chunk into several nodes. No bookkeeping information is stored in the nodes to achieve minimal memory waste: free nodes are linked using a pointer constructed in the memory of the node. @@ -4642,7 +4642,7 @@ of objects but they end storing a few of them: the node pool will be full of nod that won't be reused wasting memory from the segment. Adaptive pool based allocators trade some space (the overhead can be as low as 1%) -and performance (aceptable for many applications) with the ability to return free chunks +and performance (acceptable for many applications) with the ability to return free chunks of nodes to the memory segment, so that they can be used by any other container or managed object construction. To know the details of the implementation of of "adaptive pools" see the @@ -4777,7 +4777,7 @@ An example using [classref boost::interprocess::private_adaptive_pool private_ad [section:cached_adaptive_pool cached_adaptive_pool: Avoiding synchronization overhead] Adaptive pools have also a cached version. In this allocator the allocator caches -some nodes to avoid the synchronization and bookeeping overhead of the shared +some nodes to avoid the synchronization and bookkeeping overhead of the shared adaptive pool. [classref boost::interprocess::cached_adaptive_pool cached_adaptive_pool] allocates nodes from the common adaptive pool but caches some of them privately so that following @@ -5065,7 +5065,7 @@ smart pointers. Hopefully several Boost containers are compatible with [*Interpr [section:unordered Boost unordered containers] [*Boost.Unordered] containers are compatible with Interprocess, so programmers can store -hash containers in shared memory and memory mapped files. Here's an small example storing +hash containers in shared memory and memory mapped files. Here is a small example storing `unordered_map` in shared memory: [import ../example/doc_unordered_map.cpp] @@ -5082,7 +5082,7 @@ and those strings need to be placed in shared memory. Shared memory strings requ an allocator in their constructors so this usually makes object insertion a bit more complicated. -Here's is an example that shows how to put a multi index container in shared memory: +Here is an example that shows how to put a multi index container in shared memory: [import ../example/doc_multi_index.cpp] [doc_multi_index] @@ -5433,7 +5433,7 @@ something that is not possible if you want to place your data in shared memory. The virtual function limitation makes even impossible to achieve the same level of functionality of Boost and TR1 with [*Boost.Interprocess] smart pointers. -Interprocess ownership smart pointers are mainly "smart pointers contaning smart pointers", +Interprocess ownership smart pointers are mainly "smart pointers containing smart pointers", so we can specify the pointer type they contain. [section:intrusive_ptr Intrusive pointer] @@ -5463,7 +5463,7 @@ the pointer type to be stored in the intrusive_ptr: class intrusive_ptr; So `boost::interprocess::intrusive_ptr` is equivalent to -`boost::instrusive_ptr`. But if we want to place the intrusive_ptr in +`boost::intrusive_ptr`. But if we want to place the intrusive_ptr in shared memory we must specify a relative pointer type like `boost::interprocess::intrusive_ptr >` @@ -5511,7 +5511,7 @@ reference-counted objects in managed shared memory or mapped files. Unlike [@http://www.boost.org/libs/smart_ptr/shared_ptr.htm boost::shared_ptr], due to limitations of mapped segments [classref boost::interprocess::shared_ptr] -can not take advantage of virtual functions to maintain the same shared pointer +cannot take advantage of virtual functions to maintain the same shared pointer type while providing user-defined allocators and deleters. The allocator and the deleter are template parameters of the shared pointer. @@ -5523,7 +5523,7 @@ when constructing a non-empty instance of [classref boost::interprocess::shared_ptr shared_ptr], just like [*Boost.Interprocess] containers need to pass allocators in their constructors. -Here's is the declaration of [classref boost::interprocess::shared_ptr shared_ptr]: +Here is the declaration of [classref boost::interprocess::shared_ptr shared_ptr]: [c++] @@ -5567,7 +5567,7 @@ to easily construct a shared pointer from a type allocated in a managed segment with an allocator that will allocate the reference count also in the managed segment and a deleter that will erase the object from the segment. -These utilities will use the a [*Boost.Interprocess] allocator +These utilities will use a [*Boost.Interprocess] allocator ([classref boost::interprocess::allocator]) and deleter ([classref boost::interprocess::deleter]) to do their job. The definition of the previous shared pointer @@ -5766,7 +5766,7 @@ section. As memory algorithm examples, you can see the implementations The *segment manager*, is an object also placed in the first bytes of the managed memory segment (shared memory, memory mapped file), that offers more -sofisticated services built above the [*memory algorithm]. How can [*both] the +sophisticated services built above the [*memory algorithm]. How can [*both] the segment manager and memory algorithm be placed in the beginning of the segment? That's because the segment manager [*owns] the memory algorithm: The truth is that the memory algorithm is [*embedded] in the segment manager: @@ -5797,7 +5797,7 @@ implement "unique instance" allocations. * The first index is a map with a pointer to a c-string (the name of the named object) as a key and a structure with information of the dynamically allocated object - (the most importants being the address and the size of the object). + (the most important being the address and the size of the object). * The second index is used to implement "unique instances" and is basically the same as the first index, @@ -5906,7 +5906,7 @@ etc... Segregated storage pools are simple and follow the classic segregated storage algorithm. -* The pool allocates chuncks of memory using the segment manager's raw memory +* The pool allocates chunks of memory using the segment manager's raw memory allocation functions. * The chunk contains a pointer to form a singly linked list of chunks. The pool will contain a pointer to the first chunk. @@ -5932,7 +5932,7 @@ private_node_pool and shared_node_pool] classes. Adaptive pools are a variation of segregated lists but they have a more complicated approach: -* Instead of using raw allocation, the pool allocates [*aligned] chuncks of memory +* Instead of using raw allocation, the pool allocates [*aligned] chunks of memory using the segment manager. This is an [*essential] feature since a node can reach its chunk information applying a simple mask to its address. @@ -5958,7 +5958,7 @@ approach: * Deallocation returns the node to the free node list of its chunk and updates the "active" pool accordingly. -* If the number of totally free chunks exceds the limit, chunks are returned +* If the number of totally free chunks exceeds the limit, chunks are returned to the segment manager. * When the pool is destroyed, the list of chunks is traversed and memory is returned @@ -6037,7 +6037,7 @@ these alternatives: [section:performance_named_allocation Performance of named allocations] -[*Boost.Interprocess] allows the same paralelism as two threads writing to a common +[*Boost.Interprocess] allows the same parallelism as two threads writing to a common structure, except when the user creates/searches named/unique objects. The steps when creating a named object are these: @@ -6101,7 +6101,7 @@ The steps when destroying a named object using the pointer of the object If you see that the performance is not good enough you have these alternatives: -* Maybe the problem is that the lock time is too big and it hurts paralelism. +* Maybe the problem is that the lock time is too big and it hurts parallelism. Try to reduce the number of named objects in the global index and if your application serves several clients try to build a new managed memory segment for each one instead of using a common one. @@ -6146,12 +6146,12 @@ This is the interface to be implemented: //!The pointer type to be used by the rest of Interprocess framework typedef implementation_defined void_pointer; - //!Constructor. "size" is the total size of the maanged memory segment, + //!Constructor. "size" is the total size of the managed memory segment, //!"extra_hdr_bytes" indicates the extra bytes after the sizeof(my_algorithm) //!that the allocator should not use at all. my_algorithm (std::size_t size, std::size_t extra_hdr_bytes); - //!Obtains the minimium size needed by the algorithm + //!Obtains the minimum size needed by the algorithm static std::size_t get_min_size (std::size_t extra_hdr_bytes); //!Allocates bytes, returns 0 if there is not more memory @@ -6191,7 +6191,7 @@ But if we define: then all [*Boost.Interprocess] framework will use relative pointers. -The `mutex_family` is an structure containing typedefs +The `mutex_family` is a structure containing typedefs for different interprocess_mutex types to be used in the [*Boost.Interprocess] framework. For example the defined @@ -6236,7 +6236,7 @@ that boost::interprocess::rbtree_best_fit class offers: This function should be executed with the synchronization capabilities offered by `typename mutex_family::mutex_type` interprocess_mutex. That means, that if we define `typedef mutex_family mutex_family;` then this function should offer - the same synchronization as if it was surrounded by a interprocess_mutex lock/unlock. + the same synchronization as if it was surrounded by an interprocess_mutex lock/unlock. Normally, this is implemented using a member of type `mutex_family::mutex_type`, but it could be done using atomic instructions or lock free algorithms. @@ -6372,7 +6372,7 @@ following class: [c++] - //!The key of the the named allocation information index. Stores a to + //!The key of the named allocation information index. Stores a to //!a null string and the length of the string to speed up sorting template<...> struct index_key @@ -6448,7 +6448,7 @@ Interprocess also defines other index types: * [*boost::map_index] uses *boost::interprocess::map* as index type. * [*boost::null_index] that uses an dummy index type if the user just needs - anonymous allocations and want's to save some space and class instantations. + anonymous allocations and wants to save some space and class instantations. Defining a new managed memory segment that uses the new index is easy. For example, a new managed shared memory that uses the new index: @@ -6541,6 +6541,20 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_37_00 Boost 1.37 Release] + +* Containers can be used now in recursive types. +* Added `BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION` macro option to force the use + of generic emulation code for process-shared synchronization primitives instead of + native POSIX functions. +* Added placement insertion members to containers +* `boost::posix_time::pos_inf` value is now handled portably for timed functions. +* Update some function parameters from `iterator` to `const_iterator` in containers + to keep up with the draft of the next standard. +* Documentation fixes. + +[endsect] + [section:release_notes_boost_1_36_00 Boost 1.36 Release] * Added anonymous shared memory for UNIX systems. @@ -6559,7 +6573,7 @@ warranty. [classref boost::interprocess::shared_ptr shared_ptr], [classref boost::interprocess::weak_ptr weak_ptr] and [classref boost::interprocess::unique_ptr unique_ptr]. Added explanations - and examples of these smart pointers in the documenation. + and examples of these smart pointers in the documentation. * Optimized vector: * 1) Now works with raw pointers as much as possible when @@ -6576,7 +6590,7 @@ warranty. that might define virtual functions with the same names as container member functions. That would convert container functions in virtual functions and might disallow some of them if the returned type does not lead to a covariant return. - Allocators are now stored as base clases of internal structs. + Allocators are now stored as base classes of internal structs. * Implemented [classref boost::interprocess::named_mutex named_mutex] and [classref boost::interprocess::named_semaphore named_semaphore] with POSIX @@ -6671,12 +6685,12 @@ warranty. if the element has been moved (which is the case of many movable types). This trick was provided by Howard Hinnant. -* Added security check to avoid interger overflow bug in allocators and +* Added security check to avoid integer overflow bug in allocators and named construction functions. * Added alignment checks to forward and backwards expansion functions. -* Fixed bug in atomic funtions for PPC. +* Fixed bug in atomic functions for PPC. * Fixed race-condition error when creating and opening a managed segment. diff --git a/example/doc_contB.cpp b/example/doc_contB.cpp index 95fa43c..4aad144 100644 --- a/example/doc_contB.cpp +++ b/example/doc_contB.cpp @@ -19,7 +19,7 @@ int main () { using namespace boost::interprocess; try{ - //An special shared memory where we can + //A special shared memory where we can //construct objects associated with a name. //Connect to the already created shared memory segment //and initialize needed resources diff --git a/example/doc_ipc_messageA.cpp b/example/doc_ipc_messageA.cpp index 888135c..3a730f1 100644 --- a/example/doc_ipc_messageA.cpp +++ b/example/doc_ipc_messageA.cpp @@ -16,7 +16,7 @@ int main () { using namespace boost::interprocess; - //An special shared memory from which we are + //A special shared memory from which we are //able to allocate raw memory buffers. //First remove any old shared memory of the same name, create //the shared memory segment and initialize needed resources diff --git a/example/doc_ipc_messageB.cpp b/example/doc_ipc_messageB.cpp index 0984c6c..2c30d1a 100644 --- a/example/doc_ipc_messageB.cpp +++ b/example/doc_ipc_messageB.cpp @@ -17,7 +17,7 @@ int main () using namespace boost::interprocess; try{ - //An special shared memory from which we are + //A special shared memory from which we are //able to allocate raw memory buffers. //Connect to the already created shared memory segment //and initialize needed resources diff --git a/example/doc_managed_aligned_allocation.cpp b/example/doc_managed_aligned_allocation.cpp index 28f284f..2af9266 100644 --- a/example/doc_managed_aligned_allocation.cpp +++ b/example/doc_managed_aligned_allocation.cpp @@ -29,7 +29,7 @@ int main() void *ptr = managed_shm.allocate_aligned(100, Alignment); //Check alignment - assert(((char*)ptr-(char*)0) % Alignment == 0); + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); //Deallocate it managed_shm.deallocate(ptr); @@ -38,7 +38,7 @@ int main() ptr = managed_shm.allocate_aligned(100, Alignment, std::nothrow); //Check alignment - assert(((char*)ptr-(char*)0) % Alignment == 0); + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); //Deallocate it managed_shm.deallocate(ptr); @@ -53,7 +53,7 @@ int main() (3*Alignment - managed_shared_memory::PayloadPerAllocation, Alignment); //Check alignment - assert(((char*)ptr-(char*)0) % Alignment == 0); + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); //Deallocate it managed_shm.deallocate(ptr); diff --git a/example/doc_managed_copy_on_write.cpp b/example/doc_managed_copy_on_write.cpp index 0b8fecc..304be95 100644 --- a/example/doc_managed_copy_on_write.cpp +++ b/example/doc_managed_copy_on_write.cpp @@ -49,7 +49,7 @@ int main() std::fstream file("MyManagedFile2", std::ios_base::out | std::ios_base::binary); if(!file) throw int(0); - file.write((const char *)managed_file_cow.get_address(), managed_file_cow.get_size()); + file.write(static_cast(managed_file_cow.get_address()), managed_file_cow.get_size()); } //Now open the modified file and test changes diff --git a/example/doc_managed_external_buffer.cpp b/example/doc_managed_external_buffer.cpp index 130cd2e..051b430 100644 --- a/example/doc_managed_external_buffer.cpp +++ b/example/doc_managed_external_buffer.cpp @@ -30,7 +30,7 @@ int main() //We optimize resources to create 100 named objects in the static buffer objects_in_static_memory.reserve_named_objects(100); - //Alias a integer node allocator type + //Alias an integer node allocator type //This allocator will allocate memory inside the static buffer typedef allocator allocator_t; diff --git a/example/doc_named_allocA.cpp b/example/doc_named_allocA.cpp index 4f779c9..84eb889 100644 --- a/example/doc_named_allocA.cpp +++ b/example/doc_named_allocA.cpp @@ -19,7 +19,7 @@ int main () typedef std::pair MyType; try{ - //An special shared memory where we can + //A special shared memory where we can //construct objects associated with a name. //First remove any old shared memory of the same name, create //the shared memory segment and initialize needed resources diff --git a/example/doc_named_allocB.cpp b/example/doc_named_allocB.cpp index 4067f19..8b6bb65 100644 --- a/example/doc_named_allocB.cpp +++ b/example/doc_named_allocB.cpp @@ -21,7 +21,7 @@ int main () typedef std::pair MyType; try{ - //An special shared memory where we can + //A special shared memory where we can //construct objects associated with a name. //Connect to the already created shared memory segment //and initialize needed resources diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index b1c5b61..efa7930 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -25,7 +25,7 @@ struct list_node int main () { //Destroy any previous shared memory with the name to be used. - //Create an special shared memory from which we can + //Create a special shared memory from which we can //allocate buffers of raw memory. shared_memory_object::remove("MySharedMemory"); try{ diff --git a/example/doc_shared_memory2.cpp b/example/doc_shared_memory2.cpp index 3fd2da2..c977095 100644 --- a/example/doc_shared_memory2.cpp +++ b/example/doc_shared_memory2.cpp @@ -17,6 +17,7 @@ int main () { using namespace boost::interprocess; + shared_memory_object::remove("shared_memory"); try{ //Open already created shared memory object. shared_memory_object shm (open_only, "shared_memory", read_only); diff --git a/proj/to-do.txt b/proj/to-do.txt new file mode 100644 index 0000000..49ff717 --- /dev/null +++ b/proj/to-do.txt @@ -0,0 +1,54 @@ +-> change rvalue reference signatures in all containers + +-> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ + +-> add contiguous_elements option to burst allocation + +-> Test construct<> with throwing constructors + +-> Implement zero_memory flag for allocation_command + +-> The general allocation funtion can be improved with some fixed size allocation bins. + +-> Adapt error reporting to TR1 system exceptions + +-> Improve exception messages + +-> Movability of containers should depend on the no-throw guarantee of allocators copy constructor + +-> Check self-assignment for vectors + +-> Update writing a new memory allocator explaining new functions (like alignment) + +-> private node allocators could take the number of nodes as a runtime parameter. + +-> Explain how to build intrusive indexes. + +-> Add intrusive index types as available indexes. + +-> Add maximum alignment allocation limit in PageSize bytes. Otherwise, we can't + guarantee alignment for process-shared allocations. + +-> Add default algorithm and index types. The user does not need to know how are + they implemented. + +-> Pass max size check in allocation to node pools + +-> Use in-place expansion capabilities to shrink_to_fit and reserve functions + from iunordered_index. + +-> change unique_ptr to avoid using compressed_pair + +-> Improve unique_ptr test to test move assignment and other goodies like assigment from null + +-> barrier_test fails on MacOS X on PowerPC. + +->use virtual functions to minimize template explosion in managed classes + +->Insertions with InpIt are not tested in containers + +->Run tests with rvalue reference compilers with no variadic insertions + +->find a way to pass security attributes to shared memory + +->Explain in docs that shared memory can't be used between different users in windows diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index 7f00fbe..ed25a07 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -459,13 +459,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_complex_map", "doc_comp ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_construct_test", "named_construct_test.vcproj", "{5183C8CE-F2E1-3620-237A-B765C9896390}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.ActiveCfg = Debug|Win32 {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.Build.0 = Debug|Win32 @@ -927,6 +929,10 @@ Global {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Debug.Build.0 = Debug|Win32 {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Release.ActiveCfg = Release|Win32 {5C19CF83-4FB7-8219-8F6D-3BA9D2715A22}.Release.Build.0 = Release|Win32 + {5183C8CE-F2E1-3620-237A-B765C9896390}.Debug.ActiveCfg = Debug|Win32 + {5183C8CE-F2E1-3620-237A-B765C9896390}.Debug.Build.0 = Debug|Win32 + {5183C8CE-F2E1-3620-237A-B765C9896390}.Release.ActiveCfg = Release|Win32 + {5183C8CE-F2E1-3620-237A-B765C9896390}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 0f79970..4b4a0e4 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -361,6 +361,9 @@ + + @@ -391,12 +394,18 @@ + + + + @@ -415,6 +424,9 @@ + + @@ -430,6 +442,9 @@ + + @@ -445,6 +460,9 @@ + + @@ -526,6 +544,9 @@ + + diff --git a/proj/vc7ide/named_construct_test.vcproj b/proj/vc7ide/named_construct_test.vcproj new file mode 100644 index 0000000..b5f2cbd --- /dev/null +++ b/proj/vc7ide/named_construct_test.vcproj @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/allocator_v1.hpp b/test/allocator_v1.hpp index b46c3c4..d52a039 100644 --- a/test/allocator_v1.hpp +++ b/test/allocator_v1.hpp @@ -110,7 +110,7 @@ class allocator_v1 //!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; return pointer((value_type*)mp_mngr->allocate(count*sizeof(value_type))); } + { (void)hint; return pointer(static_cast(mp_mngr->allocate(count*sizeof(value_type)))); } //!Deallocates memory previously allocated. Never throws void deallocate(const pointer &ptr, size_type) diff --git a/test/cached_node_allocator_test.cpp b/test/cached_node_allocator_test.cpp index c29e639..a70c3e3 100644 --- a/test/cached_node_allocator_test.cpp +++ b/test/cached_node_allocator_test.cpp @@ -21,7 +21,7 @@ using namespace boost::interprocess; -//Alias a integer node allocator type +//Alias an integer node allocator type typedef cached_node_allocator cached_node_allocator_t; diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 483f8da..ceb5044 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -31,14 +32,15 @@ #include #include #include "get_process_id_name.hpp" +#include "emplace_test.hpp" -//***************************************************************// +/////////////////////////////////////////////////////////////////// // // // This example repeats the same operations with std::deque and // // shmem_deque using the node allocator // // and compares the values of both containers // // // -//***************************************************************// +/////////////////////////////////////////////////////////////////// using namespace boost::interprocess; @@ -63,23 +65,64 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) shmdeque->insert(shmdeque->end(), 50, 1); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; { - IntType move_me(1); - stddeque->insert(stddeque->begin()+size/2, 50, 1); - shmdeque->insert(shmdeque->begin()+size/2, 50, detail::move_impl(move_me)); - if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + IntType move_me(1); + stddeque->insert(stddeque->begin()+size/2, 50, 1); + shmdeque->insert(shmdeque->begin()+size/2, 50, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { - IntType move_me(2); - shmdeque->assign(shmdeque->size()/2, detail::move_impl(move_me)); - stddeque->assign(stddeque->size()/2, 2); - if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + IntType move_me(2); + shmdeque->assign(shmdeque->size()/2, detail::move_impl(move_me)); + stddeque->assign(stddeque->size()/2, 2); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } + { + IntType move_me(1); + stddeque->clear(); + shmdeque->clear(); + stddeque->insert(stddeque->begin(), 50, 1); + shmdeque->insert(shmdeque->begin(), 50, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->begin()+20, 50, 1); + shmdeque->insert(shmdeque->begin()+20, 50, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->begin()+20, 20, 1); + shmdeque->insert(shmdeque->begin()+20, 20, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + { + IntType move_me(1); + stddeque->clear(); + shmdeque->clear(); + stddeque->insert(stddeque->end(), 50, 1); + shmdeque->insert(shmdeque->end(), 50, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->end()-20, 50, 1); + shmdeque->insert(shmdeque->end()-20, 50, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + stddeque->insert(stddeque->end()-20, 20, 1); + shmdeque->insert(shmdeque->end()-20, 20, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + } + return true; } +//Test recursive structures +class recursive_deque +{ +public: + int id_; + deque deque_; +}; + template class AllocatorType > bool do_test() { + //Test for recursive types + { + deque recursive_deque_deque; + } //Customize managed_shared_memory class typedef basic_managed_shared_memory insert(shmdeque->end(), detail::move_impl(move_me)); stddeque->insert(stddeque->end(), i); } - if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + shmdeque->clear(); + stddeque->clear(); + + for(i = 0; i < max*100; ++i){ + IntType move_me(i); + shmdeque->push_back(detail::move_impl(move_me)); + stddeque->push_back(i); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + shmdeque->clear(); + stddeque->clear(); + + for(i = 0; i < max*100; ++i){ + IntType move_me(i); + shmdeque->push_front(detail::move_impl(move_me)); + stddeque->push_front(i); + } + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; typename MyShmDeque::iterator it; typename MyShmDeque::const_iterator cit = it; shmdeque->erase(shmdeque->begin()++); stddeque->erase(stddeque->begin()++); - if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; shmdeque->erase(shmdeque->begin()); stddeque->erase(stddeque->begin()); - if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; { //Initialize values @@ -185,21 +248,40 @@ bool do_test() shmdeque->erase(shmdeque->begin()); stddeque->erase(stddeque->begin()); - if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; for(i = 0; i < max; ++i){ IntType move_me(i); shmdeque->insert(shmdeque->begin(), detail::move_impl(move_me)); stddeque->insert(stddeque->begin(), i); } - if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; + + //Test insertion from list + { + std::list l(50, int(1)); + shmdeque->insert(shmdeque->begin(), l.begin(), l.end()); + stddeque->insert(stddeque->begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + shmdeque->assign(l.begin(), l.end()); + stddeque->assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + } + + shmdeque->resize(100); + stddeque->resize(100); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; + + shmdeque->resize(200); + stddeque->resize(200); + if(!test::CheckEqualContainers(shmdeque, stddeque)) return 1; segment.template destroy("MyShmDeque"); delete stddeque; segment.shrink_to_fit_indexes(); if(!segment.all_memory_deallocated()) - return 1; + return false; } catch(std::exception &ex){ std::cout << ex.what() << std::endl; @@ -227,6 +309,12 @@ int main () if(!do_test()) return 1; + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); + + if(!boost::interprocess::test::test_emplace + < deque, Options>()) + return 1; + return 0; } diff --git a/test/emplace_test.hpp b/test/emplace_test.hpp new file mode 100644 index 0000000..103d8da --- /dev/null +++ b/test/emplace_test.hpp @@ -0,0 +1,640 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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_TEST_EMPLACE_TEST_HPP +#define BOOST_INTERPROCESS_TEST_EMPLACE_TEST_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +namespace interprocess{ +namespace test{ + +class EmplaceInt +{ + private: + EmplaceInt (const EmplaceInt &o); + EmplaceInt& operator=(const EmplaceInt &o); + + public: + EmplaceInt(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0) + : a_(a), b_(b), c_(c), d_(d), e_(e) + {} + + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + EmplaceInt(EmplaceInt &&o) + : a_(o.a_), b_(o.b_), c_(o.c_), d_(o.d_), e_(o.e_) + #else + EmplaceInt(detail::moved_object mo) + : a_(mo.get().a_), b_(mo.get().b_), c_(mo.get().c_), d_(mo.get().d_), e_(mo.get().e_) + #endif + {} + + #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE + EmplaceInt& operator=(EmplaceInt &&o) + { + #else + EmplaceInt& operator=(detail::moved_object mo) + { + EmplaceInt &o = mo.get(); + #endif + this->a_ = o.a_; + this->b_ = o.b_; + this->c_ = o.c_; + this->d_ = o.d_; + this->e_ = o.e_; + return *this; + } + + friend bool operator==(const EmplaceInt &l, const EmplaceInt &r) + { + return l.a_ == r.a_ && + l.b_ == r.b_ && + l.c_ == r.c_ && + l.d_ == r.d_ && + l.e_ == r.e_; + } + + friend bool operator<(const EmplaceInt &l, const EmplaceInt &r) + { return l.sum() < r.sum(); } + + friend bool operator>(const EmplaceInt &l, const EmplaceInt &r) + { return l.sum() > r.sum(); } + + friend bool operator!=(const EmplaceInt &l, const EmplaceInt &r) + { return !(l == r); } + + friend std::ostream &operator <<(std::ostream &os, const EmplaceInt &v) + { + os << "EmplaceInt: " << v.a_ << ' ' << v.b_ << ' ' << v.c_ << ' ' << v.d_ << ' ' << v.e_; + return os; + } + + //private: + int sum() const + { return this->a_ + this->b_ + this->c_ + this->d_ + this->e_; } + + int a_, b_, c_, d_, e_; + int padding[6]; +}; + + +} //namespace test { + +template<> +struct is_movable +{ + static const bool value = true; +}; + +namespace test { + +enum EmplaceOptions{ + EMPLACE_BACK = 1 << 0, + EMPLACE_FRONT = 1 << 1, + EMPLACE_BEFORE = 1 << 2, + EMPLACE_AFTER = 1 << 3, + EMPLACE_ASSOC = 1 << 4, + EMPLACE_HINT = 1 << 5, + EMPLACE_ASSOC_PAIR = 1 << 6, + EMPLACE_HINT_PAIR = 1 << 7 +}; + +template +bool test_expected_container(const Container &ec, const EmplaceInt *Expected, unsigned int only_first_n) +{ + typedef typename Container::const_iterator const_iterator; + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + if(only_first_n > ec.size()){ + return false; + } + for(; itb != ite && only_first_n--; ++itb, ++cur){ + const EmplaceInt & cr = *itb; + if(cr != Expected[cur]){ + return false; + } + } + return true; +} + +template +bool test_expected_container(const Container &ec, const std::pair *Expected, unsigned int only_first_n) +{ + typedef typename Container::const_iterator const_iterator; + const_iterator itb(ec.begin()), ite(ec.end()); + unsigned int cur = 0; + if(only_first_n > ec.size()){ + return false; + } + for(; itb != ite && only_first_n--; ++itb, ++cur){ + if(itb->first != Expected[cur].first){ + std::cout << "Error in first: " << itb->first << ' ' << Expected[cur].first << std::endl; + return false; + + } + else if(itb->second != Expected[cur].second){ + std::cout << "Error in second: " << itb->second << ' ' << Expected[cur].second << std::endl; + return false; + } + } + return true; +} + +static EmplaceInt expected [10]; + +typedef std::pair EmplaceIntPair; +static boost::aligned_storage::type pair_storage; + +static EmplaceIntPair* initialize_emplace_int_pair() +{ + EmplaceIntPair* ret = reinterpret_cast(&pair_storage); + for(unsigned int i = 0; i != 10; ++i){ + new(&ret->first)EmplaceInt(); + new(&ret->second)EmplaceInt(); + } + return ret; +} + +static EmplaceIntPair * expected_pair = initialize_emplace_int_pair(); + + +template +bool test_emplace_back(detail::true_) +{ + std::cout << "Starting test_emplace_back." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + Container c; + c.emplace_back(); + if(!test_expected_container(c, &expected[0], 1)) + return false; + c.emplace_back(1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace_back(1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + c.emplace_back(1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + c.emplace_back(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + c.emplace_back(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + + return true; +} + +template +bool test_emplace_back(detail::false_) +{ return true; } + +template +bool test_emplace_front(detail::true_) +{ + std::cout << "Starting test_emplace_front." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + { + new(&expected [0]) EmplaceInt(1, 2, 3, 4, 5); + new(&expected [1]) EmplaceInt(1, 2, 3, 4); + new(&expected [2]) EmplaceInt(1, 2, 3); + new(&expected [3]) EmplaceInt(1, 2); + new(&expected [4]) EmplaceInt(1); + new(&expected [5]) EmplaceInt(); + Container c; + c.emplace_front(); + if(!test_expected_container(c, &expected[0] + 5, 1)) + return false; + c.emplace_front(1); + if(!test_expected_container(c, &expected[0] + 4, 2)) + return false; + c.emplace_front(1, 2); + if(!test_expected_container(c, &expected[0] + 3, 3)) + return false; + c.emplace_front(1, 2, 3); + if(!test_expected_container(c, &expected[0] + 2, 4)) + return false; + c.emplace_front(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0] + 1, 5)) + return false; + c.emplace_front(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0] + 0, 6)) + return false; + } + return true; +} + +template +bool test_emplace_front(detail::false_) +{ return true; } + +template +bool test_emplace_before(detail::true_) +{ + std::cout << "Starting test_emplace_before." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(); + Container c; + c.emplace(c.cend(), 1); + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace(c.cend()); + if(!test_expected_container(c, &expected[0], 3)) + return false; + } + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + //emplace_front-like + Container c; + c.emplace(c.cbegin(), 1, 2, 3, 4, 5); + c.emplace(c.cbegin(), 1, 2, 3, 4); + c.emplace(c.cbegin(), 1, 2, 3); + c.emplace(c.cbegin(), 1, 2); + c.emplace(c.cbegin(), 1); + c.emplace(c.cbegin()); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace_back-like + typename Container::const_iterator i = c.emplace(c.cend()); + if(!test_expected_container(c, &expected[0], 1)) + return false; + i = c.emplace(++i, 1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + i = c.emplace(++i, 1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + i = c.emplace(++i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + i = c.emplace(++i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + i = c.emplace(++i, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace in the middle + c.emplace(c.cbegin()); + i = c.emplace(c.cend(), 1, 2, 3, 4, 5); + i = c.emplace(i, 1, 2, 3, 4); + i = c.emplace(i, 1, 2, 3); + i = c.emplace(i, 1, 2); + i = c.emplace(i, 1); + + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + return true; +} + +template +bool test_emplace_before(detail::false_) +{ return true; } + +template +bool test_emplace_after(detail::true_) +{ + std::cout << "Starting test_emplace_after." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(); + Container c; + typename Container::const_iterator i = c.emplace_after(c.cbefore_begin(), 1); + c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace_after(i); + if(!test_expected_container(c, &expected[0], 3)) + return false; + } + { + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + //emplace_front-like + Container c; + c.emplace_after(c.cbefore_begin(), 1, 2, 3, 4, 5); + c.emplace_after(c.cbefore_begin(), 1, 2, 3, 4); + c.emplace_after(c.cbefore_begin(), 1, 2, 3); + c.emplace_after(c.cbefore_begin(), 1, 2); + c.emplace_after(c.cbefore_begin(), 1); + c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace_back-like + typename Container::const_iterator i = c.emplace_after(c.cbefore_begin()); + if(!test_expected_container(c, &expected[0], 1)) + return false; + i = c.emplace_after(i, 1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + i = c.emplace_after(i, 1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + i = c.emplace_after(i, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + i = c.emplace_after(i, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + i = c.emplace_after(i, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + c.clear(); + //emplace_after in the middle + i = c.emplace_after(c.cbefore_begin()); + c.emplace_after(i, 1, 2, 3, 4, 5); + c.emplace_after(i, 1, 2, 3, 4); + c.emplace_after(i, 1, 2, 3); + c.emplace_after(i, 1, 2); + c.emplace_after(i, 1); + + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + return true; +} + +template +bool test_emplace_after(detail::false_) +{ return true; } + +template +bool test_emplace_assoc(detail::true_) +{ + std::cout << "Starting test_emplace_assoc." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + { + Container c; + c.emplace(); + if(!test_expected_container(c, &expected[0], 1)) + return false; + c.emplace(1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + c.emplace(1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + c.emplace(1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + c.emplace(1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + c.emplace(1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + return true; +} + +template +bool test_emplace_assoc(detail::false_) +{ return true; } + +template +bool test_emplace_hint(detail::true_) +{ + std::cout << "Starting test_emplace_hint." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected [0]) EmplaceInt(); + new(&expected [1]) EmplaceInt(1); + new(&expected [2]) EmplaceInt(1, 2); + new(&expected [3]) EmplaceInt(1, 2, 3); + new(&expected [4]) EmplaceInt(1, 2, 3, 4); + new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); + + { + Container c; + typename Container::const_iterator it; + it = c.emplace_hint(c.begin()); + if(!test_expected_container(c, &expected[0], 1)) + return false; + it = c.emplace_hint(it, 1); + if(!test_expected_container(c, &expected[0], 2)) + return false; + it = c.emplace_hint(it, 1, 2); + if(!test_expected_container(c, &expected[0], 3)) + return false; + it = c.emplace_hint(it, 1, 2, 3); + if(!test_expected_container(c, &expected[0], 4)) + return false; + it = c.emplace_hint(it, 1, 2, 3, 4); + if(!test_expected_container(c, &expected[0], 5)) + return false; + it = c.emplace_hint(it, 1, 2, 3, 4, 5); + if(!test_expected_container(c, &expected[0], 6)) + return false; + } + + return true; +} + +template +bool test_emplace_hint(detail::false_) +{ return true; } + +template +bool test_emplace_assoc_pair(detail::true_) +{ + std::cout << "Starting test_emplace_assoc_pair." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected_pair[0].first) EmplaceInt(); + new(&expected_pair[0].second) EmplaceInt(); + new(&expected_pair[1].first) EmplaceInt(1); + new(&expected_pair[1].second) EmplaceInt(); + new(&expected_pair[2].first) EmplaceInt(2); + new(&expected_pair[2].second) EmplaceInt(2); + new(&expected_pair[3].first) EmplaceInt(3); + new(&expected_pair[3].second) EmplaceInt(2, 3); + new(&expected_pair[4].first) EmplaceInt(4); + new(&expected_pair[4].second) EmplaceInt(2, 3, 4); + new(&expected_pair[5].first) EmplaceInt(5); + new(&expected_pair[5].second) EmplaceInt(2, 3, 4, 5); + { + Container c; + c.emplace(); + if(!test_expected_container(c, &expected_pair[0], 1)){ + std::cout << "Error after c.emplace();\n"; + return false; + } + c.emplace(1); + if(!test_expected_container(c, &expected_pair[0], 2)){ + std::cout << "Error after c.emplace(1);\n"; + return false; + } + c.emplace(2, 2); + if(!test_expected_container(c, &expected_pair[0], 3)){ + std::cout << "Error after c.emplace(2, 2);\n"; + return false; + } + c.emplace(3, 2, 3); + if(!test_expected_container(c, &expected_pair[0], 4)){ + std::cout << "Error after c.emplace(3, 2, 3);\n"; + return false; + } + c.emplace(4, 2, 3, 4); + if(!test_expected_container(c, &expected_pair[0], 5)){ + std::cout << "Error after c.emplace(4, 2, 3, 4);\n"; + return false; + } + c.emplace(5, 2, 3, 4, 5); + if(!test_expected_container(c, &expected_pair[0], 6)){ + std::cout << "Error after c.emplace(5, 2, 3, 4, 5);\n"; + return false; + } + } + return true; +} + +template +bool test_emplace_assoc_pair(detail::false_) +{ return true; } + +template +bool test_emplace_hint_pair(detail::true_) +{ + std::cout << "Starting test_emplace_hint_pair." << std::endl << " Class: " + << typeid(Container).name() << std::endl; + + new(&expected_pair[0].first) EmplaceInt(); + new(&expected_pair[0].second) EmplaceInt(); + new(&expected_pair[1].first) EmplaceInt(1); + new(&expected_pair[1].second) EmplaceInt(); + new(&expected_pair[2].first) EmplaceInt(2); + new(&expected_pair[2].second) EmplaceInt(2); + new(&expected_pair[3].first) EmplaceInt(3); + new(&expected_pair[3].second) EmplaceInt(2, 3); + new(&expected_pair[4].first) EmplaceInt(4); + new(&expected_pair[4].second) EmplaceInt(2, 3, 4); + new(&expected_pair[5].first) EmplaceInt(5); + new(&expected_pair[5].second) EmplaceInt(2, 3, 4, 5); + { + Container c; + typename Container::const_iterator it; + it = c.emplace_hint(c.begin()); + if(!test_expected_container(c, &expected_pair[0], 1)){ + std::cout << "Error after c.emplace(1);\n"; + return false; + } + it = c.emplace_hint(it, 1); + if(!test_expected_container(c, &expected_pair[0], 2)){ + std::cout << "Error after c.emplace(it, 1);\n"; + return false; + } + it = c.emplace_hint(it, 2, 2); + if(!test_expected_container(c, &expected_pair[0], 3)){ + std::cout << "Error after c.emplace(it, 2, 2);\n"; + return false; + } + it = c.emplace_hint(it, 3, 2, 3); + if(!test_expected_container(c, &expected_pair[0], 4)){ + std::cout << "Error after c.emplace(it, 3, 2, 3);\n"; + return false; + } + it = c.emplace_hint(it, 4, 2, 3, 4); + if(!test_expected_container(c, &expected_pair[0], 5)){ + std::cout << "Error after c.emplace(it, 4, 2, 3, 4);\n"; + return false; + } + it = c.emplace_hint(it, 5, 2, 3, 4, 5); + if(!test_expected_container(c, &expected_pair[0], 6)){ + std::cout << "Error after c.emplace(it, 5, 2, 3, 4, 5);\n"; + return false; + } + } + return true; +} + +template +bool test_emplace_hint_pair(detail::false_) +{ return true; } + +template +struct emplace_active +{ + static const bool value = (0 != (O & Mask)); + typedef detail::bool_ type; + operator type() const{ return type(); } +}; + +template +bool test_emplace() +{ + if(!test_emplace_back(emplace_active())) + return false; + if(!test_emplace_front(emplace_active())) + return false; + if(!test_emplace_before(emplace_active())) + return false; + if(!test_emplace_after(emplace_active())) + return false; + if(!test_emplace_assoc(emplace_active())) + return false; + if(!test_emplace_hint(emplace_active())) + return false; + if(!test_emplace_assoc_pair(emplace_active())) + return false; + if(!test_emplace_hint_pair(emplace_active())) + return false; + return true; +} + +} //namespace test{ +} //namespace interprocess{ +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_INTERPROCESS_TEST_EMPLACE_TEST_HPP diff --git a/test/expand_bwd_test_template.hpp b/test/expand_bwd_test_template.hpp index 4a61d92..66545ec 100644 --- a/test/expand_bwd_test_template.hpp +++ b/test/expand_bwd_test_template.hpp @@ -148,7 +148,7 @@ bool test_insert_with_expand_bwd() } expand_bwd_test_allocator alloc - ((value_type*)&memory[0], MemorySize, Offset[iteration]); + (&memory[0], MemorySize, Offset[iteration]); VectorWithExpandBwdAllocator vector(alloc); vector.insert( vector.begin() , initial_data.begin(), initial_data.end()); @@ -165,10 +165,10 @@ bool test_insert_with_expand_bwd() } } catch(...){ - delete []((non_volatile_value_type*)memory); + delete [](const_cast(memory)); throw; } - delete []((non_volatile_value_type*)memory); + delete [](const_cast(memory)); } return true; @@ -227,10 +227,10 @@ bool test_assign_with_expand_bwd() } } catch(...){ - delete []((typename boost::remove_volatile::type*)memory); + delete [](const_cast::type*>(memory)); throw; } - delete []((typename boost::remove_volatile::type*)memory); + delete [](const_cast::type*>(memory)); } return true; diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp index 80df430..e7ebd77 100644 --- a/test/flat_tree_test.cpp +++ b/test/flat_tree_test.cpp @@ -20,6 +20,7 @@ #include "movable_int.hpp" #include "set_test.hpp" #include "map_test.hpp" +#include "emplace_test.hpp" ///////////////////////////////////////////////////////////////// // @@ -30,7 +31,7 @@ ///////////////////////////////////////////////////////////////// using namespace boost::interprocess; - +/* //Explicit instantiation to detect compilation errors template class boost::interprocess::flat_set ,test::dummy_test_allocator > >; - +*/ //Customize managed_shared_memory class typedef basic_managed_shared_memory ,shmem_move_copy_pair_allocator_t> MyMoveCopyShmMultiMap; +//Test recursive structures +class recursive_flat_set +{ +public: + int id_; + flat_set flat_set_; + friend bool operator< (const recursive_flat_set &a, const recursive_flat_set &b) + { return a.id_ < b.id_; } +}; + +class recursive_flat_map +{ +public: + int id_; + flat_map map_; + friend bool operator< (const recursive_flat_map &a, const recursive_flat_map &b) + { return a.id_ < b.id_; } +}; + int main() { using namespace boost::interprocess::test; + if (0 != set_test, MapOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace, MapOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace, SetOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace, SetOptions>()) + return 1; + #endif //!defined(__GNUC__) return 0; } diff --git a/test/intersegment_ptr_test.cpp b/test/intersegment_ptr_test.cpp index 1f2d98a..d068624 100644 --- a/test/intersegment_ptr_test.cpp +++ b/test/intersegment_ptr_test.cpp @@ -205,14 +205,14 @@ bool test_basic_comparisons() if(sizeof(segment_data) > mapped_region::get_page_size()) return false; - segment_data &seg_0_0 = *((segment_data *)reg_0_0.get_address()); - segment_data &seg_0_1 = *((segment_data *)reg_0_1.get_address()); - segment_data &seg_1_0 = *((segment_data *)reg_1_0.get_address()); - segment_data &seg_1_1 = *((segment_data *)reg_1_1.get_address()); + segment_data &seg_0_0 = *static_cast(reg_0_0.get_address()); + segment_data &seg_0_1 = *static_cast(reg_0_1.get_address()); + segment_data &seg_1_0 = *static_cast(reg_1_0.get_address()); + segment_data &seg_1_1 = *static_cast(reg_1_1.get_address()); //Some dummy multi_segment_services - multi_segment_services *services0 = (multi_segment_services *)0; - multi_segment_services *services1 = (multi_segment_services *)1; + multi_segment_services *services0 = static_cast(0); + multi_segment_services *services1 = reinterpret_cast(1); const intersegment_ptr::segment_group_id group_0_id = intersegment_ptr::new_segment_group(services0); @@ -386,7 +386,7 @@ bool test_multi_segment_shared_memory() } int main() -{ +{/* if(!test_types_and_convertions()) return 1; if(!test_arithmetic()) @@ -398,6 +398,7 @@ int main() if(!test_multi_segment_shared_memory()) return 1; +*/ return 0; } diff --git a/test/list_test.cpp b/test/list_test.cpp index e2073fe..b4c4249 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "list_test.hpp" #include "movable_int.hpp" +#include "emplace_test.hpp" using namespace boost::interprocess; @@ -35,8 +36,21 @@ typedef list MyMoveList; typedef allocator ShmemCopyMoveAllocator; typedef list MyCopyMoveList; +class recursive_list +{ +public: + int id_; + list list_; +}; + +void recursive_list_test()//Test for recursive types +{ + list recursive_list_list; +} + int main () { + recursive_list_test(); if(test::list_test()) return 1; @@ -49,6 +63,11 @@ int main () if(test::list_test()) return 1; + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); + + if(!boost::interprocess::test::test_emplace, Options>()) + return 1; + return 0; } diff --git a/test/list_test.hpp b/test/list_test.hpp index deaa277..390f61e 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -88,7 +88,6 @@ struct pop_back_function } }; - template diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index 0d00edb..d68752b 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -20,7 +20,7 @@ using namespace boost::interprocess; int main () { - const int FileSize = 65536; + const int FileSize = 65536*10; const char *const FileName = test::get_process_id_name(); //STL compatible allocator object for memory-mapped file @@ -42,6 +42,7 @@ int main () //Let's allocate some memory for(i = 0; i < max; ++i){ array[i] = mfile.allocate(i+1); + std::cout << i << ' '; } //Deallocate allocated memory diff --git a/test/memory_algorithm_test_template.hpp b/test/memory_algorithm_test_template.hpp index 29a85ef..f7216d4 100644 --- a/test/memory_algorithm_test_template.hpp +++ b/test/memory_algorithm_test_template.hpp @@ -108,7 +108,7 @@ bool test_allocation_shrink(Allocator &a) std::size_t received_size; if(a.template allocation_command ( shrink_in_place | nothrow_allocation, i*2 - , i, received_size, (char*)buffers[i]).first){ + , i, received_size, static_cast(buffers[i])).first){ if(received_size > std::size_t(i*2)){ return false; } @@ -160,7 +160,7 @@ bool test_allocation_expand(Allocator &a) while(a.template allocation_command ( expand_fwd | nothrow_allocation, min_size - , preferred_size, received_size, (char*)buffers[i]).first){ + , preferred_size, received_size, static_cast(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ return false; @@ -215,7 +215,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) std::size_t received_size; if(a.template allocation_command ( shrink_in_place | nothrow_allocation, received_sizes[i] - , i, received_size, (char*)buffers[i]).first){ + , i, received_size, static_cast(buffers[i])).first){ if(received_size > std::size_t(received_sizes[i])){ return false; } @@ -234,7 +234,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) std::size_t request_size = received_sizes[i]; if(a.template allocation_command ( expand_fwd | nothrow_allocation, request_size - , request_size, received_size, (char*)buffers[i]).first){ + , request_size, received_size, static_cast(buffers[i])).first){ if(received_size != received_sizes[i]){ return false; } @@ -299,7 +299,7 @@ bool test_allocation_deallocation_expand(Allocator &a) while(a.template allocation_command ( expand_fwd | nothrow_allocation, min_size - , preferred_size, received_size, (char*)buffers[i]).first){ + , preferred_size, received_size, static_cast(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ return false; @@ -312,8 +312,8 @@ bool test_allocation_deallocation_expand(Allocator &a) } //Now erase null values from the vector - buffers.erase(std::remove(buffers.begin(), buffers.end(), (void*)0) - ,buffers.end()); + buffers.erase( std::remove(buffers.begin(), buffers.end(), static_cast(0)) + , buffers.end()); //Deallocate it in non sequential order for(int j = 0, max = (int)buffers.size() @@ -369,7 +369,7 @@ bool test_allocation_with_reuse(Allocator &a) std::size_t prf_size = (received_size + (i+1)*2); std::pair ret = a.raw_allocation_command ( expand_bwd | nothrow_allocation, min_size - , prf_size, received_size, (char*)ptr, sizeof_object); + , prf_size, received_size, static_cast(ptr), sizeof_object); if(!ret.first) break; //If we have memory, this must be a buffer reuse @@ -511,7 +511,7 @@ bool test_clear_free_memory(Allocator &a) //Test allocated memory is zero for(int i = 0, max = buffers.size(); i < max; ++i){ for(int j = 0; j < i; ++j){ - if(((char*)buffers[i])[j]) return false; + if(static_cast(buffers[i])[j]) return false; } } diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 8d16596..eeb12f6 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -52,6 +52,9 @@ class movable_int { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } #endif + movable_int & operator= (int i) + { this->m_int = i; return *this; } + bool operator ==(const movable_int &mi) const { return this->m_int == mi.m_int; } @@ -123,6 +126,9 @@ class movable_and_copyable_int { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } #endif + movable_and_copyable_int & operator= (int i) + { this->m_int = i; return *this; } + bool operator ==(const movable_and_copyable_int &mi) const { return this->m_int == mi.m_int; } diff --git a/test/mutex_test_template.hpp b/test/mutex_test_template.hpp index 54c57d4..64b4a7a 100644 --- a/test/mutex_test_template.hpp +++ b/test/mutex_test_template.hpp @@ -165,7 +165,7 @@ struct test_recursive_lock template void lock_and_sleep(void *arg, M &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l(sm); if(pdata->m_secs){ boost::thread::sleep(xsecs(pdata->m_secs)); @@ -181,7 +181,7 @@ void lock_and_sleep(void *arg, M &sm) template void try_lock_and_sleep(void *arg, M &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ boost::thread::sleep(xsecs(2*BaseSeconds)); @@ -193,7 +193,7 @@ void try_lock_and_sleep(void *arg, M &sm) template void timed_lock_and_sleep(void *arg, M &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::posix_time::ptime pt(delay(pdata->m_secs)); boost::interprocess::scoped_lock l (sm, boost::interprocess::defer_lock); diff --git a/test/named_construct_test.cpp b/test/named_construct_test.cpp new file mode 100644 index 0000000..fade538 --- /dev/null +++ b/test/named_construct_test.cpp @@ -0,0 +1,195 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +typedef std::pair simple_pair; + +using namespace boost::interprocess; + +struct array_pair : public simple_pair +{ + array_pair(double d, int i) + : simple_pair(d, i) {} +}; + +struct array_it_pair : public array_pair +{ + array_it_pair(double d, int i) + : array_pair(d, i) {} +}; + +struct named_name_generator +{ + static const bool searchable = true; + + typedef simple_pair simple_type; + typedef array_pair array_type; + typedef array_it_pair array_it_type; + static const char *get_simple_name() + { return "MyType instance"; } + static const char *get_array_name() + { return "MyType array"; } + static const char *get_array_it_name() + { return "MyType array from it"; } +}; + +struct unique_name_generator +{ + static const bool searchable = true; + + typedef simple_pair simple_type; + typedef array_pair array_type; + typedef array_it_pair array_it_type; + static const detail::unique_instance_t *get_simple_name() + { return 0; } + static const detail::unique_instance_t *get_array_name() + { return 0; } + static const detail::unique_instance_t *get_array_it_name() + { return 0; } +}; + +struct anonymous_name_generator +{ + static const bool searchable = false; + + typedef simple_pair simple_type; + typedef array_pair array_type; + typedef array_it_pair array_it_type; + static const detail::anonymous_instance_t *get_simple_name() + { return 0; } + static const detail::anonymous_instance_t *get_array_name() + { return 0; } + static const detail::anonymous_instance_t *get_array_it_name() + { return 0; } +}; + + +template +int construct_test() +{ + typedef typename NameGenerator::simple_type simple_type; + typedef typename NameGenerator::array_type array_type; + typedef typename NameGenerator::array_it_type array_it_type; + + remove_shared_memory_on_destroy remover("MySharedMemory"); + shared_memory_object::remove("MySharedMemory"); + { + //A special shared memory where we can + //construct objects associated with a name. + //First remove any old shared memory of the same name, create + //the shared memory segment and initialize needed resources + managed_shared_memory segment + //create segment name segment size + (create_only, "MySharedMemory", 65536); + + //Create an object of MyType initialized to {0.0, 0} + simple_type *s = segment.construct + (NameGenerator::get_simple_name())//name of the object + (1.0, 2); //ctor first argument + assert(s->first == 1.0 && s->second == 2); + if(!(s->first == 1.0 && s->second == 2)) + return 1; + + //Create an array of 10 elements of MyType initialized to {0.0, 0} + array_type *a = segment.construct + (NameGenerator::get_array_name()) //name of the object + [10] //number of elements + (3.0, 4); //Same two ctor arguments for all objects + assert(a->first == 3.0 && a->second == 4); + if(!(a->first == 3.0 && a->second == 4)) + return 1; + + //Create an array of 3 elements of MyType initializing each one + //to a different value {0.0, 3}, {1.0, 4}, {2.0, 5}... + float float_initializer[3] = { 0.0, 1.0, 2.0 }; + int int_initializer[3] = { 3, 4, 5 }; + + array_it_type *a_it = segment.construct_it + (NameGenerator::get_array_it_name()) //name of the object + [3] //number of elements + ( &float_initializer[0] //Iterator for the 1st ctor argument + , &int_initializer[0]); //Iterator for the 2nd ctor argument + { + const array_it_type *a_it_ptr = a_it; + for(unsigned int i = 0, max = 3; i != max; ++i, ++a_it_ptr){ + assert(a_it_ptr->first == float_initializer[i]); + if(a_it_ptr->first != float_initializer[i]){ + return 1; + } + assert(a_it_ptr->second == int_initializer[i]); + if(a_it_ptr->second != int_initializer[i]){ + return 1; + } + } + } + + if(NameGenerator::searchable){ + { + std::pair res; + //Find the object + res = segment.find (NameGenerator::get_simple_name()); + //Length should be 1 + assert(res.second == 1); + if(res.second != 1) + return 1; + assert(res.first == s); + if(res.first != s) + return 1; + } + { + std::pair res; + + //Find the array + res = segment.find (NameGenerator::get_array_name()); + //Length should be 10 + assert(res.second == 10); + if(res.second != 10) + return 1; + assert(res.first == a); + if(res.first != a) + return 1; + } + { + std::pair res; + //Find the array constructed from iterators + res = segment.find (NameGenerator::get_array_it_name()); + //Length should be 3 + assert(res.second == 3); + if(res.second != 3) + return 1; + assert(res.first == a_it); + if(res.first != a_it) + return 1; + } + } + //We're done, delete all the objects + segment.destroy_ptr(s); + segment.destroy_ptr(a); + segment.destroy_ptr(a_it); + } + return 0; +} + +int main () +{ + if(0 != construct_test()) + return 1; + if(0 != construct_test()) + return 1; + if(0 != construct_test()) + return 1; + return 0; +} + +//] +#include diff --git a/test/node_allocator_test.cpp b/test/node_allocator_test.cpp index 4c1235f..8333fa8 100644 --- a/test/node_allocator_test.cpp +++ b/test/node_allocator_test.cpp @@ -22,7 +22,7 @@ using namespace boost::interprocess; //We will work with wide characters for shared memory objects -//Alias a integer node allocator type +//Alias an integer node allocator type typedef node_allocator shmem_node_allocator_t; typedef detail::node_allocator_v1 diff --git a/test/private_node_allocator_test.cpp b/test/private_node_allocator_test.cpp index ad3fc5d..5ea8659 100644 --- a/test/private_node_allocator_test.cpp +++ b/test/private_node_allocator_test.cpp @@ -22,7 +22,7 @@ using namespace boost::interprocess; //We will work with wide characters for shared memory objects -//Alias a integer node allocator type +//Alias an integer node allocator type typedef private_node_allocator priv_node_allocator_t; typedef detail::private_node_allocator_v1 diff --git a/test/semaphore_test_template.hpp b/test/semaphore_test_template.hpp index 23c235f..8b313cb 100644 --- a/test/semaphore_test_template.hpp +++ b/test/semaphore_test_template.hpp @@ -146,7 +146,7 @@ struct test_recursive_lock template void wait_and_sleep(void *arg, P &sm) { - data

*pdata = (data

*) arg; + data

*pdata = static_cast*>(arg); boost::interprocess::scoped_lock

l(sm); boost::thread::sleep(xsecs(3*BaseSeconds)); ++shared_val; @@ -156,7 +156,7 @@ void wait_and_sleep(void *arg, P &sm) template void try_wait_and_sleep(void *arg, P &sm) { - data

*pdata = (data

*) arg; + data

*pdata = static_cast*>(arg); boost::interprocess::scoped_lock

l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ boost::thread::sleep(xsecs(3*BaseSeconds)); @@ -168,7 +168,7 @@ void try_wait_and_sleep(void *arg, P &sm) template void timed_wait_and_sleep(void *arg, P &sm) { - data

*pdata = (data

*) arg; + data

*pdata = static_cast*>(arg); boost::posix_time::ptime pt(delay(pdata->m_secs)); boost::interprocess::scoped_lock

l (sm, boost::interprocess::defer_lock); diff --git a/test/sharable_mutex_test_template.hpp b/test/sharable_mutex_test_template.hpp index 4858646..338ef1c 100644 --- a/test/sharable_mutex_test_template.hpp +++ b/test/sharable_mutex_test_template.hpp @@ -38,7 +38,7 @@ namespace boost { namespace interprocess { namespace test { template void plain_exclusive(void *arg, SM &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l(sm); boost::thread::sleep(xsecs(3*BaseSeconds)); shared_val += 10; @@ -48,7 +48,7 @@ void plain_exclusive(void *arg, SM &sm) template void plain_shared(void *arg, SM &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::interprocess::sharable_lock l(sm); if(pdata->m_secs){ boost::thread::sleep(xsecs(pdata->m_secs*BaseSeconds)); @@ -59,7 +59,7 @@ void plain_shared(void *arg, SM &sm) template void try_exclusive(void *arg, SM &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ boost::thread::sleep(xsecs(3*BaseSeconds)); @@ -71,7 +71,7 @@ void try_exclusive(void *arg, SM &sm) template void try_shared(void *arg, SM &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::interprocess::sharable_lock l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ if(pdata->m_secs){ @@ -84,7 +84,7 @@ void try_shared(void *arg, SM &sm) template void timed_exclusive(void *arg, SM &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::posix_time::ptime pt(delay(pdata->m_secs)); boost::interprocess::scoped_lock l (sm, boost::interprocess::defer_lock); @@ -98,7 +98,7 @@ void timed_exclusive(void *arg, SM &sm) template void timed_shared(void *arg, SM &sm) { - data *pdata = (data *) arg; + data *pdata = static_cast*>(arg); boost::posix_time::ptime pt(delay(pdata->m_secs)); boost::interprocess::sharable_lock l(sm, boost::interprocess::defer_lock); @@ -143,11 +143,11 @@ void test_plain_sharable_mutex() // Reader one launches, "clearly" after writer two, and "clearly" // while writer 1 still holds the lock boost::thread::sleep(xsecs(1*BaseSeconds)); - boost::thread tr1(thread_adapter(plain_shared,&s1, *pm3)); - boost::thread tr2(thread_adapter(plain_shared,&s2, *pm4)); + boost::thread thr1(thread_adapter(plain_shared,&s1, *pm3)); + boost::thread thr2(thread_adapter(plain_shared,&s2, *pm4)); - tr2.join(); - tr1.join(); + thr2.join(); + thr1.join(); tw2.join(); tw1.join(); @@ -177,8 +177,8 @@ void test_plain_sharable_mutex() data e2(2); //We launch 2 readers, that will block for 3*BaseTime seconds - boost::thread tr1(thread_adapter(plain_shared,&s1,*pm1)); - boost::thread tr2(thread_adapter(plain_shared,&s2,*pm2)); + boost::thread thr1(thread_adapter(plain_shared,&s1,*pm1)); + boost::thread thr2(thread_adapter(plain_shared,&s2,*pm2)); //Make sure they try to hold the sharable lock boost::thread::sleep(xsecs(1*BaseSeconds)); @@ -187,8 +187,8 @@ void test_plain_sharable_mutex() boost::thread tw1(thread_adapter(plain_exclusive,&e1,*pm3)); boost::thread tw2(thread_adapter(plain_exclusive,&e2,*pm4)); - tr2.join(); - tr1.join(); + thr2.join(); + thr1.join(); tw2.join(); tw1.join(); @@ -229,13 +229,13 @@ void test_try_sharable_mutex() // Reader one launches, "clearly" after writer #1 holds the lock // and before it releases the lock. boost::thread::sleep(xsecs(1*BaseSeconds)); - boost::thread tr1(thread_adapter(try_shared,&s1,*pm2)); + boost::thread thr1(thread_adapter(try_shared,&s1,*pm2)); // Writer two launches in the same timeframe. boost::thread tw2(thread_adapter(try_exclusive,&e2,*pm3)); tw2.join(); - tr1.join(); + thr1.join(); tw1.join(); assert(e1.m_value == 10); @@ -281,12 +281,12 @@ void test_timed_sharable_mutex() // to get the lock. 2nd reader will wait 3*BaseSeconds seconds, and will get // the lock. - boost::thread tr1(thread_adapter(timed_shared,&s1,*pm3)); - boost::thread tr2(thread_adapter(timed_shared,&s2,*pm4)); + boost::thread thr1(thread_adapter(timed_shared,&s1,*pm3)); + boost::thread thr2(thread_adapter(timed_shared,&s2,*pm4)); tw1.join(); - tr1.join(); - tr2.join(); + thr1.join(); + thr2.join(); tw2.join(); assert(e1.m_value == 10); diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 54fc31d..6f363f3 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -72,7 +72,7 @@ int main () mapped_region region(mapping, read_write, 0, FileSize/2, 0); mapped_region region2(mapping, read_write, FileSize/2, FileSize - FileSize/2, 0); - unsigned char *checker = (unsigned char*)region.get_address(); + unsigned char *checker = static_cast(region.get_address()); //Check pattern for(std::size_t i = 0 ;i < FileSize/2 @@ -83,7 +83,7 @@ int main () } //Check second half - checker = (unsigned char *)region2.get_address(); + checker = static_cast(region2.get_address()); //Check pattern for(std::size_t i = FileSize/2 diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index ef7066a..38c08d1 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -587,7 +587,7 @@ void test_alias() BOOST_TEST( p2.use_count() == p.use_count() ); BOOST_TEST( !( p < p2 ) && !( p2 < p ) ); - p2.reset( p, (int*)0 ); + p2.reset( p, static_cast(0) ); BOOST_TEST( p2.get() == 0 ); diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 00d2f36..1bf7462 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -16,6 +16,7 @@ #include "dummy_test_allocator.hpp" #include "list_test.hpp" #include "movable_int.hpp" +#include "emplace_test.hpp" using namespace boost::interprocess; @@ -26,20 +27,50 @@ template class boost::interprocess::slist ShmemAllocator; typedef slist MyList; +typedef allocator ShmemVolatileAllocator; +typedef slist MyVolatileList; + typedef allocator ShmemMoveAllocator; typedef slist MyMoveList; typedef allocator ShmemCopyMoveAllocator; typedef slist MyCopyMoveList; +class recursive_slist +{ +public: + int id_; + slist slist_; +}; + +void recursive_slist_test()//Test for recursive types +{ + slist recursive_list_list; +} + int main () { + recursive_slist_test(); + if(test::list_test()) return 1; if(test::list_test()) return 1; + if(test::list_test()) + return 1; + + if(test::list_test()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions) + (test::EMPLACE_FRONT | test::EMPLACE_AFTER | test::EMPLACE_BEFORE | test::EMPLACE_AFTER); + + if(!boost::interprocess::test::test_emplace + < slist, Options>()) + return 1; + return 0; } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index 2535ec6..a9c3786 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -22,6 +22,7 @@ #include "dummy_test_allocator.hpp" #include "set_test.hpp" #include "map_test.hpp" +#include "emplace_test.hpp" /////////////////////////////////////////////////////////////////// // // @@ -32,7 +33,7 @@ /////////////////////////////////////////////////////////////////// using namespace boost::interprocess; - +/* //Explicit instantiation to detect compilation errors template class boost::interprocess::set ,test::dummy_test_allocator > >; - +*/ //Customize managed_shared_memory class typedef basic_managed_shared_memory my_managed_shared_memory; //We will work with narrow characters for shared memory objects -//Alias a integer node allocator type +//Alias an integer node allocator type typedef allocator shmem_allocator_t; typedef allocator, my_managed_shared_memory::segment_manager> @@ -119,9 +120,54 @@ typedef multimap ,shmem_move_copy_node_pair_allocator_t> MyMoveCopyShmMultiMap; +//Test recursive structures +class recursive_set +{ +public: + int id_; + set set_; + friend bool operator< (const recursive_set &a, const recursive_set &b) + { return a.id_ < b.id_; } +}; + +class recursive_map +{ + public: + int id_; + map map_; + friend bool operator< (const recursive_map &a, const recursive_map &b) + { return a.id_ < b.id_; } +}; + +//Test recursive structures +class recursive_multiset +{ +public: + int id_; + multiset multiset_; + friend bool operator< (const recursive_multiset &a, const recursive_multiset &b) + { return a.id_ < b.id_; } +}; + +class recursive_multimap +{ +public: + int id_; + multimap multimap_; + friend bool operator< (const recursive_multimap &a, const recursive_multimap &b) + { return a.id_ < b.id_; } +}; int main () { + //Recursive container instantiation + { + set set_; + multiset multiset_; + map map_; + multimap multimap_; + } + using namespace boost::interprocess::detail; if(0 != test::set_test, SetOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace, SetOptions>()) + return 1; + const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR); + if(!boost::interprocess::test::test_emplace, MapOptions>()) + return 1; + if(!boost::interprocess::test::test_emplace, MapOptions>()) + return 1; return 0; } diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index 0835575..cc107f1 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -198,7 +198,7 @@ int main () std::size_t heap_list_size = heaplist->size(); //Copy heap buffer to another - const char *insert_beg = detail::char_ptr_cast(heap_buffer.get_address()); + const char *insert_beg = static_cast(heap_buffer.get_address()); const char *insert_end = insert_beg + heap_buffer.get_size(); std::vector grow_copy (insert_beg, insert_end); diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 206b0d0..22c9a57 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -76,8 +76,21 @@ int test_expand_bwd() return 0; } +class recursive_vector +{ + public: + int id_; + vector vector_; +}; + +void recursive_vector_test()//Test for recursive types +{ + vector recursive_vector_vector; +} + int main() { + recursive_vector_test(); typedef allocator ShmemAllocator; typedef vector MyVector; @@ -105,6 +118,11 @@ int main() if(test_expand_bwd()) return 1; + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::interprocess::test::test_emplace + < vector, Options>()) + return 1; + return 0; } diff --git a/test/vector_test.hpp b/test/vector_test.hpp index d2f17ac..dd3e46f 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #include #include "get_process_id_name.hpp" +#include "emplace_test.hpp" namespace boost{ namespace interprocess{ @@ -46,22 +48,22 @@ bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) if(!test::CheckEqualContainers(shmvector, stdvector)) return false; { - IntType move_me(1); - stdvector->insert(stdvector->begin()+size/2, 50, 1); - shmvector->insert(shmvector->begin()+size/2, 50, detail::move_impl(move_me)); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + IntType move_me(1); + stdvector->insert(stdvector->begin()+size/2, 50, 1); + shmvector->insert(shmvector->begin()+size/2, 50, detail::move_impl(move_me)); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { - IntType move_me(2); - shmvector->assign(shmvector->size()/2, detail::move_impl(move_me)); - stdvector->assign(stdvector->size()/2, 2); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + IntType move_me(2); + shmvector->assign(shmvector->size()/2, detail::move_impl(move_me)); + stdvector->assign(stdvector->size()/2, 2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { - IntType move_me(3); - shmvector->assign(shmvector->size()*3-1, detail::move_impl(move_me)); - stdvector->assign(stdvector->size()*3-1, 3); - if(!test::CheckEqualContainers(shmvector, stdvector)) return false; + IntType move_me(3); + shmvector->assign(shmvector->size()*3-1, detail::move_impl(move_me)); + stdvector->assign(stdvector->size()*3-1, 3); + if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } return true; } @@ -192,6 +194,17 @@ int vector_test() } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + //Test insertion from list + { + std::list l(50, int(1)); + shmvector->insert(shmvector->begin(), l.begin(), l.end()); + stdvector->insert(stdvector->begin(), l.begin(), l.end()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->assign(l.begin(), l.end()); + stdvector->assign(l.begin(), l.end()); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + } + delete stdvector; segment.template destroy("MyShmVector"); segment.shrink_to_fit_indexes(); diff --git a/test/windows_shared_memory_mapping_test.cpp b/test/windows_shared_memory_mapping_test.cpp index a5a20ab..8bd4f10 100644 --- a/test/windows_shared_memory_mapping_test.cpp +++ b/test/windows_shared_memory_mapping_test.cpp @@ -68,7 +68,7 @@ int main () mapped_region region (mapping, read_only, 0, FileSize/2, 0); mapped_region region2(mapping, read_only, FileSize/2, FileSize - FileSize/2, 0); - unsigned char *checker = (unsigned char*)region.get_address(); + unsigned char *checker = static_cast(region.get_address()); //Check pattern for(std::size_t i = 0 ;i < FileSize/2 @@ -79,7 +79,7 @@ int main () } //Check second half - checker = (unsigned char *)region2.get_address(); + checker = static_cast(region2.get_address()); //Check pattern for(std::size_t i = FileSize/2 From 96f9913aa8a55aa625c6509bcccad7c22d4946ca Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Sat, 1 Nov 2008 13:15:41 +0000 Subject: [PATCH 54/77] Continuing merge of CMake build system files into trunk with the encouragement of Doug Gregor [SVN r49510] --- CMakeLists.txt | 21 +++++++++++++++++++++ test/CMakeLists.txt | 5 +++++ 2 files changed, 26 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3859163 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +#---------------------------------------------------------------------------- +# This file was automatically generated from the original CMakeLists.txt file +# Add a variable to hold the headers for the library +set (lib_headers + interprocess +) + +# Add a library target to the build system +boost_library_project( + interprocess + # SRCDIRS + TESTDIRS test + HEADERS ${lib_headers} + # DOCDIRS + DESCRIPTION "Shared memory, memory mapped files, process-shared mutexes, condition variables, containers and allocators." + MODULARIZED + AUTHORS "Ion Gaztanaga " + # MAINTAINERS +) + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..82102d7 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,5 @@ +file(GLOB INTERPROCESS_TESTS *.cpp) +foreach(TEST ${INTERPROCESS_TESTS}) + get_filename_component(TEST ${TEST} NAME_WE) + boost_test_run(${TEST} DEPENDS boost_thread MULTI_THREADED) +endforeach() \ No newline at end of file From 74c8c4439251f5fd7d9e6f7e4ea9f93c3072cab1 Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Fri, 7 Nov 2008 17:02:56 +0000 Subject: [PATCH 55/77] Updating CMake files to latest trunk. Added dependency information for regression tests and a few new macros for internal use. [SVN r49627] --- test/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 82102d7..0d2011d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,6 @@ +boost_additional_test_dependencies(interprocess BOOST_DEPENDS test thread date_time multi_index) + + file(GLOB INTERPROCESS_TESTS *.cpp) foreach(TEST ${INTERPROCESS_TESTS}) get_filename_component(TEST ${TEST} NAME_WE) From c4be489f0f613c09ea18f14c6e26a64684ae7a67 Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Fri, 7 Nov 2008 17:05:27 +0000 Subject: [PATCH 56/77] Updating dependency information for modularized libraries. [SVN r49628] --- module.cmake | 1 + 1 file changed, 1 insertion(+) create mode 100644 module.cmake diff --git a/module.cmake b/module.cmake new file mode 100644 index 0000000..408603f --- /dev/null +++ b/module.cmake @@ -0,0 +1 @@ +boost_module(interprocess DEPENDS date_time intrusive math) \ No newline at end of file From 2b9761a341889962f7148eb11def00291edf1993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 22 Nov 2008 10:48:17 +0000 Subject: [PATCH 57/77] Fixed bug in optimized allocator insertion. Empty range insertion was not checked. [SVN r49871] --- include/boost/interprocess/containers/list.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index 9f74caa..b06e94e 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -1283,9 +1283,11 @@ class list void priv_create_and_insert_nodes (const_iterator pos, 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(), pos.get())); + 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 From 6ec4cd6987b4d51e38235695dd9ad2ed90b6fc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 22 Nov 2008 11:07:35 +0000 Subject: [PATCH 58/77] Fixed bug with empty ranges. [SVN r49872] --- .../containers/detail/node_alloc_holder.hpp | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index dbb5377..a4bc2b9 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -297,32 +297,34 @@ struct node_alloc_holder FwdIterator allocate_many_and_construct (FwdIterator beg, difference_type n, Inserter inserter) { - typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; + if(n){ + typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; - //Try to allocate memory in a single block - multiallocation_iterator itbeg = - this->node_alloc().allocate_individual(n), itend, itold; - int constructed = 0; - Node *p = 0; - BOOST_TRY{ - for(difference_type i = 0; i < n; ++i, ++beg, --constructed){ - p = &*itbeg; - ++itbeg; - //This can throw - boost::interprocess::construct_in_place(p, beg); - ++constructed; - //This can throw in some containers (predicate might throw) - inserter(*p); + //Try to allocate memory in a single block + multiallocation_iterator itbeg = + this->node_alloc().allocate_individual(n), itend, itold; + int constructed = 0; + Node *p = 0; + BOOST_TRY{ + for(difference_type i = 0; i < n; ++i, ++beg, --constructed){ + p = &*itbeg; + ++itbeg; + //This can throw + 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); + BOOST_CATCH(...){ + if(constructed){ + this->destroy(p); + } + this->node_alloc().deallocate_many(itbeg); + BOOST_RETHROW } - this->node_alloc().deallocate_many(itbeg); - BOOST_RETHROW + BOOST_CATCH_END } - BOOST_CATCH_END return beg; } From 7858e9f60a479154373ba306e54c469742bfb36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 22 Nov 2008 23:51:13 +0000 Subject: [PATCH 59/77] Fixed missing include in doc_named_mutex and removed superfluous cout in managed_mapped_file_test [SVN r49876] --- example/doc_named_mutex.cpp | 1 + test/managed_mapped_file_test.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/example/doc_named_mutex.cpp b/example/doc_named_mutex.cpp index 5f929bf..80e7f98 100644 --- a/example/doc_named_mutex.cpp +++ b/example/doc_named_mutex.cpp @@ -12,6 +12,7 @@ #include #include #include +#include int main () { diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index d68752b..5b394ba 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -42,7 +42,6 @@ int main () //Let's allocate some memory for(i = 0; i < max; ++i){ array[i] = mfile.allocate(i+1); - std::cout << i << ' '; } //Deallocate allocated memory From 43b0545a8a7b5ce55fb2ee2385599f5b96644a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 5 Dec 2008 22:57:51 +0000 Subject: [PATCH 60/77] ticket 2570: boost::interprocess::message_queue::timed_send and timed_receive bug [SVN r50146] --- include/boost/interprocess/ipc/message_queue.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index 5c049f8..a4260a9 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -465,8 +465,11 @@ inline bool message_queue::do_send(block_t block, case timed : do{ - if(!p_hdr->m_cond_send.timed_wait(lock, abs_time)) - return !p_hdr->is_full(); + 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; @@ -555,7 +558,9 @@ inline bool case timed : do{ if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time)) - return !p_hdr->is_empty(); + if(p_hdr->is_empty()) + return false; + break; } while (p_hdr->is_empty()); break; From 1a85096c535e8dfb5c5e9e69e5cf24c52dfcc23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 8 Dec 2008 16:27:11 +0000 Subject: [PATCH 61/77] Ticket #2570 again [SVN r50194] --- include/boost/interprocess/ipc/message_queue.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/interprocess/ipc/message_queue.hpp b/include/boost/interprocess/ipc/message_queue.hpp index a4260a9..bd3ee69 100644 --- a/include/boost/interprocess/ipc/message_queue.hpp +++ b/include/boost/interprocess/ipc/message_queue.hpp @@ -557,10 +557,11 @@ inline bool case timed : do{ - if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time)) + 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; From c1a6867856e64b354d25db6460fba4c90c8fd5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 13 Dec 2008 13:43:10 +0000 Subject: [PATCH 62/77] * Updated documentation to show rvalue-references funcions instead of emulation functions. * More non-copyable classes are now movable. * Move-constructor and assignments now leave moved object in default-constructed state instead of just swapping contents. * Several bugfixes (#2391, #2431, #1390, #2570, #2528). [SVN r50257] --- .../boost/interprocess/containers/deque.hpp | 71 +++++--- .../containers/detail/flat_tree.hpp | 14 +- .../containers/detail/node_alloc_holder.hpp | 9 +- .../interprocess/containers/detail/tree.hpp | 36 ++-- .../interprocess/containers/flat_map.hpp | 136 +++++++-------- .../interprocess/containers/flat_set.hpp | 100 +++++------ .../boost/interprocess/containers/list.hpp | 132 +++++++-------- include/boost/interprocess/containers/map.hpp | 160 +++++++----------- include/boost/interprocess/containers/set.hpp | 100 +++++------ .../boost/interprocess/containers/slist.hpp | 149 +++++++++------- .../boost/interprocess/containers/string.hpp | 79 +++++---- .../boost/interprocess/containers/vector.hpp | 74 ++++---- .../detail/os_thread_functions.hpp | 60 ++++++- .../boost/interprocess/detail/utilities.hpp | 18 +- include/boost/interprocess/file_mapping.hpp | 64 ++++--- .../interprocess/managed_external_buffer.hpp | 39 +++-- .../interprocess/managed_heap_memory.hpp | 34 ++-- .../interprocess/managed_mapped_file.hpp | 32 ++-- .../interprocess/managed_shared_memory.hpp | 34 ++-- .../managed_windows_shared_memory.hpp | 25 ++- include/boost/interprocess/mapped_region.hpp | 26 ++- .../interprocess/shared_memory_object.hpp | 17 +- .../interprocess/smart_ptr/shared_ptr.hpp | 4 +- .../interprocess/smart_ptr/unique_ptr.hpp | 10 +- .../interprocess_recursive_mutex.hpp | 18 +- include/boost/interprocess/sync/file_lock.hpp | 69 +++++++- .../sync/interprocess_recursive_mutex.hpp | 6 +- .../boost/interprocess/sync/lock_options.hpp | 20 +-- .../boost/interprocess/sync/scoped_lock.hpp | 29 ++-- .../boost/interprocess/sync/sharable_lock.hpp | 16 +- .../interprocess/sync/upgradable_lock.hpp | 20 +-- .../interprocess/windows_shared_memory.hpp | 11 +- 32 files changed, 874 insertions(+), 738 deletions(-) diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index c4661d2..e820596 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -215,6 +215,9 @@ class deque_base 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); } @@ -459,7 +462,7 @@ class deque_base 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(), m_finish(m_start) {} ptr_alloc_ptr m_map; @@ -610,11 +613,16 @@ class deque : protected deque_base {} deque(const deque& x) - : Base(x.alloc(), x.size()) - { std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start); } + : Base(x.alloc()) + { + if(x.size()){ + this->priv_initialize_map(x.size()); + std::uninitialized_copy(x.begin(), x.end(), this->members_.m_start); + } + } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - deque(const detail::moved_object &mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + deque(detail::moved_object mx) : Base(mx.get().alloc()) { this->swap(mx.get()); } #else @@ -661,8 +669,8 @@ class deque : protected deque_base return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - deque& operator= (const detail::moved_object &mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + deque& operator= (detail::moved_object mx) { deque &x = mx.get(); #else @@ -674,7 +682,9 @@ class deque : protected deque_base return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } void swap(deque& x) #else void swap(deque &&x) @@ -686,11 +696,6 @@ class deque : protected deque_base std::swap(this->members_.m_map_size, x.members_.m_map_size); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object &mx) - { this->swap(mx.get()); } - #endif - void assign(size_type n, const T& val) { this->priv_fill_assign(n, val); } @@ -714,8 +719,8 @@ class deque : protected deque_base } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void push_back(const detail::moved_object &mt) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void push_back(detail::moved_object mt) { value_type &t = mt.get(); #else @@ -742,8 +747,8 @@ class deque : protected deque_base } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void push_front(const detail::moved_object &mt) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void push_front(detail::moved_object mt) { value_type &t = mt.get(); #else @@ -796,8 +801,8 @@ class deque : protected deque_base } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator position, const detail::moved_object &m) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator position, detail::moved_object m) { value_type &mx = m.get(); #else @@ -1487,12 +1492,34 @@ inline bool operator>=(const deque& x, const deque& y) { return !(x < y); } -template -inline void swap(deque& x, deque& y) - { x.swap(y); } + +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +template +inline void swap(deque& x, deque& y) +{ x.swap(y); } + +template +inline void swap(detail::moved_object > x, deque& y) +{ x.get().swap(y); } + +template +inline void swap(deque &x, detail::moved_object > y) +{ x.swap(y.get()); } +#else +template +inline void swap(deque&&x, deque&&y) +{ x.swap(y); } +#endif /// @cond +//!This class is movable +template +struct is_movable > +{ + enum { value = true }; +}; + //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/detail/flat_tree.hpp index 76503b4..c2ebfc1 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/detail/flat_tree.hpp @@ -134,7 +134,7 @@ class flat_tree { } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree(const detail::moved_object &x) + flat_tree(detail::moved_object x) : m_data(detail::move_impl(x.get().m_data)) { } #else @@ -150,7 +150,7 @@ class flat_tree { m_data = x.m_data; return *this; } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree& operator=(const detail::moved_object& mx) + flat_tree& operator=(detail::moved_object mx) { m_data = detail::move_impl(mx.get().m_data); return *this; } #else flat_tree& operator=(flat_tree &&mx) @@ -227,7 +227,7 @@ class flat_tree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object& other) + void swap(detail::moved_object other) { this->swap(other.get()); } #else void swap(flat_tree &&other) @@ -247,7 +247,7 @@ class flat_tree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert_unique(const detail::moved_object& mval) + std::pair insert_unique(detail::moved_object mval) { value_type &val = mval.get(); #else @@ -271,7 +271,7 @@ class flat_tree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(const detail::moved_object& mval) + iterator insert_equal(detail::moved_object mval) { iterator i = this->upper_bound(KeyOfValue()(mval.get())); i = this->m_data.m_vect.insert(i, mval); @@ -297,7 +297,7 @@ class flat_tree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_unique(const_iterator pos, const detail::moved_object& mval) + iterator insert_unique(const_iterator pos, detail::moved_object mval) { insert_commit_data data; std::pair ret = priv_insert_unique_prepare(pos, mval.get(), data); @@ -326,7 +326,7 @@ class flat_tree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(const_iterator pos, const detail::moved_object& mval) + iterator insert_equal(const_iterator pos, detail::moved_object mval) { insert_commit_data data; priv_insert_equal_prepare(pos, mval.get(), data); diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp index a4bc2b9..6e88903 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/detail/node_alloc_holder.hpp @@ -87,7 +87,7 @@ struct node_alloc_holder {} #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - node_alloc_holder(const detail::moved_object &other) + node_alloc_holder(detail::moved_object other) : members_(detail::move_impl(other.get().node_alloc())) { this->swap(other.get()); } #else @@ -103,7 +103,7 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - node_alloc_holder(const detail::moved_object &a, const Pred &c) + node_alloc_holder(detail::moved_object a, const Pred &c) : members_(a.get(), typename ICont::value_compare(c)) {} #else @@ -119,7 +119,7 @@ struct node_alloc_holder {} ~node_alloc_holder() - {} + { this->clear(alloc_version()); } size_type max_size() const { return this->node_alloc().max_size(); } @@ -144,7 +144,7 @@ struct node_alloc_holder #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - static void construct(const NodePtr &ptr, const detail::moved_object > &value) + static void construct(const NodePtr &ptr, detail::moved_object > value) { typedef typename Node::hook_type hook_type; typedef typename Node::value_type::first_type first_type; @@ -326,6 +326,7 @@ struct node_alloc_holder BOOST_CATCH_END } return beg; + } void clear(allocator_v1) diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/detail/tree.hpp index 7ede6b1..408ce3d 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/detail/tree.hpp @@ -451,7 +451,7 @@ class rbtree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree(const detail::moved_object& x) + rbtree(detail::moved_object x) : AllocHolder(x.get(), x.get().key_comp()) { this->swap(x.get()); } #else @@ -461,7 +461,7 @@ class rbtree #endif ~rbtree() - { this->clear(); } + {} //AllocHolder clears the tree rbtree& operator=(const rbtree& x) { @@ -489,7 +489,7 @@ class rbtree } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree& operator=(const detail::moved_object& mx) + rbtree& operator=(detail::moved_object mx) { this->clear(); this->swap(mx.get()); return *this; } #else rbtree& operator=(rbtree &&mx) @@ -584,7 +584,7 @@ class rbtree { AllocHolder::swap(x); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object& mt) + void swap(detail::moved_object mt) { this->swap(mt.get()); } #else void swap(rbtree &&mt) @@ -622,7 +622,7 @@ class rbtree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator insert_unique_commit - (const detail::moved_object& mv, insert_commit_data &data) + (detail::moved_object mv, insert_commit_data &data) { NodePtr tmp = AllocHolder::create_node(mv); iiterator it(this->icont().insert_unique_commit(*tmp, data)); @@ -652,8 +652,7 @@ class rbtree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - std::pair insert_unique - (const detail::moved_object& mv) + std::pair insert_unique(detail::moved_object mv) { insert_commit_data data; std::pair ret = @@ -796,8 +795,7 @@ class rbtree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_unique - (const_iterator hint, const detail::moved_object &mv) + iterator insert_unique(const_iterator hint, detail::moved_object mv) { insert_commit_data data; std::pair ret = @@ -844,7 +842,7 @@ class rbtree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(const detail::moved_object &mv) + iterator insert_equal(detail::moved_object mv) { NodePtr p(AllocHolder::create_node(mv)); return iterator(this->icont().insert_equal(this->icont().end(), *p)); @@ -866,7 +864,7 @@ class rbtree #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(const_iterator hint, const detail::moved_object &mv) + iterator insert_equal(const_iterator hint, detail::moved_object mv) { NodePtr p(AllocHolder::create_node(mv)); return iterator(this->icont().insert_equal(hint.get(), *p)); @@ -993,13 +991,15 @@ class rbtree void priv_create_and_insert_nodes (FwdIterator beg, FwdIterator end, bool unique, allocator_v2, std::forward_iterator_tag) { - 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())); + 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())); + } } } }; diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 62fab5e..3649906 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -171,8 +172,8 @@ class flat_map //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_map(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_map(detail::moved_object > x) : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} #else @@ -192,8 +193,8 @@ class flat_map //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_map& operator=(const detail::moved_object >& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_map& operator=(detail::moved_object > mx) { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_map& operator=(flat_map && mx) @@ -353,13 +354,6 @@ class flat_map 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(detail::move_impl(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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE //! Effects: If there is no key equivalent to x in the flat_map, inserts //! value_type(x, T()) into the flat_map. //! @@ -375,7 +369,14 @@ class flat_map return (*i).second; } - T &operator[](const detail::moved_object& mk) + //! 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + T &operator[](detail::moved_object mk) { key_type &k = mk.get(); iterator i = lower_bound(k); @@ -385,12 +386,6 @@ class flat_map return (*i).second; } #else - //! 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[](key_type &&mk) { key_type &k = mk; @@ -402,14 +397,29 @@ class flat_map } #endif - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - void swap(flat_map& x) - { m_flat_tree.swap(x.m_flat_tree); } + //! 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; + } //! Effects: Swaps the contents of *this and x. //! If this->allocator_type() != x.allocator_type() allocators are also swapped. @@ -417,13 +427,14 @@ class flat_map //! Throws: Nothing. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& x) - { m_flat_tree.swap(x.get().m_flat_tree); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(flat_map& x) #else - void swap(flat_map && x) - { m_flat_tree.swap(x.m_flat_tree); } + void swap(flat_map &&x) #endif + { m_flat_tree.swap(x.m_flat_tree); } //! Effects: Inserts x if and only if there is no element in the container //! with key equivalent to the key of x. @@ -451,8 +462,8 @@ class flat_map //! to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + std::pair insert(detail::moved_object x) { return force >( m_flat_tree.insert_unique(force(x))); } #else @@ -485,8 +496,8 @@ class flat_map //! right before p) plus insertion linear to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator position, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator position, detail::moved_object x) { return force_copy( m_flat_tree.insert_unique(force(position), force(x))); } #else @@ -742,20 +753,20 @@ inline bool operator>=(const flat_map& x, const flat_map& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template inline void swap(flat_map& x, flat_map& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, +inline void swap(detail::moved_object > x, flat_map& y) { x.get().swap(y); } template inline void swap(flat_map& x, - const detail::moved_object >& y) + detail::moved_object > y) { x.swap(y.get()); } #else template @@ -916,8 +927,8 @@ class flat_multimap //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_multimap(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_multimap(detail::moved_object > x) : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) { } #else flat_multimap(flat_multimap && x) @@ -927,20 +938,17 @@ class flat_multimap //! Effects: Makes *this a copy of x. //! //! Complexity: Linear in x.size(). - flat_multimap& - operator=(const flat_multimap& x) + flat_multimap& operator=(const flat_multimap& x) { m_flat_tree = x.m_flat_tree; return *this; } //! Effects: this->swap(x.get()). //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_multimap& - operator=(const detail::moved_object >& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_multimap& operator=(detail::moved_object > mx) { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else - flat_multimap& - operator=(flat_multimap && mx) + flat_multimap& operator=(flat_multimap && mx) { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } #endif @@ -1069,22 +1077,14 @@ class flat_multimap //! Throws: Nothing. //! //! Complexity: Constant. - void swap(flat_multimap& x) - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& x) - { m_flat_tree.swap(x.get().m_flat_tree); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(flat_multimap& x) #else - void swap(flat_multimap && x) - { m_flat_tree.swap(x.m_flat_tree); } + void swap(flat_multimap &&x) #endif + { m_flat_tree.swap(x.m_flat_tree); } //! Effects: Inserts x and returns the iterator pointing to the //! newly inserted element. @@ -1103,8 +1103,8 @@ class flat_multimap //! to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(detail::moved_object x) { return force_copy(m_flat_tree.insert_equal(force(x))); } #else iterator insert(value_type &&x) @@ -1136,8 +1136,8 @@ class flat_multimap //! to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator position, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator position, detail::moved_object x) { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } #else iterator insert(const_iterator position, value_type &&x) @@ -1391,21 +1391,21 @@ inline bool operator>=(const flat_multimap& x, const flat_multimap& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template inline void swap(flat_multimap& x, flat_multimap& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, +inline void swap(detail::moved_object > x, flat_multimap& y) { x.get().swap(y); } template inline void swap(flat_multimap& x, - const detail::moved_object > & y) + detail::moved_object > y) { x.swap(y.get()); } #else template diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index 9c2cb9e..1e3c9bf 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -115,8 +115,8 @@ class flat_set //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_set(const detail::moved_object >& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_set(detail::moved_object > mx) : m_flat_tree(detail::move_impl(mx.get().m_flat_tree)) {} #else flat_set(flat_set && mx) @@ -132,8 +132,8 @@ class flat_set //! Effects: Makes *this a copy of x. //! //! Complexity: Linear in x.size(). - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_set& operator=(const detail::moved_object > &mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_set& operator=(detail::moved_object > mx) { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else @@ -301,22 +301,14 @@ class flat_set //! Throws: Nothing. //! //! Complexity: Constant. - void swap(flat_set& x) - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& mx) - { this->swap(mx.get()); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(flat_set& x) #else - void swap(flat_set && mx) - { this->swap(mx); } + void swap(flat_set &&x) #endif + { m_flat_tree.swap(x.m_flat_tree); } //! Effects: Inserts x if and only if there is no element in the container //! with key equivalent to the key of x. @@ -343,8 +335,8 @@ class flat_set //! to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + std::pair insert(detail::moved_object x) { return m_flat_tree.insert_unique(x); } #else std::pair insert(value_type && x) @@ -374,8 +366,8 @@ class flat_set //! right before p) plus insertion linear to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator position, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator position, detail::moved_object x) { return m_flat_tree.insert_unique(position, x); } #else iterator insert(const_iterator position, value_type && x) @@ -623,25 +615,21 @@ inline bool operator>=(const flat_set& x, const flat_set& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template -inline void swap(flat_set& x, - flat_set& y) +inline void swap(flat_set& x, flat_set& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, - flat_set& y) +inline void swap(detail::moved_object > x, flat_set& y) { x.get().swap(y); } template -inline void swap(flat_set& x, - const detail::moved_object >& y) +inline void swap(flat_set& x, detail::moved_object > y) { x.swap(y.get()); } #else template -inline void swap(flat_set&&x, - flat_set&&y) +inline void swap(flat_set&&x, flat_set&&y) { x.swap(y); } #endif @@ -732,8 +720,8 @@ class flat_multiset flat_multiset(const flat_multiset& x) : m_flat_tree(x.m_flat_tree) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_multiset(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_multiset(detail::moved_object > x) : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} #else flat_multiset(flat_multiset && x) @@ -743,8 +731,8 @@ class flat_multiset flat_multiset& operator=(const flat_multiset& x) { m_flat_tree = x.m_flat_tree; return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_multiset& operator=(const detail::moved_object >& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + flat_multiset& operator=(detail::moved_object > mx) { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } #else flat_multiset& operator=(flat_multiset && mx) @@ -910,22 +898,14 @@ class flat_multiset //! Throws: Nothing. //! //! Complexity: Constant. - void swap(flat_multiset& x) - { m_flat_tree.swap(x.m_flat_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& mx) - { this->swap(mx.get()); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(flat_multiset& x) #else - void swap(flat_multiset && mx) - { this->swap(mx); } + void swap(flat_multiset &&x) #endif + { m_flat_tree.swap(x.m_flat_tree); } //! Effects: Inserts x and returns the iterator pointing to the //! newly inserted element. @@ -944,8 +924,8 @@ class flat_multiset //! to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(detail::moved_object x) { return m_flat_tree.insert_equal(x); } #else iterator insert(value_type && x) @@ -975,8 +955,8 @@ class flat_multiset //! right before p) plus insertion linear to the elements with bigger keys than x. //! //! Note: If an element it's inserted it might invalidate elements. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator position, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator position, detail::moved_object x) { return m_flat_tree.insert_equal(position, x); } #else iterator insert(const_iterator position, value_type && x) @@ -1219,25 +1199,21 @@ inline bool operator>=(const flat_multiset& x, const flat_multiset& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template -inline void swap(flat_multiset& x, - flat_multiset& y) +inline void swap(flat_multiset& x, flat_multiset& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, - flat_multiset& y) +inline void swap(detail::moved_object > x, flat_multiset& y) { x.get().swap(y); } template -inline void swap(flat_multiset& x, - const detail::moved_object >& y) +inline void swap(flat_multiset& x, detail::moved_object > y) { x.swap(y.get()); } #else template -inline void swap(flat_multiset&&x, - flat_multiset&&y) +inline void swap(flat_multiset&&x, flat_multiset&&y) { x.swap(y); } #endif diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index b06e94e..9f17f5f 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -153,9 +153,9 @@ class list /// @cond typedef typename detail::intrusive_list_type::type Icont; + typedef list ThisType; typedef detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; - typedef list ThisType; typedef typename AllocHolder::NodeAlloc NodeAlloc; typedef typename AllocHolder::ValAlloc ValAlloc; typedef typename AllocHolder::Node Node; @@ -365,11 +365,11 @@ class list //! Effects: Move constructor. Moves mx's resources to *this. //! - //! Throws: If allocator_type's default constructor throws. + //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - list(const detail::moved_object &x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + list(detail::moved_object x) : AllocHolder(detail::move_impl((AllocHolder&)x.get())) {} #else @@ -396,8 +396,8 @@ class list //! Throws: Nothing. //! //! Complexity: Linear to the number of elements. - ~list() - { this->clear(); } + ~list() + {} //AllocHolder clears the list //! Effects: Returns a copy of the internal allocator. //! @@ -562,8 +562,8 @@ class list //! Throws: If memory allocation throws. //! //! Complexity: Amortized constant time. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void push_front(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void push_front(detail::moved_object x) { this->insert(this->cbegin(), x); } #else void push_front(T &&x) @@ -583,8 +583,8 @@ class list //! Throws: Nothing. //! //! Complexity: Amortized constant time. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void push_back (const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void push_back (detail::moved_object x) { this->insert(this->cend(), x); } #else void push_back (T &&x) @@ -715,19 +715,15 @@ class list //! Throws: Nothing. //! //! Complexity: Constant. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } void swap(ThisType& x) + #else + void swap(ThisType &&x) + #endif { AllocHolder::swap(x); } - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //void swap(const detail::moved_object& x) - //{ this->swap(x.get()); } - //! Effects: Makes *this contain the same elements as x. //! //! Postcondition: this->size() == x.size(). *this contains a copy @@ -752,8 +748,8 @@ class list //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - ThisType& operator=(const detail::moved_object& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + ThisType& operator=(detail::moved_object mx) { this->clear(); this->swap(mx.get()); @@ -814,8 +810,8 @@ class list //! Throws: If memory allocation throws. //! //! Complexity: Amortized constant time. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator p, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator p, detail::moved_object x) { NodePtr tmp = AllocHolder::create_node(x); return iterator(this->icont().insert(p.get(), *tmp)); @@ -973,7 +969,13 @@ class list //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(iterator p, detail::moved_object 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()); @@ -983,9 +985,6 @@ class list } } -// void splice(iterator p, const detail::moved_object& x) -// { this->splice(p, x.get()); } - //! Requires: p must point to an element contained //! by this list. i must point to an element contained in list x. //! @@ -1000,7 +999,13 @@ class list //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(const_iterator p, detail::moved_object 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()); @@ -1010,9 +1015,6 @@ class list } } -// void splice(const_iterator p, const detail::moved_object &x, const_iterator i) -// { this->splice(p, x.get(), i); } - //! Requires: p must point to an element contained //! by this list. first and last must point to elements contained in list x. //! @@ -1026,7 +1028,13 @@ class list //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(const_iterator p, detail::moved_object 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()); @@ -1036,9 +1044,6 @@ class list } } -// void splice(const_iterator p, detail::moved_object &x, const_iterator first, const_iterator last) -// { return this->splice(p, x.get(), first, last); } - //! Requires: 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) @@ -1053,7 +1058,13 @@ class list //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(const_iterator p, detail::moved_object 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); @@ -1063,9 +1074,6 @@ class list } } -// void splice(const_iterator p, detail::moved_object &x, const_iterator first, const_iterator last, size_type n) -// { return this->splice(p, x.get(), first, last, n); } - //! Effects: Reverses the order of elements in the list. //! //! Throws: Nothing. @@ -1142,23 +1150,15 @@ class list //! //! Complexity: This function is linear time: it performs at most //! size() + x.size() - 1 comparisons. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void merge(detail::moved_object > x) + { this->merge(x.get()); } void merge(list& x) + #else + void merge(list&& x) + #endif { this->merge(x, value_less()); } - //! Effects: This function removes all of moved mx's elements and inserts them - //! in order into *this according to std::less. 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. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - //void merge(const detail::moved_object >& x) - //{ this->merge(x.get()); } - //! Requires: 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. @@ -1173,8 +1173,16 @@ class list //! size() + x.size() - 1 comparisons. //! //! Note: Iterators and references to *this are not invalidated. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + template + void merge(detail::moved_object > x, StrictWeakOrdering comp) + { this->merge(x.get(), comp); } template void merge(list& x, StrictWeakOrdering comp) + #else + template + void merge(list&& x, StrictWeakOrdering comp) + #endif { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().merge(x.icont(), @@ -1185,24 +1193,6 @@ class list } } - //! Requires: 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. - //! - //! Effects: This function removes all of moved mx'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. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - //template - //void merge(const detail::moved_object >& x, StrictWeakOrdering comp) - //{ return this->merge(x.get(), comp); } - //! Effects: This function sorts the list *this according to std::less. //! The sort is stable, that is, the relative order of equivalent elements is preserved. //! @@ -1412,7 +1402,7 @@ inline bool operator>=(const list& x, const list& y) return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template inline void swap(list& x, list& y) { @@ -1420,13 +1410,13 @@ inline void swap(list& x, list& y) } template -inline void swap(const detail::moved_object >& x, list& y) +inline void swap(detail::moved_object >& x, list y) { x.get().swap(y); } template -inline void swap(list& x, const detail::moved_object >& y) +inline void swap(list& x, detail::moved_object > y) { x.swap(y.get()); } diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index b793cc0..2d7f1a3 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -164,8 +165,8 @@ class map //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - map(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + map(detail::moved_object > x) : m_tree(detail::move_impl(x.get().m_tree)) {} #else @@ -183,8 +184,8 @@ class map //! Effects: this->swap(x.get()). //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - map& operator=(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + map& operator=(detail::moved_object > x) { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else map& operator=(map &&x) @@ -334,8 +335,8 @@ class map //! Returns: A reference to the mapped_type corresponding to x in *this. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - T& operator[](const detail::moved_object& mk) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + T& operator[](detail::moved_object mk) { key_type &k = mk.get(); //we can optimize this @@ -362,34 +363,29 @@ class map } #endif -/* - //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(detail::move_impl(x), T()) into the map (the key is move-constructed) - //! - //! Returns: A reference to the mapped_type corresponding to x in *this. - //! - //! Complexity: Logarithmic. - T& at(const key_type& x) + //! 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) { - if(this->find(x) == this->end()){ - + iterator i = this->find(k); + if(i == this->end()){ + throw std::out_of_range("key not found"); } - 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, detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; + return i->second; } -//; -//const T& at(const key_type& x) const; -//4 Returns: A reference to the element whose key is equivalent to x. -//5 Throws: An exception object of type out_of_range if no such element is present. -*/ + //! 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; + } //! Effects: Swaps the contents of *this and x. //! If this->allocator_type() != x.allocator_type() allocators are also swapped. @@ -397,22 +393,14 @@ class map //! Throws: Nothing. //! //! Complexity: Constant. - void swap(map& x) - { m_tree.swap(x.m_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& x) - { m_tree.swap(x.get().m_tree); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(map& x) #else - void swap(map &&x) - { m_tree.swap(x.m_tree); } + void swap(map &&x) #endif + { m_tree.swap(x.m_tree); } //! Effects: Inserts x if and only if there is no element in the container //! with key equivalent to the key of x. @@ -444,8 +432,8 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert(const detail::moved_object > &x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + std::pair insert(detail::moved_object > x) { return m_tree.insert_unique(x); } #else std::pair insert(std::pair &&x) @@ -460,8 +448,8 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + std::pair insert(detail::moved_object x) { return m_tree.insert_unique(x); } #else std::pair insert(value_type &&x) @@ -489,8 +477,8 @@ class map //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object > &x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(iterator position, detail::moved_object > x) { return m_tree.insert_unique(position, x); } #else iterator insert(iterator position, std::pair &&x) @@ -512,8 +500,8 @@ class map //! Returns: An iterator pointing to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(iterator position, detail::moved_object x) { return m_tree.insert_unique(position, x); } #else iterator insert(iterator position, value_type &&x) @@ -716,25 +704,21 @@ inline bool operator>=(const map& x, const map& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template -inline void swap(map& x, - map& y) +inline void swap(map& x, map& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, - map& y) +inline void swap(detail::moved_object > x, map& y) { x.get().swap(y); } template -inline void swap(map& x, - const detail::moved_object >& y) +inline void swap(map& x, detail::moved_object > y) { x.swap(y.get()); } #else template -inline void swap(map&&x, - map&&y) +inline void swap(map&&x, map&&y) { x.swap(y); } #endif @@ -863,8 +847,8 @@ class multimap //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - multimap(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + multimap(detail::moved_object > x) : m_tree(detail::move_impl(x.get().m_tree)) {} #else @@ -883,13 +867,11 @@ class multimap //! Effects: this->swap(x.get()). //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - multimap& - operator=(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + multimap& operator=(detail::moved_object > x) { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else - multimap& - operator=(multimap && x) + multimap& operator=(multimap && x) { m_tree = detail::move_impl(x.m_tree); return *this; } #endif @@ -1018,22 +1000,14 @@ class multimap //! Throws: Nothing. //! //! Complexity: Constant. - void swap(multimap& x) - { m_tree.swap(x.m_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& x) - { m_tree.swap(x.get().m_tree); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(multimap& x) #else - void swap(multimap && x) - { m_tree.swap(x.m_tree); } + void swap(multimap &&x) #endif + { m_tree.swap(x.m_tree); } //! Effects: Inserts x and returns the iterator pointing to the //! newly inserted element. @@ -1053,8 +1027,8 @@ class multimap //! the iterator pointing to the newly inserted element. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(detail::moved_object > x) { return m_tree.insert_equal(x); } #else iterator insert(std::pair && x) @@ -1091,8 +1065,8 @@ class multimap //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(iterator position, const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(iterator position, detail::moved_object > x) { return m_tree.insert_equal(position, x); } #else iterator insert(iterator position, std::pair && x) @@ -1295,25 +1269,21 @@ inline bool operator>=(const multimap& x, { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template -inline void swap(multimap& x, - multimap& y) +inline void swap(multimap& x, multimap& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, - multimap& y) +inline void swap(detail::moved_object > x, multimap& y) { x.get().swap(y); } template -inline void swap(multimap& x, - const detail::moved_object >& y) +inline void swap(multimap& x, detail::moved_object > y) { x.swap(y.get()); } #else template -inline void swap(multimap&&x, - multimap&&y) +inline void swap(multimap&&x, multimap&&y) { x.swap(y); } #endif diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index a3aec9d..0908116 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -144,8 +144,8 @@ class set //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - set(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + set(detail::moved_object > x) : m_tree(detail::move_impl(x.get().m_tree)) {} #else @@ -163,8 +163,8 @@ class set //! Effects: this->swap(x.get()). //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - set& operator=(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + set& operator=(detail::moved_object > x) { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else set& operator=(set &&x) @@ -330,22 +330,14 @@ class set //! Throws: Nothing. //! //! Complexity: Constant. - void swap(set& x) - { m_tree.swap(x.m_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& x) - { m_tree.swap(x.get().m_tree); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(set& x) #else - void swap(set &&x) - { m_tree.swap(x.m_tree); } + void swap(set &&x) #endif + { m_tree.swap(x.m_tree); } //! Effects: Inserts x if and only if there is no element in the container //! with key equivalent to the key of x. @@ -366,8 +358,8 @@ class set //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + std::pair insert(detail::moved_object x) { return m_tree.insert_unique(x); } #else std::pair insert(value_type &&x) @@ -392,8 +384,8 @@ class set //! Returns: An iterator pointing to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator p, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator p, detail::moved_object x) { return m_tree.insert_unique(p, x); } #else iterator insert(const_iterator p, value_type &&x) @@ -596,26 +588,22 @@ inline bool operator>=(const set& x, const set& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template -inline void swap(set& x, - set& y) +inline void swap(set& x, set& y) { x.swap(y); } template -inline void swap(set& x, - detail::moved_object >& y) +inline void swap(set& x, detail::moved_object >& y) { x.swap(y.get()); } template -inline void swap(detail::moved_object >& y, - set& x) +inline void swap(detail::moved_object >& y, set& x) { y.swap(x.get()); } #else template -inline void swap(set&&x, - set&&y) +inline void swap(set&&x, set&&y) { x.swap(y); } #endif @@ -718,8 +706,8 @@ class multiset //! Complexity: Construct. //! //! Postcondition: x is emptied. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - multiset(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + multiset(detail::moved_object > x) : m_tree(detail::move_impl(x.get().m_tree)) {} #else @@ -737,8 +725,8 @@ class multiset //! Effects: this->swap(x.get()). //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - multiset& operator=(const detail::moved_object >& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + multiset& operator=(detail::moved_object > x) { m_tree = detail::move_impl(x.get().m_tree); return *this; } #else multiset& operator=(multiset &&x) @@ -904,22 +892,14 @@ class multiset //! Throws: Nothing. //! //! Complexity: Constant. - void swap(multiset& x) - { m_tree.swap(x.m_tree); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object >& x) - { m_tree.swap(x.get().m_tree); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(multiset& x) #else - void swap(multiset && x) - { m_tree.swap(x.m_tree); } + void swap(multiset &&x) #endif + { m_tree.swap(x.m_tree); } //! Effects: Inserts x and returns the iterator pointing to the //! newly inserted element. @@ -935,8 +915,8 @@ class multiset //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(detail::moved_object x) { return m_tree.insert_equal(x); } #else iterator insert(value_type && x) @@ -962,8 +942,8 @@ class multiset //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator p, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator p, detail::moved_object x) { return m_tree.insert_equal(p, x); } #else iterator insert(const_iterator p, value_type && x) @@ -1160,25 +1140,21 @@ inline bool operator>=(const multiset& x, const multiset& y) { return !(x < y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template -inline void swap(multiset& x, - multiset& y) +inline void swap(multiset& x, multiset& y) { x.swap(y); } template -inline void swap(multiset& x, - detail::moved_object >& y) +inline void swap(multiset& x, detail::moved_object >& y) { x.swap(y.get()); } template -inline void swap(detail::moved_object >& y, - multiset& x) +inline void swap(detail::moved_object >& y, multiset& x) { y.swap(x.get()); } #else template -inline void swap(multiset&&x, - multiset&&y) +inline void swap(multiset&&x, multiset&&y) { x.swap(y); } #endif diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 2082b0e..4b0728d 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -178,7 +178,7 @@ class slist detail::intrusive_slist_type::type Icont; typedef detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; - typedef list ThisType; + typedef slist ThisType; typedef typename AllocHolder::NodeAlloc NodeAlloc; typedef typename AllocHolder::ValAlloc ValAlloc; typedef typename AllocHolder::Node Node; @@ -384,11 +384,11 @@ class slist //! Effects: Move constructor. Moves mx's resources to *this. //! - //! Throws: If allocator_type's default constructor throws. + //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - slist(const detail::moved_object &x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + slist(detail::moved_object x) : AllocHolder(detail::move_impl((AllocHolder&)x.get())) {} #else @@ -421,8 +421,8 @@ class slist //! Throws: If memory allocation throws or T's copy constructor throws. //! //! Complexity: Linear to the number of elements in x. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - slist& operator= (const detail::moved_object& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + slist& operator= (detail::moved_object mx) { if (&mx.get() != this){ this->clear(); @@ -448,7 +448,7 @@ class slist //! //! Complexity: Linear to the number of elements. ~slist() - { this->clear(); } + {} //AllocHolder clears the slist //! Effects: Returns a copy of the internal allocator. //! @@ -597,7 +597,13 @@ class slist //! Throws: Nothing. //! //! Complexity: Linear to the number of elements on *this and x. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } void swap(slist& x) + #else + void swap(slist &&x) + #endif { AllocHolder::swap(x); } //! Requires: !empty() @@ -637,8 +643,8 @@ class slist //! Throws: If memory allocation throws. //! //! Complexity: Amortized constant time. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void push_front(const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void push_front(detail::moved_object x) { this->icont().push_front(*this->create_node(x)); } #else void push_front(T && x) @@ -702,8 +708,8 @@ class slist //! //! Note: Does not affect the validity of iterators and references of //! previous values. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_after(const_iterator prev_pos, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert_after(const_iterator prev_pos, detail::moved_object 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) @@ -760,8 +766,8 @@ class slist //! Throws: If memory allocation throws. //! //! Complexity: Linear to the elements before p. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator p, const detail::moved_object& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator p, detail::moved_object x) { return this->insert_after(previous(p), x); } #else iterator insert(const_iterator p, value_type && x) @@ -1000,7 +1006,13 @@ class slist //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice_after(const_iterator prev_pos, detail::moved_object 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()); @@ -1010,12 +1022,6 @@ class slist } } - //void splice_after(const_iterator prev_pos, const detail::moved_object& x) - //{ this->splice_after(prev_pos, x.get()); } - - // Moves the element that follows prev to *this, inserting it immediately - // after p. This is constant time. - //! Requires: prev_pos must be a valid iterator of this. //! i must point to an element contained in list x. //! @@ -1030,7 +1036,13 @@ class slist //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice_after(const_iterator prev_pos, detail::moved_object 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()); @@ -1040,13 +1052,6 @@ class slist } } - //void splice_after(const_iterator prev_pos, const detail::moved_object& x, iterator prev) - //{ return splice_after(prev_pos, x.get(), prev); } - - // Moves the range [before_first + 1, before_last + 1) to *this, - // inserting it immediately after p. This is constant time. - - //! Requires: 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. @@ -1061,8 +1066,16 @@ class slist //! //! Note: 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. - void splice_after(const_iterator prev_pos, slist& x, + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice_after(const_iterator prev_pos, detail::moved_object 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 @@ -1073,10 +1086,6 @@ class slist } } - //void splice_after(const_iterator prev_pos, const detail::moved_object& x, - // const_iterator before_first, const_iterator before_last) - //{ this->splice_after(prev_pos, x.get(), before_first, before_last); } - //! Requires: 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. @@ -1092,9 +1101,19 @@ class slist //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice_after(const_iterator prev_pos, detail::moved_object 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 @@ -1105,10 +1124,6 @@ class slist } } - //void splice_after(const_iterator prev_pos, const detail::moved_object& x, - // const_iterator before_first, const_iterator before_last, size_type n) - //{ this->splice_after(prev_pos, x.get(), before_first, before_last, n); } - //! Requires: p must point to an element contained //! by the list. x != *this //! @@ -1122,12 +1137,15 @@ class slist //! //! Note: 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. - void splice(const_iterator p, slist& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(const_iterator p, detail::moved_object 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); } - //void splice(const_iterator p, const detail::moved_object& x) - //{ return this->splice(p, x.get()); } - //! Requires: p must point to an element contained //! by this list. i must point to an element contained in list x. //! @@ -1142,12 +1160,15 @@ class slist //! //! Note: 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. - void splice(const_iterator p, slist& x, const_iterator i) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(const_iterator p, detail::moved_object 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); } - //void splice(const_iterator p, const detail::moved_object& x, const_iterator i) - //{ this->splice(p, x.get(), i); } - //! Requires: p must point to an element contained //! by this list. first and last must point to elements contained in list x. //! @@ -1162,12 +1183,15 @@ class slist //! //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void splice(const_iterator p, detail::moved_object 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)); } - //void splice(const_iterator p, const detail::moved_object& x, const_iterator first, const_iterator last) - //{ this->splice(p, x.get(), first, last); } - //! Effects: Reverses the order of elements in the list. //! //! Throws: Nothing. @@ -1244,12 +1268,15 @@ class slist //! //! Complexity: This function is linear time: it performs at most //! size() + x.size() - 1 comparisons. - void merge(slist& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void merge(detail::moved_object > x) + { this->merge(x.get()); } + void merge(slist& x) + #else + void merge(slist&& x) + #endif { this->merge(x, value_less()); } - //void merge(const detail::moved_object& x) - //{ this->merge(x.get(), value_less()); } - //! Requires: 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. @@ -1264,8 +1291,16 @@ class slist //! size() + x.size() - 1 comparisons. //! //! Note: Iterators and references to *this are not invalidated. - template - void merge(slist& x, StrictWeakOrdering comp) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + template + void merge(detail::moved_object > x, StrictWeakOrdering comp) + { this->merge(x.get(), comp); } + template + void merge(slist& x, StrictWeakOrdering comp) + #else + template + void merge(slist&& x, StrictWeakOrdering comp) + #endif { if((NodeAlloc&)*this == (NodeAlloc&)x){ this->icont().merge(x.icont(), @@ -1276,10 +1311,6 @@ class slist } } - //template - //void merge(const detail::moved_object& x, StrictWeakOrdering comp) - //{ this->merge(x.get(), comp); } - //! Effects: This function sorts the list *this according to std::less. //! The sort is stable, that is, the relative order of equivalent elements is preserved. //! @@ -1509,17 +1540,17 @@ inline bool operator>=(const slist& sL1, const slist& sL2) { return !(sL1 < sL2); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template inline void swap(slist& x, slist& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, slist& y) +inline void swap(detail::moved_object > x, slist& y) { x.get().swap(y); } template -inline void swap(slist& x, const detail::moved_object >& y) +inline void swap(slist& x, detail::moved_object > y) { x.swap(y.get()); } #else template diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index b0666a4..4410423 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -98,8 +98,8 @@ class basic_string_base this->allocate_initial_block(n); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_string_base(const detail::moved_object >& b) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) + basic_string_base(detail::moved_object > b) : members_(b.get().members_) { init(); @@ -380,7 +380,13 @@ class basic_string_base this->members_.m_repr.long_repr().length = static_cast(sz); } - void swap(basic_string_base& other) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object 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()){ @@ -552,8 +558,8 @@ class basic_string //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_string(const detail::moved_object& s) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_string(detail::moved_object s) : base_t(detail::move_impl((base_t&)s.get())) {} #else @@ -637,8 +643,8 @@ class basic_string //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_string& operator=(const detail::moved_object& ms) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_string& operator=(detail::moved_object ms) { basic_string &s = ms.get(); if (&s != this){ @@ -965,8 +971,8 @@ class basic_string { return this->operator=(s); } //! Effects: Moves the resources from ms *this. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_string& assign(const detail::moved_object& ms) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_string& assign(detail::moved_object ms) { return this->operator=(ms);} #else basic_string& assign(basic_string && ms) @@ -1259,17 +1265,14 @@ class basic_string } //! Effects: Swaps the contents of two strings. - void swap(basic_string& s) - { base_t::swap(s); } - - //! Effects: Swaps the contents of two strings. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object& ms) - { this->swap(ms.get()); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(basic_string& x) #else - void swap(basic_string && ms) - { this->swap(ms); } + void swap(basic_string &&x) #endif + { base_t::swap(x); } //! Returns: Returns a pointer to a null-terminated array of characters //! representing the string's contents. For any string s it is guaranteed @@ -1930,7 +1933,7 @@ operator+(const basic_string& x, #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template inline detail::moved_object > -operator+(const detail::moved_object >& mx, +operator+(detail::moved_object > mx, const basic_string& y) { mx.get() += y; @@ -1951,7 +1954,7 @@ operator+(basic_string && mx, template inline detail::moved_object > operator+(const basic_string& x, - const detail::moved_object >& my) + detail::moved_object > my) { typedef typename basic_string::size_type size_type; return my.get().replace(size_type(0), size_type(0), x); @@ -1985,7 +1988,7 @@ operator+(const CharT* s, const basic_string& y) template inline detail::moved_object > operator+(const CharT* s, - const detail::moved_object >& my) + detail::moved_object > my) { typedef typename basic_string::size_type size_type; return my.get().replace(size_type(0), size_type(0), s); @@ -2018,7 +2021,7 @@ operator+(CharT c, const basic_string& y) template inline detail::moved_object > operator+(CharT c, - const detail::moved_object >& my) + detail::moved_object > my) { typedef typename basic_string::size_type size_type; return my.get().replace(size_type(0), size_type(0), &c, &c + 1); @@ -2051,7 +2054,7 @@ operator+(const basic_string& x, const CharT* s) #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template inline detail::moved_object > -operator+(const detail::moved_object >& mx, +operator+(detail::moved_object > mx, const CharT* s) { mx.get() += s; @@ -2084,7 +2087,7 @@ operator+(const basic_string& x, const CharT c) #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template inline detail::moved_object > -operator+(const detail::moved_object >& mx, +operator+(detail::moved_object > mx, const CharT c) { mx.get() += c; @@ -2234,23 +2237,19 @@ operator>=(const basic_string& x, const CharT* s) // Swap. #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template -inline void swap(basic_string& x, - basic_string& y) +inline void swap(basic_string& x, basic_string& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& mx, - basic_string& y) +inline void swap(detail::moved_object > mx, basic_string& y) { mx.get().swap(y); } template -inline void swap(basic_string& x, - const detail::moved_object >& my) +inline void swap(basic_string& x, detail::moved_object > my) { x.swap(my.get()); } #else template -inline void swap(basic_string && x, - basic_string &&y) +inline void swap(basic_string && x, basic_string &&y) { x.swap(y); } #endif @@ -2319,7 +2318,7 @@ operator<<(std::basic_ostream& os, template std::basic_ostream& operator<<(std::basic_ostream& os, - const detail::moved_object >& ms) + detail::moved_object > ms) { return os << ms.get(); } #endif @@ -2327,7 +2326,7 @@ operator<<(std::basic_ostream& os, template std::basic_istream& operator>>(std::basic_istream& is, - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_string& s) #else basic_string&&s) @@ -2376,18 +2375,18 @@ operator>>(std::basic_istream& is, return is; } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template std::basic_istream& operator>>(std::basic_istream& is, - const detail::moved_object >& ms) + detail::moved_object > ms) { return is >> ms.get(); } #endif template std::basic_istream& getline(std::istream& is, - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_string& s, #else basic_string&&s, @@ -2427,12 +2426,12 @@ getline(std::istream& is, template std::basic_istream& getline(std::istream& is, - const detail::moved_object >& ms, + detail::moved_object > ms, CharT delim) { return getline(is, ms.get(), delim); } #endif -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template inline std::basic_istream& getline(std::basic_istream& is, @@ -2444,7 +2443,7 @@ getline(std::basic_istream& is, template std::basic_istream& getline(std::istream& is, - const detail::moved_object >& ms) + detail::moved_object > ms) { return getline(is, ms.get()); } #else template diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 0a7d188..680bb82 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -312,7 +312,10 @@ struct vector_alloc_holder //Destructor ~vector_alloc_holder() - { this->prot_deallocate(); } + { + this->prot_destroy_all(); + this->prot_deallocate(); + } typedef detail::integral_constant allocator_v1; typedef detail::integral_constant allocator_v2; @@ -397,6 +400,12 @@ struct vector_alloc_holder 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_; } @@ -502,8 +511,8 @@ class vector : private detail::vector_alloc_holder //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - vector(const detail::moved_object >& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + vector(detail::moved_object > mx) : base_t(mx.get()) { this->swap(mx.get()); } #else @@ -531,7 +540,7 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: Linear to the number of elements. ~vector() - { this->priv_destroy_all(); } + {} //vector_alloc_holder clears the data //! Effects: Returns an iterator to the first element contained in the vector. //! @@ -870,8 +879,8 @@ class vector : private detail::vector_alloc_holder //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - vector& operator=(const detail::moved_object >& mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + vector& operator=(detail::moved_object > mx) { vector &x = mx.get(); #else @@ -932,8 +941,8 @@ class vector : private detail::vector_alloc_holder //! Throws: If memory allocation throws. //! //! Complexity: Amortized constant time. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void push_back(const detail::moved_object & mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void push_back(detail::moved_object mx) { value_type &x = mx.get(); #else @@ -1059,10 +1068,12 @@ class vector : private detail::vector_alloc_holder //! Throws: Nothing. //! //! Complexity: Constant. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(vector& x) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object x) + { this->swap(x.get()); } + void swap(vector& x) #else - void swap(vector && x) + void swap(vector &&x) #endif { allocator_type &this_al = this->alloc(), &other_al = x.alloc(); @@ -1076,21 +1087,6 @@ class vector : private detail::vector_alloc_holder } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - void swap(const detail::moved_object >& mx) - { - vector &x = mx.get(); - this->swap(x); - } - #endif - //! Requires: position must be a valid iterator of *this. //! //! Effects: Insert a copy of x before position. @@ -1115,8 +1111,8 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: If position is end(), amortized constant time //! Linear time otherwise. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert(const_iterator position, const detail::moved_object &mx) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + iterator insert(const_iterator position, detail::moved_object mx) { value_type &x = mx.get(); #else @@ -1255,7 +1251,7 @@ class vector : private detail::vector_alloc_holder //! //! Complexity: Linear to the number of elements in the vector. void clear() - { this->priv_destroy_all(); } + { this->prot_destroy_all(); } /// @cond @@ -1303,12 +1299,6 @@ class vector : private detail::vector_alloc_holder } } - void priv_destroy_all() - { - this->destroy_n(detail::get_pointer(this->members_.m_start), this->members_.m_size); - this->members_.m_size = 0; - } - template void priv_range_insert(pointer pos, FwdIt first, FwdIt last, std::forward_iterator_tag) { @@ -1319,13 +1309,7 @@ class vector : private detail::vector_alloc_holder } } - void priv_range_insert(pointer pos, const size_type n, - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - advanced_insert_aux_int_t &&interf - #else - advanced_insert_aux_int_t &interf - #endif - ) + 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; @@ -1969,17 +1953,17 @@ operator<(const vector& x, const vector& y) y.begin(), y.end()); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template inline void swap(vector& x, vector& y) { x.swap(y); } template -inline void swap(const detail::moved_object >& x, vector& y) +inline void swap(detail::moved_object > x, vector& y) { x.get().swap(y); } template -inline void swap(vector &x, const detail::moved_object >& y) +inline void swap(vector &x, detail::moved_object > y) { x.swap(y.get()); } #else template diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp index 4373152..eee090e 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -34,10 +34,13 @@ namespace detail{ 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(); } +//thread inline OS_thread_id_t get_current_thread_id() { return winapi::get_current_thread_id(); } @@ -50,28 +53,71 @@ inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t 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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) typedef pthread_t OS_thread_id_t; -typedef int OS_process_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(); } +{ return ::getpid(); } -inline pthread_t get_current_thread_id() -{ return pthread_self(); } +//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); } +{ return 0 != ::pthread_equal(id1, id2); } inline void thread_yield() -{ sched_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(pid_t(0), get_invalid_thread_id()); +} #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index aedbfac..a96215e 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -542,7 +542,7 @@ struct pair #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - pair(const detail::moved_object >& p) + pair(detail::moved_object > p) : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else @@ -567,7 +567,7 @@ struct pair {} #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair(const detail::moved_object >& p) + pair(detail::moved_object > p) : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else @@ -578,7 +578,7 @@ struct pair #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - pair(const detail::moved_object >& p) + pair(detail::moved_object > p) : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) {} #else @@ -616,7 +616,7 @@ struct pair #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(const detail::moved_object > &p) + pair& operator=(detail::moved_object > p) { first = detail::move_impl(p.get().first); second = detail::move_impl(p.get().second); @@ -632,7 +632,7 @@ struct pair #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(const detail::moved_object > &p) + pair& operator=(detail::moved_object > p) { first = detail::move_impl(p.get().first); second = detail::move_impl(p.get().second); @@ -649,7 +649,7 @@ struct pair #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - pair& operator=(const detail::moved_object > &p) + pair& operator=(detail::moved_object > p) { first = detail::move_impl(p.get().first); second = detail::move_impl(p.get().second); @@ -666,7 +666,7 @@ struct pair #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(const detail::moved_object &p) + void swap(detail::moved_object p) { std::swap(*this, p.get()); } void swap(pair& p) @@ -709,14 +709,14 @@ inline pair make_pair(T1 x, T2 y) #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template -inline void swap(const detail::moved_object > &x, pair& y) +inline void swap(detail::moved_object > &x, pair y) { swap(x.get().first, y.first); swap(x.get().second, y.second); } template -inline void swap(pair& x, const detail::moved_object > &y) +inline void swap(pair& x, detail::moved_object > y) { swap(x.first, y.get().first); swap(x.second, y.get().second); diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index c4cd9a6..6599b9d 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -8,8 +8,8 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_MAPPED_FILE_HPP -#define BOOST_INTERPROCESS_MAPPED_FILE_HPP +#ifndef BOOST_INTERPROCESS_FILE_MAPPING_HPP +#define BOOST_INTERPROCESS_FILE_MAPPING_HPP #include #include @@ -28,9 +28,22 @@ //!Describes file_mapping and mapped region classes namespace boost { - namespace interprocess { +///@cond + +class file_mapping; + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; + +///@endcond + //!A class that wraps a file-mapping that can be used to //!create mapped regions from the mapped files class file_mapping @@ -52,10 +65,10 @@ class file_mapping //!modes. Throws interprocess_exception on error. file_mapping(const char *filename, mode_t mode); - //!Moves the ownership of "moved"'s shared memory object to *this. - //!After the call, "moved" does not represent any shared memory object. + //!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 - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) file_mapping(detail::moved_object moved) : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved.get()); } @@ -65,29 +78,31 @@ class file_mapping { this->swap(moved); } #endif - //!Moves the ownership of "moved"'s shared memory to *this. - //!After the call, "moved" does not represent any shared memory. + //!Moves the ownership of "moved"'s file mapping to *this. + //!After the call, "moved" does not represent any file mapping. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_mapping &operator= - (detail::moved_object moved) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + file_mapping &operator=(detail::moved_object m_other) { - file_mapping tmp(moved); - this->swap(tmp); - return *this; - } + file_mapping &moved = m_other.get(); #else file_mapping &operator=(file_mapping &&moved) { + #endif file_mapping tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } - #endif //!Swaps to file_mappings. //!Does not throw. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.get()); } void swap(file_mapping &other); + #else + void swap(file_mapping &&other); + #endif //!Returns access mode //!used in the constructor @@ -125,7 +140,11 @@ inline file_mapping::~file_mapping() inline const char *file_mapping::get_name() const { return m_filename.c_str(); } -inline void file_mapping::swap(file_mapping &other) +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) +void file_mapping::swap(file_mapping &other) +#else +void file_mapping::swap(file_mapping &&other) +#endif { std::swap(m_handle, other.m_handle); std::swap(m_mode, other.m_mode); @@ -170,15 +189,6 @@ inline void file_mapping::priv_close() } } - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - ///@endcond //!A class that stores the name of a file @@ -202,4 +212,4 @@ class remove_file_on_destroy #include -#endif //BOOST_INTERPROCESS_MAPPED_FILE_HPP +#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index 8faea6d..88550f6 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -75,35 +75,42 @@ class basic_managed_external_buffer } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_external_buffer - (detail::moved_object moved) - { this->swap(moved.get()); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_external_buffer(detail::moved_object mother) + { + basic_managed_external_buffer &moved = mother.get(); #else - basic_managed_external_buffer - (basic_managed_external_buffer &&moved) - { this->swap(moved); } - #endif + 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 - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_external_buffer &operator= - (detail::moved_object moved) - { this->swap(moved.get()); return *this; } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_external_buffer &operator=(detail::moved_object moved) #else - basic_managed_external_buffer &operator= - (basic_managed_external_buffer &&moved) - { this->swap(moved); return *this; } + basic_managed_external_buffer &operator=(basic_managed_external_buffer &&moved) #endif + { + basic_managed_external_buffer tmp(detail::move_impl(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.get()); } void swap(basic_managed_external_buffer &other) + #else + void swap(basic_managed_external_buffer &&other) + #endif { base_t::swap(other); } - }; ///@cond diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp index 4ed9869..87a5452 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -71,25 +71,29 @@ class basic_managed_heap_memory } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_managed_heap_memory - (detail::moved_object moved) - { this->swap(moved.get()); } + (detail::moved_object mother) + { + basic_managed_heap_memory &moved = mother.get(); #else basic_managed_heap_memory(basic_managed_heap_memory &&moved) - { this->swap(moved); } - #endif + { + #endif + this->swap(moved); + } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_heap_memory &operator= - (detail::moved_object moved) - { this->swap(moved.get()); return *this; } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_heap_memory &operator=(detail::moved_object moved) #else - basic_managed_heap_memory &operator= - (basic_managed_heap_memory &&moved) - { this->swap(moved); return *this; } + basic_managed_heap_memory &operator=(basic_managed_heap_memory &&moved) #endif + { + basic_managed_heap_memory tmp(detail::move_impl(moved)); + this->swap(tmp); + return *this; + } //!Tries to resize internal heap memory so that //!we have room for more objects. @@ -121,7 +125,13 @@ class basic_managed_heap_memory //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.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); diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index be3a15a..dee8488 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -118,25 +118,30 @@ class basic_managed_mapped_file //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_managed_mapped_file - (detail::moved_object moved) - { this->swap(moved.get()); } + (detail::moved_object mother) + { + basic_managed_mapped_file &moved = mother.get(); #else basic_managed_mapped_file(basic_managed_mapped_file &&moved) - { this->swap(moved); } - #endif + { + #endif + this->swap(moved); + } //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_mapped_file &operator= - (detail::moved_object moved) - { this->swap(moved.get()); return *this; } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_mapped_file &operator=(detail::moved_object moved) #else basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved) - { this->swap(moved); return *this; } #endif + { + basic_managed_mapped_file tmp(detail::move_impl(moved)); + this->swap(tmp); + return *this; + } //!Destroys *this and indicates that the calling process is finished using //!the resource. The destructor function will deallocate @@ -149,7 +154,14 @@ class basic_managed_mapped_file //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.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); diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index 21d9b5b..a726e06 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -134,29 +134,41 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_shared_memory(detail::moved_object mother) + { + basic_managed_shared_memory &moved = mother.get(); #else basic_managed_shared_memory(basic_managed_shared_memory &&moved) - { this->swap(moved); } - #endif + { + #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 - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_shared_memory &operator= - (detail::moved_object moved) - { this->swap(moved.get()); return *this; } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_shared_memory &operator=(detail::moved_object moved) #else basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved) - { this->swap(moved); return *this; } #endif + { + basic_managed_shared_memory tmp(detail::move_impl(moved)); + this->swap(tmp); + return *this; + } //!Swaps the ownership of the managed shared memories managed by *this and other. //!Never throws. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.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); diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index 805a481..a0e9a92 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -121,7 +121,7 @@ class basic_managed_windows_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_managed_windows_shared_memory (detail::moved_object moved) { this->swap(moved.get()); } @@ -132,15 +132,16 @@ class basic_managed_windows_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - basic_managed_windows_shared_memory &operator= - (detail::moved_object moved) - { this->swap(moved.get()); return *this; } + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + basic_managed_windows_shared_memory &operator=(detail::moved_object moved) #else - basic_managed_windows_shared_memory &operator= - (basic_managed_windows_shared_memory &&moved) - { this->swap(moved); return *this; } + basic_managed_windows_shared_memory &operator=(basic_managed_windows_shared_memory &&moved) #endif + { + basic_managed_windows_shared_memory tmp(detail::move_impl(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 @@ -152,13 +153,19 @@ class basic_managed_windows_shared_memory //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.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 + /// @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. diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 384e624..50b896b 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -78,7 +78,7 @@ class mapped_region //!Move constructor. *this will be constructed taking ownership of "other"'s //!region and "other" will be left in default constructor state. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) mapped_region(detail::moved_object other); #else mapped_region(mapped_region &&other); @@ -90,7 +90,7 @@ class 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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) mapped_region &operator=(detail::moved_object other); #else mapped_region &operator=(mapped_region &&other); @@ -119,7 +119,13 @@ class mapped_region //!Swaps the mapped_region with another //!mapped region + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.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. @@ -158,12 +164,16 @@ inline void swap(mapped_region &x, mapped_region &y) { x.swap(y); } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region &mapped_region::operator=(detail::moved_object other) -{ this->swap(other.get()); return *this; } +inline mapped_region &mapped_region::operator=(detail::moved_object moved) +{ #else -inline mapped_region &mapped_region::operator=(mapped_region &&other) -{ this->swap(other); return *this; } +inline mapped_region &mapped_region::operator=(mapped_region &&moved) +{ #endif + mapped_region tmp(detail::move_impl(moved)); + this->swap(tmp); + return *this; +} inline mapped_region::~mapped_region() { this->priv_close(); } @@ -545,7 +555,11 @@ const std::size_t mapped_region::page_size_holder::PageSize inline std::size_t mapped_region::get_page_size() { return page_size_holder<0>::PageSize; } +#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !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); diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index 7866696..f84c0c7 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -74,9 +74,8 @@ class shared_memory_object //!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 - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - shared_memory_object - (const detail::moved_object moved) + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + shared_memory_object(detail::moved_object moved) : m_handle(file_handle_t(detail::invalid_file())) { this->swap(moved.get()); } #else @@ -88,7 +87,7 @@ class shared_memory_object //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) shared_memory_object &operator= (detail::moved_object moved) { @@ -106,7 +105,13 @@ class shared_memory_object #endif //!Swaps the shared_memory_objects. Does not throw + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.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 @@ -168,7 +173,11 @@ inline const char *shared_memory_object::get_name() const 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_INTERPROCESS_RVALUE_REFERENCE) && !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); diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index fa272aa..ddf6f7d 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -153,7 +153,7 @@ class shared_ptr //!Move-Constructs a shared_ptr that takes ownership of other resource and //!other is put in default-constructed state. //!Throws: nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) explicit shared_ptr(detail::moved_object other) : m_pn() { this->swap(other.get()); } @@ -198,7 +198,7 @@ class shared_ptr //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). //!Never throws - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) shared_ptr & operator=(detail::moved_object other) // never throws { this_type(other).swap(*this); diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index 4a73eaf..064af09 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -150,7 +150,7 @@ class unique_ptr //!deleter() and u.get_deleter() both reference the same lvalue deleter. //! //!Throws: nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) unique_ptr(detail::moved_object u) : ptr_(u.get().release(), detail::move_impl(u.get().get_deleter())) {} @@ -179,7 +179,7 @@ class unique_ptr //!was constructed from u.get_deleter(). //! //!Throws: nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template unique_ptr(detail::moved_object > u, typename detail::enable_if_c< @@ -230,7 +230,7 @@ class unique_ptr //!Returns: *this. //! //!Throws: nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) unique_ptr& operator=(detail::moved_object u) { reset(u.get().release()); @@ -261,7 +261,7 @@ class unique_ptr //! //!Throws: nothing. template - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) unique_ptr& operator=(detail::moved_object > mu) { reset(mu.get().release()); @@ -359,7 +359,7 @@ class unique_ptr //!Effects: The stored pointers of this and u are exchanged. //! The stored deleters are swapped (unqualified). //!Throws: nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(unique_ptr& u) { ptr_.swap(u.ptr_); } diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp index 8cc7de2..c659e20 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -33,14 +33,14 @@ namespace boost { namespace interprocess { inline interprocess_recursive_mutex::interprocess_recursive_mutex() - : m_nLockCount(0), m_nOwner(detail::get_invalid_thread_id()){} + : m_nLockCount(0), m_nOwner(detail::get_invalid_systemwide_thread_id()){} inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} inline void interprocess_recursive_mutex::lock() { - detail::OS_thread_id_t th_id = detail::get_current_thread_id(); - if(detail::equal_thread_id(th_id, m_nOwner)){ + detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); + if(detail::equal_systemwide_thread_id(th_id, m_nOwner)){ if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -56,8 +56,8 @@ inline void interprocess_recursive_mutex::lock() inline bool interprocess_recursive_mutex::try_lock() { - detail::OS_thread_id_t th_id = detail::get_current_thread_id(); - if(detail::equal_thread_id(th_id, m_nOwner)) { // we own it + detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); + if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -79,8 +79,8 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt this->lock(); return true; } - detail::OS_thread_id_t th_id = detail::get_current_thread_id(); - if(detail::equal_thread_id(th_id, m_nOwner)) { // we own it + detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); + if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -98,10 +98,10 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt inline void interprocess_recursive_mutex::unlock() { - assert(detail::equal_thread_id(detail::get_current_thread_id(), m_nOwner)); + assert(detail::equal_systemwide_thread_id(detail::get_current_systemwide_thread_id(), m_nOwner)); --m_nLockCount; if(!m_nLockCount){ - m_nOwner = detail::get_invalid_thread_id(); + m_nOwner = detail::get_invalid_systemwide_thread_id(); m_mutex.unlock(); } } diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index dfef5ff..517770f 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -18,10 +18,10 @@ #include #include #include -#include #include #include #include +#include //!\file //!Describes a class that wraps file locking capabilities. @@ -29,6 +29,20 @@ namespace boost { namespace interprocess { +///@cond + +class file_lock; + +//!Trait class to detect if a type is +//!movable +template<> +struct is_movable +{ + enum { value = true }; +}; + +///@endcond + //!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. @@ -38,17 +52,67 @@ class file_lock { /// @cond //Non-copyable - file_lock(); file_lock(const file_lock &); file_lock &operator=(const file_lock &); /// @endcond public: + + //!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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + file_lock(detail::moved_object 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + file_lock &operator=(detail::moved_object m_other) + { + file_lock &moved = m_other.get(); + #else + file_lock &operator=(file_lock &&moved) + { + #endif + file_lock tmp(detail::move_impl(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + void swap(detail::moved_object mother) + { this->swap(mother.get()); } + void swap(file_lock &other) + #else + void swap(file_lock &&other) + #endif + { + file_handle_t tmp = m_file_hnd; + other.m_file_hnd = other.m_file_hnd; + other.m_file_hnd = tmp; + } //Exclusive locking @@ -266,7 +330,6 @@ inline void file_lock::unlock_sharable() } } //namespace interprocess { - } //namespace boost { #include diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index 6f2eae9..13c0eb0 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -104,9 +104,9 @@ class interprocess_recursive_mutex /// @cond private: #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) - interprocess_mutex m_mutex; - unsigned int m_nLockCount; - detail::OS_thread_id_t m_nOwner; + interprocess_mutex m_mutex; + unsigned int m_nLockCount; + 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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) diff --git a/include/boost/interprocess/sync/lock_options.hpp b/include/boost/interprocess/sync/lock_options.hpp index 65a7e32..3dc7360 100644 --- a/include/boost/interprocess/sync/lock_options.hpp +++ b/include/boost/interprocess/sync/lock_options.hpp @@ -28,26 +28,24 @@ namespace posix_time namespace interprocess { -namespace detail{ - //!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{}; -} //namespace detail{ +//!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 detail::defer_lock_type defer_lock = detail::defer_lock_type(); +static const defer_lock_type defer_lock = defer_lock_type(); //!An object indicating that a try_lock() //!operation must be executed. -static const detail::try_to_lock_type try_to_lock = detail::try_to_lock_type(); +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 detail::accept_ownership_type accept_ownership = detail::accept_ownership_type(); +static const accept_ownership_type accept_ownership = accept_ownership_type(); } // namespace interprocess { } // namespace boost{ diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index f9e155e..2bdfa3e 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -80,14 +80,14 @@ class scoped_lock //!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, detail::defer_lock_type) + 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, detail::accept_ownership_type) + scoped_lock(mutex_type& m, accept_ownership_type) : mp_mutex(&m), m_locked(true) {} @@ -99,7 +99,7 @@ class scoped_lock //! 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, detail::try_to_lock_type) + scoped_lock(mutex_type& m, try_to_lock_type) : mp_mutex(&m), m_locked(mp_mutex->try_lock()) {} @@ -125,12 +125,11 @@ class scoped_lock //! can be moved with the expression: "detail::move_impl(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) scoped_lock(detail::moved_object > 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(); } @@ -148,7 +147,7 @@ class scoped_lock //! the expression: "detail::move_impl(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). - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) scoped_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(false) { @@ -187,9 +186,9 @@ class scoped_lock //! 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.*/ - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) scoped_lock(detail::moved_object > upgr - ,detail::try_to_lock_type) + ,try_to_lock_type) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr.get(); @@ -204,7 +203,7 @@ class scoped_lock } #else scoped_lock(upgradable_lock &&upgr - ,detail::try_to_lock_type) + ,try_to_lock_type) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -233,7 +232,7 @@ class scoped_lock //! "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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) scoped_lock(detail::moved_object > upgr ,boost::posix_time::ptime &abs_time) : mp_mutex(0), m_locked(false) @@ -280,9 +279,9 @@ class scoped_lock //! 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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) scoped_lock(detail::moved_object > shar - ,detail::try_to_lock_type) + ,try_to_lock_type) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar.get(); @@ -297,7 +296,7 @@ class scoped_lock } #else scoped_lock(sharable_lock &&shar - ,detail::try_to_lock_type) + ,try_to_lock_type) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -326,7 +325,7 @@ class scoped_lock //! 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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) scoped_lock &operator=(detail::moved_object scop) { if(this->owns()) @@ -430,7 +429,7 @@ class scoped_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(detail::moved_object > other) { std::swap(mp_mutex, other.get().mp_mutex); diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index 178140e..ea97864 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -86,14 +86,14 @@ class sharable_lock //!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, detail::defer_lock_type) + 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, detail::accept_ownership_type) + sharable_lock(mutex_type& m, accept_ownership_type) : mp_mutex(&m), m_locked(true) {} @@ -105,7 +105,7 @@ class sharable_lock //! 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, detail::try_to_lock_type) + sharable_lock(mutex_type& m, try_to_lock_type) : mp_mutex(&m), m_locked(false) { m_locked = mp_mutex->try_lock_sharable(); } @@ -129,7 +129,7 @@ class sharable_lock //! signature. An non-moved sharable_lock can be moved with the expression: //! "detail::move_impl(lock);". This constructor does not alter the state of the mutex, //! only potentially who owns it. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) sharable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(upgr.get().owns()) { mp_mutex = upgr.get().release(); } @@ -148,7 +148,7 @@ class sharable_lock //! unlocking upgr. Only a moved sharable_lock's will match this //! signature. An non-moved upgradable_lock can be moved with the expression: //! "detail::move_impl(lock);".*/ - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) sharable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(false) { @@ -182,7 +182,7 @@ class sharable_lock //! Only a moved scoped_lock's will match this //! signature. An non-moved scoped_lock can be moved with the expression: //! "detail::move_impl(lock);".*/ - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) sharable_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(false) { @@ -221,7 +221,7 @@ class sharable_lock //!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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) sharable_lock &operator=(detail::moved_object > upgr) { if(this->owns()) @@ -328,7 +328,7 @@ class sharable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(detail::moved_object > other) { std::swap(mp_mutex, other.get().mp_mutex); diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index c541487..386187d 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -78,14 +78,14 @@ class upgradable_lock //!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, detail::defer_lock_type) + 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, detail::accept_ownership_type) + upgradable_lock(mutex_type& m, accept_ownership_type) : mp_mutex(&m), m_locked(true) {} @@ -97,7 +97,7 @@ class upgradable_lock //! 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, detail::try_to_lock_type) + upgradable_lock(mutex_type& m, try_to_lock_type) : mp_mutex(&m), m_locked(false) { m_locked = mp_mutex->try_lock_upgradable(); } @@ -123,7 +123,7 @@ class upgradable_lock //! signature. An non-moved upgradable_lock can be moved with the //! expression: "detail::move_impl(lock);". This constructor does not alter the //! state of the mutex, only potentially who owns it. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) upgradable_lock(detail::moved_object > upgr) : mp_mutex(0), m_locked(upgr.get().owns()) { mp_mutex = upgr.get().release(); } @@ -142,7 +142,7 @@ class upgradable_lock //! Only a moved sharable_lock's will match this //! signature. An non-moved sharable_lock can be moved with the //! expression: "detail::move_impl(lock);". - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) upgradable_lock(detail::moved_object > scop) : mp_mutex(0), m_locked(false) { @@ -181,9 +181,9 @@ class upgradable_lock //! 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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) upgradable_lock( detail::moved_object > shar - , detail::try_to_lock_type) + , try_to_lock_type) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar.get(); @@ -198,7 +198,7 @@ class upgradable_lock } #else upgradable_lock( sharable_lock &&shar - , detail::try_to_lock_type) + , try_to_lock_type) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -229,7 +229,7 @@ class upgradable_lock //! 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. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) upgradable_lock &operator=(detail::moved_object > upgr) { if(this->owns()) @@ -336,7 +336,7 @@ class upgradable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(detail::moved_object > other) { std::swap(mp_mutex, other.get().mp_mutex); diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index 88165be..cd82e01 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -81,7 +81,7 @@ class windows_shared_memory //!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 - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) windows_shared_memory (detail::moved_object moved) { this->swap(moved.get()); } @@ -93,22 +93,17 @@ class windows_shared_memory //!Moves the ownership of "moved"'s shared memory to *this. //!After the call, "moved" does not represent any shared memory. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE + #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) windows_shared_memory &operator= (detail::moved_object moved) - { - windows_shared_memory tmp(moved); - this->swap(tmp); - return *this; - } #else windows_shared_memory &operator=(windows_shared_memory &&moved) + #endif { windows_shared_memory tmp(detail::move_impl(moved)); this->swap(tmp); return *this; } - #endif //!Swaps to shared_memory_objects. Does not throw void swap(windows_shared_memory &other); From 8f145becf5cbe25ddce435930cff78822ba128f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 13 Dec 2008 13:47:00 +0000 Subject: [PATCH 63/77] * Updated documentation to show rvalue-references funcions instead of emulation functions. * More non-copyable classes are now movable. * Move-constructor and assignments now leave moved object in default-constructed state instead of just swapping contents. * Several bugfixes (#2391, #2431, #1390, #2570, #2528). [SVN r50258] --- doc/interprocess.qbk | 30 +++++++++++++++++++---------- example/Jamfile.v2 | 1 - proj/to-do.txt | 16 +++++++++++++++ proj/vc7ide/interprocesslib.vcproj | 2 +- test/deque_test.cpp | 11 +++++++++++ test/file_lock_test.cpp | 11 ++++++++++- test/file_mapping_test.cpp | 2 ++ test/list_test.cpp | 9 +++++++++ test/managed_mapped_file_test.cpp | 2 ++ test/managed_shared_memory_test.cpp | 2 ++ test/movable_int.hpp | 8 ++++---- test/slist_test.cpp | 9 +++++++++ test/tree_test.cpp | 19 ++++++++++++++++++ test/user_buffer_test.cpp | 19 ++++++++++++++++++ test/vector_test.cpp | 9 +++++++++ 15 files changed, 133 insertions(+), 17 deletions(-) diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 2665ea2..c1bdc02 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -1,5 +1,5 @@ [/ - / Copyright (c) 2007 Ion Gaztanaga + / Copyright (c) 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) @@ -8,7 +8,7 @@ [library Boost.Interprocess [quickbook 1.3] [authors [Gaztañaga, Ion]] - [copyright 2005- 2007 Ion Gaztañaga] + [copyright 2005- 2008 Ion Gaztañaga] [id interprocess] [dirname interprocess] [purpose Interprocess communication utilities] @@ -1516,11 +1516,11 @@ In the previous example, a mutex is used to ['lock] but we can't use it to can do two things: * [*wait]: The thread is blocked until some other thread notifies that it can - continue because the condition that lead to waiting has disapeared. + continue because the condition that lead to waiting has disappeared. * [*notify]: The thread sends a signal to one blocked thread or to all blocked threads to tell them that they the condition that provoked their wait has - disapeared. + disappeared. Waiting in a condition variable is always associated with a mutex. The mutex must be locked prior to waiting on the condition. When waiting @@ -2178,7 +2178,7 @@ These operations can be managed more effectively using [*lock transfer operation A lock transfer operations explicitly indicates that a mutex owned by a lock is transferred to another lock executing atomic unlocking plus locking operations. -[section:lock_trnasfer_simple_transfer Simple Lock Transfer] +[section:lock_transfer_simple_transfer Simple Lock Transfer] Imagine that a thread modifies some data in the beginning but after that, it has to just read it in a long time. The code can acquire the exclusive lock, modify the data @@ -3668,10 +3668,10 @@ corrupted. As mentioned, the managed segment stores the information about named and unique objects in two indexes. Depending on the type of those indexes, the index must reallocate some auxiliary structures when new named or unique allocations are made. -For some indexes, if the user knows how many maned or unique objects is going to -create it's possible to preallocate some structures to obtain much better -performance (if the index is an ordered vector it can preallocate memory to avoid -reallocations, if the index is a hash structure it can preallocate the bucket array...). +For some indexes, if the user knows how many named or unique objects are going to +be created it's possible to preallocate some structures to obtain much better +performance. (If the index is an ordered vector it can preallocate memory to avoid +reallocations. If the index is a hash structure it can preallocate the bucket array). The following functions reserve memory to make the subsequent allocation of named or unique objects more efficient. These functions are only useful for @@ -5671,7 +5671,7 @@ including creating containers of such objects: [section:basic_guidelines Basic guidelines] When building [*Boost.Interprocess] architecture, I took some basic guidelines that can be -resumed in these points: +summarized by these points: * [*Boost.Interprocess] should be portable at least in UNIX and Windows systems. That means unifying not only interfaces but also behaviour. This is why @@ -6541,6 +6541,16 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_38_00 Boost 1.38 Release] + +* Updated documentation to show rvalue-references funcions instead of emulation functions. +* More non-copyable classes are now movable. +* Move-constructor and assignments now leave moved object in default-constructed state + instead of just swapping contents. +* Several bugfixes (#2391, #2431, #1390, #2570, #2528). + +[endsect] + [section:release_notes_boost_1_37_00 Boost 1.37 Release] * Containers can be used now in recursive types. diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index eb26876..9551f9f 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -22,7 +22,6 @@ rule test_all for local fileb in [ glob *.cpp ] { all_rules += [ link $(fileb) /boost/thread//boost_thread -# all_rules += [ compile $(fileb) : # additional args : # test-files : # requirements diff --git a/proj/to-do.txt b/proj/to-do.txt index 49ff717..3ac56ac 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -52,3 +52,19 @@ ->find a way to pass security attributes to shared memory ->Explain in docs that shared memory can't be used between different users in windows + +-> Implement vector with memcpy/memmove for trivially copyable types. + +-> Update all swap() calls to work with rvalues in all classes + +-> correct swap overloads for the documentation so that just appears a single rvalue swap + +-> correct splice()/merg overloads for the documentation so that just appears a single rvalue splice + +-> flat_xxx constructors are not documented + +-> operator >> eta antzekoek moved_value behar dute + +-> make file_lock movable + +-> Add cmath workaround for Boost < 1.37 diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index 4b4a0e4..abf9115 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -312,7 +312,7 @@ recursive_deque_deque; } + + { + //Now test move semantics + deque original; + deque move_ctor(detail::move_impl(original)); + deque move_assign; + move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); + } + //Customize managed_shared_memory class typedef basic_managed_shared_memory sl(flock, test::delay(1)); } - } + }/* + { + //Now test move semantics + file_lock mapping(test::get_process_id_name()); + file_lock move_ctor(detail::move_impl(mapping)); + file_lock move_assign; + move_assign = detail::move_impl(move_ctor); + mapping.swap(detail::move_impl(move_assign)); + mapping.swap(move_assign); + }*/ //test::test_all_lock(); //test::test_all_mutex(); diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 743c917..2aa7e3f 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -128,6 +128,8 @@ int main () file_mapping move_ctor(detail::move_impl(mapping)); file_mapping move_assign; move_assign = detail::move_impl(move_ctor); + mapping.swap(detail::move_impl(move_assign)); + mapping.swap(move_assign); } } catch(std::exception &exc){ diff --git a/test/list_test.cpp b/test/list_test.cpp index b4c4249..d7f58dd 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -51,6 +51,15 @@ void recursive_list_test()//Test for recursive types int main () { recursive_list_test(); + { + //Now test move semantics + list original; + list move_ctor(detail::move_impl(original)); + list move_assign; + move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); + } if(test::list_test()) return 1; diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index 5b394ba..cebbfe5 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -206,6 +206,8 @@ int main () managed_mapped_file move_ctor(detail::move_impl(original)); managed_mapped_file move_assign; move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); } } diff --git a/test/managed_shared_memory_test.cpp b/test/managed_shared_memory_test.cpp index 2004af8..1314038 100644 --- a/test/managed_shared_memory_test.cpp +++ b/test/managed_shared_memory_test.cpp @@ -202,6 +202,8 @@ int main () managed_shared_memory move_ctor(detail::move_impl(original)); managed_shared_memory move_assign; move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); } } diff --git a/test/movable_int.hpp b/test/movable_int.hpp index eeb12f6..2ac7fb8 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -35,7 +35,7 @@ class movable_int {} #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_int(const detail::moved_object &mmi) + movable_int(detail::moved_object mmi) : m_int(mmi.get().m_int) { mmi.get().m_int = 0; } #else @@ -45,7 +45,7 @@ class movable_int #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_int & operator= (const detail::moved_object &mmi) + movable_int & operator= (detail::moved_object mmi) { this->m_int = mmi.get().m_int; mmi.get().m_int = 0; return *this; } #else movable_int & operator= (movable_int &&mmi) @@ -109,7 +109,7 @@ class movable_and_copyable_int { this->m_int = mi.m_int; return *this; } #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_and_copyable_int(const detail::moved_object &mmi) + movable_and_copyable_int(detail::moved_object mmi) : m_int(mmi.get().m_int) { mmi.get().m_int = 0; } #else @@ -119,7 +119,7 @@ class movable_and_copyable_int #endif #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_and_copyable_int & operator= (const detail::moved_object &mmi) + movable_and_copyable_int & operator= (detail::moved_object mmi) { this->m_int = mmi.get().m_int; mmi.get().m_int = 0; return *this; } #else movable_and_copyable_int & operator= (movable_and_copyable_int &&mmi) diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 1bf7462..5944f35 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -51,6 +51,15 @@ void recursive_slist_test()//Test for recursive types int main () { recursive_slist_test(); + { + //Now test move semantics + slist original; + slist move_ctor(detail::move_impl(original)); + slist move_assign; + move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); + } if(test::list_test()) return 1; diff --git a/test/tree_test.cpp b/test/tree_test.cpp index a9c3786..21b4668 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -158,6 +158,18 @@ public: { return a.id_ < b.id_; } }; +template +void test_move_semantics() +{ + //Now test move semantics + C original; + C move_ctor(detail::move_impl(original)); + C move_assign; + move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); +} + int main () { //Recursive container instantiation @@ -167,6 +179,13 @@ int main () map map_; multimap multimap_; } + //Now test move semantics + { + test_move_semantics >(); + test_move_semantics >(); + test_move_semantics >(); + test_move_semantics >(); + } using namespace boost::interprocess::detail; diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index cc107f1..fdcab2d 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -56,6 +56,25 @@ int main () const int memsize = 65536/size_aligner*size_aligner; static detail::max_align static_buffer[memsize/size_aligner]; + { + //Now test move semantics + managed_heap_memory original(memsize); + managed_heap_memory move_ctor(detail::move_impl(original)); + managed_heap_memory move_assign; + move_assign = detail::move_impl(move_ctor); + original.swap(detail::move_impl(move_assign)); + original.swap(move_assign); + } + { + //Now test move semantics + managed_external_buffer original(create_only, static_buffer, memsize); + managed_external_buffer move_ctor(detail::move_impl(original)); + managed_external_buffer move_assign; + move_assign = detail::move_impl(move_ctor); + original.swap(detail::move_impl(move_assign)); + original.swap(move_assign); + } + //Named new capable user mem allocator wmanaged_external_buffer user_buffer(create_only, static_buffer, memsize); diff --git a/test/vector_test.cpp b/test/vector_test.cpp index 22c9a57..afb1e12 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -91,6 +91,15 @@ void recursive_vector_test()//Test for recursive types int main() { recursive_vector_test(); + { + //Now test move semantics + vector original; + vector move_ctor(detail::move_impl(original)); + vector move_assign; + move_assign = detail::move_impl(move_ctor); + move_assign.swap(detail::move_impl(original)); + move_assign.swap(original); + } typedef allocator ShmemAllocator; typedef vector MyVector; From 3e4f6bceda62f8b7a89006b6e09d9e3a38fd9895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 14 Dec 2008 21:43:59 +0000 Subject: [PATCH 64/77] Fixed static "PageSize" variable initialization for DLLs [SVN r50273] --- include/boost/interprocess/mapped_region.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 50b896b..115b25d 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -553,7 +553,12 @@ const std::size_t mapped_region::page_size_holder::PageSize = mapped_region::page_size_holder::get_page_size(); inline std::size_t mapped_region::get_page_size() -{ return page_size_holder<0>::PageSize; } +{ + if(!page_size_holder<0>::PageSize) + return page_size_holder<0>::get_page_size(); + else + return page_size_holder<0>::PageSize; +} #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) inline void mapped_region::swap(mapped_region &other) From 5ecb62bbe0054ac8b533ab1e9aa4c21aae847049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 19 Dec 2008 18:58:26 +0000 Subject: [PATCH 65/77] Fixes wrong static_cast<> in return statement [SVN r50327] --- include/boost/interprocess/detail/segment_manager_helper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 89478d8..ffbe9fb 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -382,7 +382,7 @@ struct index_data index_data(void *ptr) : m_ptr(ptr){} void *value() const - { return static_cast(detail::get_pointer(m_ptr)); } + { return static_cast(detail::get_pointer(m_ptr)); } }; template From 1e4c941ea91b72acc79302c6c2ae0b6abc6b0fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 21 Dec 2008 00:31:08 +0000 Subject: [PATCH 66/77] Fixed swap to be an inline function to avoid linking errors [SVN r50336] --- include/boost/interprocess/file_mapping.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index 6599b9d..37391e2 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -141,9 +141,9 @@ inline const char *file_mapping::get_name() const { return m_filename.c_str(); } #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -void file_mapping::swap(file_mapping &other) +inline void file_mapping::swap(file_mapping &other) #else -void file_mapping::swap(file_mapping &&other) +inline void file_mapping::swap(file_mapping &&other) #endif { std::swap(m_handle, other.m_handle); From b511d91348708c1a9f97bf8ff6cb4a45ccc35912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 23 Dec 2008 14:18:15 +0000 Subject: [PATCH 67/77] Added configuration to properly detect FreeBSD options [SVN r50372] --- .../boost/interprocess/detail/workaround.hpp | 52 +++++++------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index 9e4f3fa..e21164d 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -8,40 +8,32 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_PTR_WRKRND_HPP -#define BOOST_INTERPROCESS_PTR_WRKRND_HPP +#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP +#define BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP #include -#undef BOOST_DISABLE_WIN32 - #if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) #include - #if defined(_POSIX_THREAD_PROCESS_SHARED) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_THREAD_PROCESS_SHARED - 0 <= 0)) + #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 - #endif - - #if defined(_POSIX_BARRIERS) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_BARRIERS - 0 <= 0)) + #endif + + #if ((_POSIX_BARRIERS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_BARRIERS # endif - #endif - #if defined(_POSIX_SEMAPHORES) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_SEMAPHORES - 0 <= 0)) + #if ((_POSIX_SEMAPHORES - 0) > 0) # define BOOST_INTERPROCESS_POSIX_SEMAPHORES # if defined(__CYGWIN__) #define BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK # endif - # endif #endif #if ((defined _V6_ILP32_OFFBIG) &&(_V6_ILP32_OFFBIG - 0 > 0)) ||\ @@ -56,10 +48,8 @@ #else #endif - #if defined(_POSIX_SHARED_MEMORY_OBJECTS) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_SHARED_MEMORY_OBJECTS - 0 <= 0)) + #if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS - # endif #else # if defined(__vms) # if __CRTL_VER >= 70200000 @@ -68,28 +58,26 @@ # endif #endif - #if defined(_POSIX_TIMEOUTS) - # if !((_XOPEN_VERSION >= 600) && (_POSIX_TIMEOUTS - 0 <= 0)) + #if ((_POSIX_TIMEOUTS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_TIMEOUTS - # endif #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 - //Some systems have filesystem-based shared memory, 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 - #if defined(__hpux) || defined(__osf__) || defined(__vms) + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES) #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SHARED_MEMORY #endif #endif #ifdef BOOST_INTERPROCESS_POSIX_SEMAPHORES - //Some systems have filesystem-based shared memory, so the - //portable "/semname" 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 - #if defined(__hpux) || defined(__osf__) || defined(__vms) + #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES) #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES #endif #endif @@ -136,4 +124,4 @@ #include -#endif //#ifndef BOOST_INTERPROCESS_PTR_WRKRND_HPP +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_WORKAROUND_HPP From 7ef71f4527795f2b59f87008b1032f90aa7ba347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 30 Jan 2009 15:23:42 +0000 Subject: [PATCH 68/77] Fixed deallocation before destructor. [SVN r50903] --- include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp index b0a1766..51f44e9 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -84,7 +84,7 @@ class sp_counted_impl_pd this_pointer this_ptr (this); //Do it now! scoped_ptr >(this_ptr, a_copy); + scoped_ptr_dealloc_functor > deallocator(this_ptr, a_copy); typedef typename this_allocator::value_type value_type; detail::get_pointer(this_ptr)->~value_type(); } From 7fe60a8cbd10fd2e71884a422d36de9e3b9e31c1 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 17 Feb 2009 10:05:58 +0000 Subject: [PATCH 69/77] Add PDF generation options to fix external links to point to the web site. Added a few more Boostbook based libs that were missed first time around. Fixed PDF naming issues. [SVN r51284] --- doc/Jamfile.v2 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9474715..6eb1d7c 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -43,4 +43,5 @@ boostbook standalone chunk.first.sections=1 chunk.section.depth=2 autodoc + pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html ; From 814c51a80362d1e27989eb2855d0bb70d594c93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 17 Feb 2009 16:59:35 +0000 Subject: [PATCH 70/77] Ticket #2766: error in boost::interprocess::file_lock::swap [SVN r51289] --- include/boost/interprocess/sync/file_lock.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 517770f..75a2693 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -110,7 +110,7 @@ class file_lock #endif { file_handle_t tmp = m_file_hnd; - other.m_file_hnd = other.m_file_hnd; + m_file_hnd = other.m_file_hnd; other.m_file_hnd = tmp; } From 3d0fcd68e3929894b7645b8e4091f7c3f7e09f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 24 Mar 2009 21:52:06 +0000 Subject: [PATCH 71/77] Changes for Boost.1.39 [SVN r51964] --- doc/Jamfile.v2 | 9 +- doc/interprocess.qbk | 181 +- example/Jamfile.v2 | 13 +- ....cpp => comp_doc_anonymous_conditionA.cpp} | 13 +- ....cpp => comp_doc_anonymous_conditionB.cpp} | 5 +- ...texA.cpp => comp_doc_anonymous_mutexA.cpp} | 13 +- example/comp_doc_anonymous_mutexB.cpp | 68 + example/comp_doc_anonymous_semaphoreA.cpp | 64 + example/comp_doc_anonymous_semaphoreB.cpp | 61 + .../comp_doc_anonymous_upgradable_mutexA.cpp | 72 + .../comp_doc_anonymous_upgradable_mutexB.cpp | 70 + ...queueA.cpp => comp_doc_message_queueA.cpp} | 0 ...queueB.cpp => comp_doc_message_queueB.cpp} | 0 example/doc_adaptive_pool.cpp | 64 +- example/doc_allocator.cpp | 7 +- example/doc_anonymous_mutexB.cpp | 70 - example/doc_anonymous_semaphoreA.cpp | 70 - example/doc_anonymous_semaphoreB.cpp | 66 - example/doc_anonymous_upgradable_mutexA.cpp | 79 - example/doc_anonymous_upgradable_mutexB.cpp | 72 - example/doc_bufferstream.cpp | 115 +- example/doc_cached_adaptive_pool.cpp | 77 +- example/doc_cached_node_allocator.cpp | 77 +- example/doc_complex_map.cpp | 39 +- example/doc_cont.cpp | 71 +- example/doc_contA.cpp | 60 - example/doc_contB.cpp | 57 - example/doc_file_mapping.cpp | 81 +- example/doc_file_mapping2.cpp | 74 - example/doc_intrusive.cpp | 57 +- example/doc_ipc_message.cpp | 72 + example/doc_ipc_messageA.cpp | 55 - example/doc_ipc_messageB.cpp | 47 - example/doc_managed_aligned_allocation.cpp | 65 +- example/doc_managed_allocation_command.cpp | 104 +- example/doc_managed_construction_info.cpp | 56 +- example/doc_managed_copy_on_write.cpp | 5 +- example/doc_managed_external_buffer.cpp | 4 +- example/doc_managed_grow.cpp | 81 +- example/doc_managed_mapped_file.cpp | 86 +- example/doc_managed_multiple_allocation.cpp | 84 +- example/doc_managed_raw_allocation.cpp | 33 +- example/doc_map.cpp | 79 +- example/doc_move_containers.cpp | 87 +- example/doc_multi_index.cpp | 39 +- ...c_named_allocA.cpp => doc_named_alloc.cpp} | 72 +- example/doc_named_allocB.cpp | 63 - example/doc_named_mutex.cpp | 3 + example/doc_node_allocator.cpp | 64 +- example/doc_offset_ptr.cpp | 62 +- example/doc_private_adaptive_pool.cpp | 56 +- example/doc_private_node_allocator.cpp | 56 +- example/doc_scoped_ptr.cpp | 93 +- example/doc_shared_memory.cpp | 39 +- example/doc_shared_memory2.cpp | 48 - example/doc_shared_ptr.cpp | 5 +- example/doc_shared_ptr_explicit.cpp | 10 +- example/doc_spawn_vector.cpp | 79 + example/doc_unique_ptr.cpp | 12 +- example/doc_unordered_map.cpp | 63 +- example/doc_vectorstream.cpp | 142 +- example/doc_where_allocate.cpp | 67 +- example/doc_windows_shared_memory.cpp | 50 +- example/doc_windows_shared_memory2.cpp | 55 - .../interprocess/allocators/adaptive_pool.hpp | 30 +- .../interprocess/allocators/allocator.hpp | 56 +- .../allocators/cached_adaptive_pool.hpp | 16 +- .../allocators/cached_node_allocator.hpp | 16 +- .../allocators/detail/adaptive_node_pool.hpp | 61 +- .../allocators/detail/allocator_common.hpp | 200 +- .../allocators/detail/node_pool.hpp | 56 +- .../allocators/node_allocator.hpp | 30 +- .../allocators/private_adaptive_pool.hpp | 30 +- .../allocators/private_node_allocator.hpp | 30 +- .../interprocess/anonymous_shared_memory.hpp | 22 +- .../containers/allocation_type.hpp | 40 + .../containers/container/containers_fwd.hpp | 153 + .../containers/container/deque.hpp | 1482 ++++++++++ .../container}/detail/advanced_insert_int.hpp | 111 +- .../container}/detail/algorithms.hpp | 66 +- .../container/detail}/allocation_type.hpp | 19 +- .../container/detail/config_begin.hpp | 47 + .../container/detail/config_end.hpp | 17 + .../container/detail/destroyers.hpp | 154 + .../{ => container}/detail/flat_tree.hpp | 208 +- .../container}/detail/iterators.hpp | 217 +- .../containers/container/detail/mpl.hpp | 152 + .../detail/multiallocation_chain.hpp | 554 ++++ .../detail/node_alloc_holder.hpp | 283 +- .../containers/container/detail/pair.hpp | 189 ++ .../container/detail/preprocessor.hpp | 101 + .../container/detail/transform_iterator.hpp | 176 ++ .../{ => container}/detail/tree.hpp | 279 +- .../container/detail/type_traits.hpp | 166 ++ .../containers/container/detail/utilities.hpp | 95 + .../container/detail/value_init.hpp | 43 + .../detail/variadic_templates_tools.hpp | 153 + .../container}/detail/version_type.hpp | 26 +- .../container/detail/workaround.hpp | 24 + .../containers/container/flat_map.hpp | 1390 +++++++++ .../containers/container/flat_set.hpp | 1172 ++++++++ .../containers/container/list.hpp | 1372 +++++++++ .../interprocess/containers/container/map.hpp | 1266 +++++++++ .../interprocess/containers/container/set.hpp | 1112 ++++++++ .../containers/container/slist.hpp | 1524 ++++++++++ .../containers/container/stable_vector.hpp | 1351 +++++++++ .../containers/container/string.hpp | 2320 +++++++++++++++ .../containers/container/vector.hpp | 1933 +++++++++++++ .../boost/interprocess/containers/deque.hpp | 1518 +--------- .../interprocess/containers/flat_map.hpp | 1431 +--------- .../interprocess/containers/flat_set.hpp | 1234 +------- .../boost/interprocess/containers/list.hpp | 1451 +--------- include/boost/interprocess/containers/map.hpp | 1303 +-------- .../boost/interprocess/containers/pair.hpp | 32 + include/boost/interprocess/containers/set.hpp | 1176 +------- .../boost/interprocess/containers/slist.hpp | 1631 +---------- .../interprocess/containers/stable_vector.hpp | 31 + .../boost/interprocess/containers/string.hpp | 2485 +---------------- .../boost/interprocess/containers/vector.hpp | 1978 +------------ .../interprocess/containers/version_type.hpp | 33 + include/boost/interprocess/detail/atomic.hpp | 2 +- .../interprocess/detail/file_wrapper.hpp | 27 +- .../detail/managed_memory_impl.hpp | 16 +- .../detail/managed_multi_shared_memory.hpp | 8 +- .../detail/managed_open_or_create_impl.hpp | 43 +- include/boost/interprocess/detail/move.hpp | 796 +++++- .../interprocess/detail/move_iterator.hpp | 138 - include/boost/interprocess/detail/mpl.hpp | 6 +- .../boost/interprocess/detail/named_proxy.hpp | 8 +- .../interprocess/detail/os_file_functions.hpp | 119 +- .../detail/os_thread_functions.hpp | 51 +- .../interprocess/detail/preprocessor.hpp | 32 +- .../detail/segment_manager_helper.hpp | 35 +- .../interprocess/detail/tmp_dir_helpers.hpp | 79 + .../detail/transform_iterator.hpp | 180 ++ .../boost/interprocess/detail/type_traits.hpp | 4 +- .../boost/interprocess/detail/utilities.hpp | 727 +---- .../boost/interprocess/detail/win32_api.hpp | 469 +++- .../boost/interprocess/detail/workaround.hpp | 47 +- include/boost/interprocess/errors.hpp | 22 +- include/boost/interprocess/file_mapping.hpp | 65 +- .../indexes/iunordered_set_index.hpp | 6 +- .../boost/interprocess/interprocess_fwd.hpp | 132 +- .../interprocess/managed_external_buffer.hpp | 47 +- .../interprocess/managed_heap_memory.hpp | 49 +- .../interprocess/managed_mapped_file.hpp | 47 +- .../interprocess/managed_shared_memory.hpp | 52 +- .../managed_windows_shared_memory.hpp | 45 +- include/boost/interprocess/mapped_region.hpp | 166 +- .../mem_algo/detail/mem_algo_common.hpp | 762 +++-- .../detail/multi_simple_seq_fit_impl.hpp | 42 +- .../mem_algo/detail/simple_seq_fit_impl.hpp | 106 +- .../interprocess/mem_algo/rbtree_best_fit.hpp | 134 +- include/boost/interprocess/offset_ptr.hpp | 6 +- .../boost/interprocess/segment_manager.hpp | 70 +- .../interprocess/shared_memory_object.hpp | 59 +- .../boost/interprocess/smart_ptr/deleter.hpp | 5 +- .../smart_ptr/detail/shared_count.hpp | 17 +- .../smart_ptr/detail/sp_counted_impl.hpp | 39 +- .../interprocess/smart_ptr/intrusive_ptr.hpp | 3 +- .../interprocess/smart_ptr/scoped_ptr.hpp | 3 +- .../interprocess/smart_ptr/shared_ptr.hpp | 51 +- .../interprocess/smart_ptr/unique_ptr.hpp | 97 +- .../boost/interprocess/smart_ptr/weak_ptr.hpp | 3 +- .../sync/emulation/interprocess_condition.hpp | 15 +- .../interprocess_recursive_mutex.hpp | 37 +- include/boost/interprocess/sync/file_lock.hpp | 38 +- .../sync/interprocess_barrier.hpp | 4 + .../sync/interprocess_condition.hpp | 4 + .../interprocess/sync/interprocess_mutex.hpp | 6 +- .../sync/interprocess_recursive_mutex.hpp | 8 +- .../sync/interprocess_semaphore.hpp | 6 +- .../interprocess/sync/named_condition.hpp | 14 +- .../sync/posix/semaphore_wrapper.hpp | 2 +- .../boost/interprocess/sync/scoped_lock.hpp | 144 +- .../boost/interprocess/sync/sharable_lock.hpp | 99 +- .../interprocess/sync/upgradable_lock.hpp | 103 +- .../interprocess/windows_shared_memory.hpp | 32 +- proj/to-do.txt | 26 +- proj/vc7ide/Interprocess.sln | 122 +- proj/vc7ide/adaptive_node_pool_test.vcproj | 1 + proj/vc7ide/doc_adaptive_pool.vcproj | 5 - proj/vc7ide/doc_allocator.vcproj | 5 - proj/vc7ide/doc_anonymous_conditionA.vcproj | 7 +- proj/vc7ide/doc_anonymous_conditionB.vcproj | 7 +- proj/vc7ide/doc_anonymous_mutexA.vcproj | 7 +- proj/vc7ide/doc_anonymous_mutexB.vcproj | 7 +- proj/vc7ide/doc_anonymous_semaphoreA.vcproj | 7 +- proj/vc7ide/doc_anonymous_semaphoreB.vcproj | 7 +- .../vc7ide/doc_anonymous_shared_memory.vcproj | 5 - .../doc_anonymous_upgradable_mutexA.vcproj | 7 +- .../doc_anonymous_upgradable_mutexB.vcproj | 7 +- proj/vc7ide/doc_bufferstream.vcproj | 5 - proj/vc7ide/doc_cached_adaptive_pool.vcproj | 5 - proj/vc7ide/doc_cached_node_allocator.vcproj | 5 - proj/vc7ide/doc_cont.vcproj | 5 - proj/vc7ide/doc_contB.vcproj | 7 +- proj/vc7ide/doc_file_mapping.vcproj | 5 - proj/vc7ide/doc_file_mapping2.vcproj | 138 - proj/vc7ide/doc_intrusive.vcproj | 5 - ...messageA.vcproj => doc_ipc_message.vcproj} | 19 +- .../doc_managed_aligned_allocation.vcproj | 5 - .../doc_managed_allocation_command.vcproj | 5 - .../doc_managed_construction_info.vcproj | 5 - proj/vc7ide/doc_managed_grow.vcproj | 5 - proj/vc7ide/doc_managed_heap_memory.vcproj | 5 - proj/vc7ide/doc_managed_mapped_file.vcproj | 5 - .../doc_managed_multiple_allocation.vcproj | 5 - proj/vc7ide/doc_managed_raw_allocation.vcproj | 5 - proj/vc7ide/doc_map.vcproj | 5 - proj/vc7ide/doc_message_queueA.vcproj | 7 +- proj/vc7ide/doc_message_queueB.vcproj | 7 +- proj/vc7ide/doc_move_containers.vcproj | 5 - ...d_allocA.vcproj => doc_named_alloc.vcproj} | 19 +- proj/vc7ide/doc_named_conditionA.vcproj | 7 +- proj/vc7ide/doc_named_conditionB.vcproj | 7 +- proj/vc7ide/doc_named_mutex.vcproj | 5 - proj/vc7ide/doc_node_allocator.vcproj | 5 - proj/vc7ide/doc_offset_ptr.vcproj | 5 - proj/vc7ide/doc_private_adaptive_pool.vcproj | 5 - proj/vc7ide/doc_private_node_allocator.vcproj | 5 - proj/vc7ide/doc_scoped_ptr.vcproj | 5 - proj/vc7ide/doc_shared_memory.vcproj | 5 - proj/vc7ide/doc_shared_ptr.vcproj | 5 - proj/vc7ide/doc_shared_ptr_explicit.vcproj | 5 - ..._allocB.vcproj => doc_spawn_vector.vcproj} | 21 +- proj/vc7ide/doc_unique_ptr.vcproj | 5 - proj/vc7ide/doc_vectorstream.vcproj | 5 - proj/vc7ide/doc_where_allocate.vcproj | 5 - proj/vc7ide/doc_windows_shared_memory.vcproj | 5 - proj/vc7ide/doc_windows_shared_memory2.vcproj | 11 +- proj/vc7ide/interprocesslib.vcproj | 43 +- .../vc7ide/shared_memory_mappable_test.vcproj | 2 + ...sageB.vcproj => stable_vector_test.vcproj} | 23 +- proj/vc7ide/string_test.vcproj | 1 + .../windows_shared_memory_mapping_test.vcproj | 8 +- proj/vc7ide/windows_shared_memory_test.vcproj | 4 +- test/adaptive_node_pool_test.cpp | 1 + test/allocator_v1.hpp | 14 +- test/check_equal_containers.hpp | 6 +- test/data_test.cpp | 6 - test/deque_test.cpp | 44 +- test/dummy_test_allocator.hpp | 8 +- test/emplace_test.hpp | 23 +- test/expand_bwd_test_allocator.hpp | 10 +- test/file_lock_test.cpp | 12 +- test/file_mapping_test.cpp | 17 +- test/flat_tree_test.cpp | 46 +- test/get_process_id_name.hpp | 4 +- test/list_test.cpp | 5 +- test/list_test.hpp | 18 +- test/managed_mapped_file_test.cpp | 11 +- test/managed_shared_memory_test.cpp | 5 +- test/managed_windows_shared_memory_test.cpp | 7 +- test/map_test.hpp | 415 ++- test/mapped_file_test.cpp | 11 +- test/memory_algorithm_test_template.hpp | 66 +- test/movable_int.hpp | 56 +- test/multi_index_test.cpp | 56 +- test/set_test.hpp | 102 +- test/shared_memory_mapping_test.cpp | 13 +- test/shared_memory_test.cpp | 11 +- test/shared_ptr_test.cpp | 8 +- test/slist_test.cpp | 9 +- test/stable_vector_test.cpp | 90 + test/string_test.cpp | 4 +- test/tree_test.cpp | 43 +- test/unique_ptr_test.cpp | 29 +- test/upgradable_mutex_test.cpp | 70 +- test/user_buffer_test.cpp | 22 +- test/vector_test.cpp | 22 +- test/vector_test.hpp | 44 +- test/windows_shared_memory_mapping_test.cpp | 2 +- test/windows_shared_memory_test.cpp | 14 +- 274 files changed, 23335 insertions(+), 20691 deletions(-) rename example/{doc_anonymous_conditionA.cpp => comp_doc_anonymous_conditionA.cpp} (88%) rename example/{doc_anonymous_conditionB.cpp => comp_doc_anonymous_conditionB.cpp} (92%) rename example/{doc_anonymous_mutexA.cpp => comp_doc_anonymous_mutexA.cpp} (87%) create mode 100644 example/comp_doc_anonymous_mutexB.cpp create mode 100644 example/comp_doc_anonymous_semaphoreA.cpp create mode 100644 example/comp_doc_anonymous_semaphoreB.cpp create mode 100644 example/comp_doc_anonymous_upgradable_mutexA.cpp create mode 100644 example/comp_doc_anonymous_upgradable_mutexB.cpp rename example/{doc_message_queueA.cpp => comp_doc_message_queueA.cpp} (100%) rename example/{doc_message_queueB.cpp => comp_doc_message_queueB.cpp} (100%) delete mode 100644 example/doc_anonymous_mutexB.cpp delete mode 100644 example/doc_anonymous_semaphoreA.cpp delete mode 100644 example/doc_anonymous_semaphoreB.cpp delete mode 100644 example/doc_anonymous_upgradable_mutexA.cpp delete mode 100644 example/doc_anonymous_upgradable_mutexB.cpp delete mode 100644 example/doc_contA.cpp delete mode 100644 example/doc_contB.cpp delete mode 100644 example/doc_file_mapping2.cpp create mode 100644 example/doc_ipc_message.cpp delete mode 100644 example/doc_ipc_messageA.cpp delete mode 100644 example/doc_ipc_messageB.cpp rename example/{doc_named_allocA.cpp => doc_named_alloc.cpp} (50%) delete mode 100644 example/doc_named_allocB.cpp delete mode 100644 example/doc_shared_memory2.cpp create mode 100644 example/doc_spawn_vector.cpp delete mode 100644 example/doc_windows_shared_memory2.cpp create mode 100644 include/boost/interprocess/containers/allocation_type.hpp create mode 100644 include/boost/interprocess/containers/container/containers_fwd.hpp create mode 100644 include/boost/interprocess/containers/container/deque.hpp rename include/boost/interprocess/{ => containers/container}/detail/advanced_insert_int.hpp (77%) rename include/boost/interprocess/{ => containers/container}/detail/algorithms.hpp (70%) rename include/boost/interprocess/{allocators => containers/container/detail}/allocation_type.hpp (75%) create mode 100644 include/boost/interprocess/containers/container/detail/config_begin.hpp create mode 100644 include/boost/interprocess/containers/container/detail/config_end.hpp create mode 100644 include/boost/interprocess/containers/container/detail/destroyers.hpp rename include/boost/interprocess/containers/{ => container}/detail/flat_tree.hpp (80%) rename include/boost/interprocess/{ => containers/container}/detail/iterators.hpp (65%) create mode 100644 include/boost/interprocess/containers/container/detail/mpl.hpp create mode 100644 include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp rename include/boost/interprocess/containers/{ => container}/detail/node_alloc_holder.hpp (58%) create mode 100644 include/boost/interprocess/containers/container/detail/pair.hpp create mode 100644 include/boost/interprocess/containers/container/detail/preprocessor.hpp create mode 100644 include/boost/interprocess/containers/container/detail/transform_iterator.hpp rename include/boost/interprocess/containers/{ => container}/detail/tree.hpp (80%) create mode 100644 include/boost/interprocess/containers/container/detail/type_traits.hpp create mode 100644 include/boost/interprocess/containers/container/detail/utilities.hpp create mode 100644 include/boost/interprocess/containers/container/detail/value_init.hpp create mode 100644 include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp rename include/boost/interprocess/{ => containers/container}/detail/version_type.hpp (66%) create mode 100644 include/boost/interprocess/containers/container/detail/workaround.hpp create mode 100644 include/boost/interprocess/containers/container/flat_map.hpp create mode 100644 include/boost/interprocess/containers/container/flat_set.hpp create mode 100644 include/boost/interprocess/containers/container/list.hpp create mode 100644 include/boost/interprocess/containers/container/map.hpp create mode 100644 include/boost/interprocess/containers/container/set.hpp create mode 100644 include/boost/interprocess/containers/container/slist.hpp create mode 100644 include/boost/interprocess/containers/container/stable_vector.hpp create mode 100644 include/boost/interprocess/containers/container/string.hpp create mode 100644 include/boost/interprocess/containers/container/vector.hpp create mode 100644 include/boost/interprocess/containers/pair.hpp create mode 100644 include/boost/interprocess/containers/stable_vector.hpp create mode 100644 include/boost/interprocess/containers/version_type.hpp delete mode 100644 include/boost/interprocess/detail/move_iterator.hpp create mode 100644 include/boost/interprocess/detail/transform_iterator.hpp delete mode 100644 proj/vc7ide/doc_file_mapping2.vcproj rename proj/vc7ide/{doc_ipc_messageA.vcproj => doc_ipc_message.vcproj} (87%) rename proj/vc7ide/{doc_named_allocA.vcproj => doc_named_alloc.vcproj} (87%) rename proj/vc7ide/{doc_named_allocB.vcproj => doc_spawn_vector.vcproj} (85%) rename proj/vc7ide/{doc_ipc_messageB.vcproj => stable_vector_test.vcproj} (83%) create mode 100644 test/stable_vector_test.cpp diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 6eb1d7c..fdae0b2 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -25,8 +25,15 @@ doxygen autodoc EXTRACT_ALL=NO HIDE_UNDOC_MEMBERS=YES EXTRACT_PRIVATE=NO + ENABLE_PREPROCESSING=YES EXPAND_ONLY_PREDEF=YES - PREDEFINED=BOOST_INTERPROCESS_DOXYGEN_INVOKED + MACRO_EXPANSION=YES + "PREDEFINED=\"BOOST_INTERPROCESS_DOXYGEN_INVOKED\" \\ + \"BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(a)= \" \\ + \"BOOST_INTERPROCESS_RV_REF(a)=a &&\" \\ + \"BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(a)=a &&\" \\ + \"BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(a)=a &&\" \\ + \"BOOST_INTERPROCESS_FWD_REF(a)=a &&\"" "boost.doxygen.reftitle=Boost.Interprocess Reference" ; diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index c1bdc02..dc0d29d 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -94,13 +94,8 @@ You can just allocate a portion of a shared memory segment, copy the message to that buffer, send the offset of that portion of shared memory to another process, and you are done. Let's see the example: -[import ../example/doc_ipc_messageA.cpp] -[doc_ipc_messageA] - -In receiver process one just could write the following lines: - -[import ../example/doc_ipc_messageB.cpp] -[doc_ipc_messageB] +[import ../example/doc_ipc_message.cpp] +[doc_ipc_message] [endsect] @@ -108,15 +103,10 @@ In receiver process one just could write the following lines: You want to create objects in a shared memory segment, giving a string name to them so that any other process can find, use and delete them from the segment when the objects are not -needed anymore. Just write in one process: +needed anymore. Example: -[import ../example/doc_named_allocA.cpp] -[doc_named_allocA] - -In other process execute the following: - -[import ../example/doc_named_allocB.cpp] -[doc_named_allocB] +[import ../example/doc_named_alloc.cpp] +[doc_named_alloc] [endsect] @@ -148,16 +138,19 @@ list, map, so you can avoid these manual data structures just like with standard mapped files. For example, we can construct STL-like containers in shared memory. To do this, we just need to create a special (managed) shared memory segment, declare a [*Boost.Interprocess] allocator and construct the vector in shared memory -just if it was any other object. Just execute this first process: +just if it was any other object. -[import ../example/doc_contA.cpp] -[doc_contA] +The class that allows this complex structures in shared memory is called +[classref boost::interprocess::managed_shared_memory] and it's easy to use. +Just execute this example without arguments: -After this process is executed we can search the constructed vector and use it with -STL algorithms: +[import ../example/doc_spawn_vector.cpp] +[doc_spawn_vector] -[import ../example/doc_contB.cpp] -[doc_contB] +The parent process will create an special shared memory class that allows easy construction +of many complex data structures associated with a name. The parent process executes the same +program with an additional argument so the child process opens the shared memory and uses +the vector and erases it. [endsect] @@ -498,16 +491,11 @@ For more details regarding `mapped_region` see the Let's see a simple example of shared memory use. A server process creates a shared memory object, maps it and initializes all the bytes to a value. After that, a client process opens the shared memory, maps it, and checks -that the data is correctly initialized. This is the server process: +that the data is correctly initialized: [import ../example/doc_shared_memory.cpp] [doc_shared_memory] -Now the client process: - -[import ../example/doc_shared_memory2.cpp] -[doc_shared_memory2] - [endsect] [section:emulation Emulation for systems without shared memory objects] @@ -521,12 +509,11 @@ POSIX: defined by POSIX (see [link interprocess.sharedmemorybetweenprocesses.sharedmemory.windows_shared_memory Native windows shared memory] section for more information). -* Some UNIX systems don't support shared memory objects at all. MacOS is - one of these operating systems. +* Some UNIX systems don't fully support POSIX shared memory objects at all. In those platforms, shared memory is emulated with mapped files created in the temporary files directory. Because of this emulation, shared memory -has filesystem lifetime in those systems. +has filesystem lifetime in some of those systems. [endsect] @@ -554,12 +541,9 @@ the name will subsequently cause the creation of a shared memory object of this name exists (that is, trying to open an object with that name will fail and an object of the same name can be created again). -In Windows operating systems, the function fails if the object is being used, -so a programmer can't consider the UNIX behavior as the portable behavior: - -`shared_memory_object::remove` [*can] fail if the shared memory is still in use, -but this does not mean that it [*will] fail if it's in use. Just the same -behavior as the standard C (stdio.h) `int remove(const char *path)` function. +In Windows operating systems, current version supports an usually acceptable emulation +of the UNIX unlink behaviour: the file is randomly renamed and marked as to be deleted when +the last open handle is closed. [endsect] @@ -586,7 +570,6 @@ be used so that `region` is used to communicate two related processes. [endsect] - [section:windows_shared_memory Native windows shared memory] Windows operating system also offers shared memory, but the lifetime of this @@ -624,20 +607,13 @@ shared memory object, maps it and initializes all the bytes to a value. After th a client process opens the shared memory, maps it, and checks that the data is correctly initialized. Take in care that [*if the server exits before the client connects to the shared memory the client connection will fail], because -the shared memory segment is destroyed when no processes are attached to the memory. +the shared memory segment is destroyed when no proces is attached to the memory. This is the server process: [import ../example/doc_windows_shared_memory.cpp] [doc_windows_shared_memory] -Now, before destroying the -[classref boost::interprocess::windows_shared_memory windows_shared memory] -object, launch the client process: - -[import ../example/doc_windows_shared_memory2.cpp] -[doc_windows_shared_memory2] - As we can see, native windows shared memory needs synchronization to make sure that the shared memory won't be destroyed before the client is launched. @@ -801,16 +777,11 @@ Let's reproduce the same example described in the shared memory section, using memory mapped files. A server process creates a shared memory segment, maps it and initializes all the bytes to a value. After that, a client process opens the shared memory, maps it, and checks -that the data is correctly initialized. This is the server process: +that the data is correctly initialized:: [import ../example/doc_file_mapping.cpp] [doc_file_mapping] -Now the client process: - -[import ../example/doc_file_mapping2.cpp] -[doc_file_mapping2] - [endsect] [endsect] @@ -1478,17 +1449,17 @@ will write a flag when ends writing the traces This is the process main process. Creates the shared memory, constructs the cyclic buffer and start writing traces: -[import ../example/doc_anonymous_mutexA.cpp] +[import ../example/comp_doc_anonymous_mutexA.cpp] [doc_anonymous_mutexA] The second process opens the shared memory, obtains access to the cyclic buffer and starts writing traces: -[import ../example/doc_anonymous_mutexB.cpp] +[import ../example/comp_doc_anonymous_mutexB.cpp] [doc_anonymous_mutexB] -As we can see, a mutex is useful to protect data but not to notify to another process -an event. For this, we need a condition variable, as we will see in the next section. +As we can see, a mutex is useful to protect data but not to notify an event to another +process. For this, we need a condition variable, as we will see in the next section. [endsect] @@ -1583,13 +1554,13 @@ This is the process main process. Creates the shared memory, places there the buffer and starts writing messages one by one until it writes "last message" to indicate that there are no more messages to print: -[import ../example/doc_anonymous_conditionA.cpp] +[import ../example/comp_doc_anonymous_conditionA.cpp] [doc_anonymous_conditionA] The second process opens the shared memory and prints each message until the "last message" message is received: -[import ../example/doc_anonymous_conditionB.cpp] +[import ../example/comp_doc_anonymous_conditionB.cpp] [doc_anonymous_conditionB] With condition variables, a process can block if it can't continue the work, @@ -1665,13 +1636,13 @@ This is the process main process. Creates the shared memory, places there the integer array and starts integers one by one, blocking if the array is full: -[import ../example/doc_anonymous_semaphoreA.cpp] +[import ../example/comp_doc_anonymous_semaphoreA.cpp] [doc_anonymous_semaphoreA] The second process opens the shared memory and copies the received integers to it's own buffer: -[import ../example/doc_anonymous_semaphoreB.cpp] +[import ../example/comp_doc_anonymous_semaphoreB.cpp] [doc_anonymous_semaphoreB] The same interprocess communication can be achieved with a condition variables @@ -2152,11 +2123,11 @@ more features and operations, see their reference for more informations [/section:upgradable_mutexes_example Anonymous Upgradable Mutex Example] -[/import ../example/doc_anonymous_upgradable_mutexA.cpp] +[/import ../example/comp_doc_anonymous_upgradable_mutexA.cpp] [/doc_anonymous_upgradable_mutexA] -[/import ../example/doc_anonymous_upgradable_mutexB.cpp] +[/import ../example/comp_doc_anonymous_upgradable_mutexB.cpp] [/doc_anonymous_upgradable_mutexB] [/endsect] @@ -2722,7 +2693,7 @@ objects are created pointing to the same file, no synchronization is guaranteed. POSIX, when two file descriptors are used to lock a file if a descriptor is closed, all file locks set by the calling process are cleared. -To sum up, if you plan to use file locking in your processes, use the following +To sum up, if you plan to use portable file locking in your processes, use the following restrictions: * [*For each file, use a single `file_lock` object per process.] @@ -2867,12 +2838,12 @@ In the following example, the first process creates the message queue, and write an array of integers on it. The other process just reads the array and checks that the sequence number is correct. This is the first process: -[import ../example/doc_message_queueA.cpp] +[import ../example/comp_doc_message_queueA.cpp] [doc_message_queueA] This is the second process: -[import ../example/doc_message_queueB.cpp] +[import ../example/comp_doc_message_queueB.cpp] [doc_message_queueB] To know more about this class and all its operations, please see the @@ -3246,11 +3217,16 @@ To use a managed mapped file, you must include the following header: managed_mapped_file mfile (open_or_create, "MyMappedFile", //Mapped file name 65536); //Mapped file size When the `managed_mapped_file` object is destroyed, the file is automatically unmapped, and all the resources are freed. To remove -the file from the filesystem you can use standard C `std::remove` -or [*Boost.Filesystem]'s `remove()` functions. File removing might fail +the file from the filesystem you could use standard C `std::remove` +or [*Boost.Filesystem]'s `remove()` functions, but file removing might fail if any process still has the file mapped in memory or the file is open by any process. +To obtain a more portable behaviour, use `file_mapping::remove(const char *)` operation, which +will remove the file even if it's being mapped. However, removal will fail in some OS systems if +the file (eg. by C++ file streams) and no delete share permission was granted to the file. But in +most common cases `file_mapping::remove` is portable enough. + [endsect] For more information about managed mapped file capabilities, see @@ -3871,20 +3847,20 @@ Here is the declaration of the function: [c++] - enum allocation_type + enum boost::interprocess::allocation_type { //Bitwise OR (|) combinable values - allocate_new = ..., - expand_fwd = ..., - expand_bwd = ..., - shrink_in_place = ..., - nothrow_allocation = ... + boost::interprocess::allocate_new = ..., + boost::interprocess::expand_fwd = ..., + boost::interprocess::expand_bwd = ..., + boost::interprocess::shrink_in_place = ..., + boost::interprocess::nothrow_allocation = ... }; template std::pair - allocation_command( allocation_type command + allocation_command( boost::interprocess::allocation_type command , std::size_t limit_size , std::size_t preferred_size , std::size_t &received_size @@ -3893,66 +3869,66 @@ Here is the declaration of the function: [*Preconditions for the function]: -* If the parameter command contains the value `shrink_in_place` it can't -contain any of these values: `expand_fwd`, `expand_bwd`. +* If the parameter command contains the value `boost::interprocess::shrink_in_place` it can't +contain any of these values: `boost::interprocess::expand_fwd`, `boost::interprocess::expand_bwd`. -* If the parameter command contains `expand_fwd` or `expand_bwd`, the parameter +* If the parameter command contains `boost::interprocess::expand_fwd` or `boost::interprocess::expand_bwd`, the parameter `reuse_ptr` must be non-null and returned by a previous allocation function. -* If the parameter command contains the value `shrink_in_place`, the parameter +* If the parameter command contains the value `boost::interprocess::shrink_in_place`, the parameter `limit_size` must be equal or greater than the parameter `preferred_size`. -* If the parameter `command` contains any of these values: `expand_fwd` or `expand_bwd`, +* If the parameter `command` contains any of these values: `boost::interprocess::expand_fwd` or `boost::interprocess::expand_bwd`, the parameter `limit_size` must be equal or less than the parameter `preferred_size`. [*Which are the effects of this function:] -* If the parameter command contains the value `shrink_in_place`, the function +* If the parameter command contains the value `boost::interprocess::shrink_in_place`, the function will try to reduce the size of the memory block referenced by pointer `reuse_ptr` to the value `preferred_size` moving only the end of the block. If it's not possible, it will try to reduce the size of the memory block as much as possible as long as this results in `size(p) <= limit_size`. Success is reported only if this results in `preferred_size <= size(p)` and `size(p) <= limit_size`. -* If the parameter `command` only contains the value `expand_fwd` (with optional - additional `nothrow_allocation`), the allocator will try to increase the size of the +* If the parameter `command` only contains the value `boost::interprocess::expand_fwd` (with optional + additional `boost::interprocess::nothrow_allocation`), the allocator will try to increase the size of the memory block referenced by pointer reuse moving only the end of the block to the value `preferred_size`. If it's not possible, it will try to increase the size of the memory block as much as possible as long as this results in `size(p) >= limit_size`. Success is reported only if this results in `limit_size <= size(p)`. -* If the parameter `command` only contains the value `expand_bwd` (with optional - additional `nothrow_allocation`), the allocator will try to increase the size of +* If the parameter `command` only contains the value `boost::interprocess::expand_bwd` (with optional + additional `boost::interprocess::nothrow_allocation`), the allocator will try to increase the size of the memory block referenced by pointer `reuse_ptr` only moving the start of the block to a returned new position `new_ptr`. If it's not possible, it will try to move the start of the block as much as possible as long as this results in `size(new_ptr) >= limit_size`. Success is reported only if this results in `limit_size <= size(new_ptr)`. -* If the parameter `command` only contains the value `allocate_new` (with optional - additional `nothrow_allocation`), the allocator will try to allocate memory for +* If the parameter `command` only contains the value `boost::interprocess::allocate_new` (with optional + additional `boost::interprocess::nothrow_allocation`), the allocator will try to allocate memory for `preferred_size` objects. If it's not possible it will try to allocate memory for at least `limit_size` objects. -* If the parameter `command` only contains a combination of `expand_fwd` and - `allocate_new`, (with optional additional `nothrow_allocation`) the allocator will +* If the parameter `command` only contains a combination of `boost::interprocess::expand_fwd` and + `boost::interprocess::allocate_new`, (with optional additional `boost::interprocess::nothrow_allocation`) the allocator will try first the forward expansion. If this fails, it would try a new allocation. -* If the parameter `command` only contains a combination of `expand_bwd` and - `allocate_new` (with optional additional `nothrow_allocation`), the allocator will +* If the parameter `command` only contains a combination of `boost::interprocess::expand_bwd` and + `boost::interprocess::allocate_new` (with optional additional `boost::interprocess::nothrow_allocation`), the allocator will try first to obtain `preferred_size` objects using both methods if necessary. If this fails, it will try to obtain `limit_size` objects using both methods if necessary. -* If the parameter `command` only contains a combination of `expand_fwd` and - `expand_bwd` (with optional additional `nothrow_allocation`), the allocator will +* If the parameter `command` only contains a combination of `boost::interprocess::expand_fwd` and + `boost::interprocess::expand_bwd` (with optional additional `boost::interprocess::nothrow_allocation`), the allocator will try first forward expansion. If this fails it will try to obtain preferred_size objects using backwards expansion or a combination of forward and backwards expansion. If this fails, it will try to obtain `limit_size` objects using both methods if necessary. * If the parameter `command` only contains a combination of allocation_new, - `expand_fwd` and `expand_bwd`, (with optional additional `nothrow_allocation`) + `boost::interprocess::expand_fwd` and `boost::interprocess::expand_bwd`, (with optional additional `boost::interprocess::nothrow_allocation`) the allocator will try first forward expansion. If this fails it will try to obtain preferred_size objects using new allocation, backwards expansion or a combination of forward and backwards expansion. If this fails, it will try to obtain `limit_size` @@ -3967,13 +3943,13 @@ contain any of these values: `expand_fwd`, `expand_bwd`. * The allocator is unable to allocate/expand/shrink the memory or there is an error in preconditions -* The parameter command does not contain `nothrow_allocation`. +* The parameter command does not contain `boost::interprocess::nothrow_allocation`. [*This function returns:] * The address of the allocated memory or the new address of the expanded memory as the first member of the pair. If the parameter command contains - `nothrow_allocation` the first member will be 0 + `boost::interprocess::nothrow_allocation` the first member will be 0 if the allocation/expansion fails or there is an error in preconditions. * The second member of the pair will be false if the memory has been allocated, @@ -5018,7 +4994,7 @@ Let's see an example: [endsect] -[section:containers_and_move_semantics Move semantics in Interprocess containers] +[section:containers_and_move Move semantics in Interprocess containers] [*Boost.Interprocess] containers support move semantics, which means that the contents of a container can be moved from a container two another one, without any copying. The @@ -5030,7 +5006,7 @@ objects in the container, avoiding unnecessary copies. To transfer the contents of a container to another one, use -`boost::interprocess::move()` function, as shown in the example. For more details +`boost::move()` function, as shown in the example. For more details about functions supporting move-semantics, see the reference section of Boost.Interprocess containers: @@ -6541,6 +6517,17 @@ warranty. [section:release_notes Release Notes] +[section:release_notes_boost_1_39_00 Boost 1.39 Release] + +* Added experimental `stable_vector` container. +* `shared_memory_object::remove` has now POSIX `unlink` semantics and + `file_mapping::remove` was added to obtain POSIX `unlink` semantics with mapped files. +* Shared memory in windows has now kernel lifetime instead of filesystem lifetime: shared + memory will disappear when the system reboots. +* Updated move semantics. + +[endsect] + [section:release_notes_boost_1_38_00 Boost 1.38 Release] * Updated documentation to show rvalue-references funcions instead of emulation functions. diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 9551f9f..ba27162 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -19,7 +19,7 @@ rule test_all { local all_rules = ; - for local fileb in [ glob *.cpp ] + for local fileb in [ glob comp*.cpp ] { all_rules += [ link $(fileb) /boost/thread//boost_thread : # additional args @@ -28,6 +28,17 @@ rule test_all ] ; } + for local fileb in [ glob doc_*.cpp ] + { + all_rules += [ run $(fileb) /boost/thread//boost_thread + : # additional args + : # test-files + : # requirements + acc:-lrt + acc-pa_risc:-lrt + ] ; + } + return $(all_rules) ; } diff --git a/example/doc_anonymous_conditionA.cpp b/example/comp_doc_anonymous_conditionA.cpp similarity index 88% rename from example/doc_anonymous_conditionA.cpp rename to example/comp_doc_anonymous_conditionA.cpp index 1fb3336..cd0c7d3 100644 --- a/example/doc_anonymous_conditionA.cpp +++ b/example/comp_doc_anonymous_conditionA.cpp @@ -21,13 +21,17 @@ using namespace boost::interprocess; int main () { - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); + //Erase previous shared memory and schedule erasure on exit + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create - ,"shared_memory" //name + ,"MySharedMemory" //name ,read_write //read-write mode ); try{ @@ -66,13 +70,10 @@ int main () } } catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); std::cout << ex.what() << std::endl; return 1; } - //Erase shared memory - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_anonymous_conditionB.cpp b/example/comp_doc_anonymous_conditionB.cpp similarity index 92% rename from example/doc_anonymous_conditionB.cpp rename to example/comp_doc_anonymous_conditionB.cpp index 06d0a55..baa6a58 100644 --- a/example/doc_anonymous_conditionB.cpp +++ b/example/comp_doc_anonymous_conditionB.cpp @@ -23,7 +23,7 @@ int main () //Create a shared memory object. shared_memory_object shm (open_only //only create - ,"shared_memory" //name + ,"MySharedMemory" //name ,read_write //read-write mode ); @@ -61,13 +61,10 @@ int main () while(!end_loop); } catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); std::cout << ex.what() << std::endl; return 1; } - //Erase shared memory - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/doc_anonymous_mutexA.cpp b/example/comp_doc_anonymous_mutexA.cpp similarity index 87% rename from example/doc_anonymous_mutexA.cpp rename to example/comp_doc_anonymous_mutexA.cpp index 04710fb..bbbc33c 100644 --- a/example/doc_anonymous_mutexA.cpp +++ b/example/comp_doc_anonymous_mutexA.cpp @@ -21,13 +21,17 @@ using namespace boost::interprocess; int main () { try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create - ,"shared_memory" //name + ,"MySharedMemory" //name ,read_write //read-write mode ); @@ -65,12 +69,9 @@ int main () } } catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); std::cout << ex.what() << std::endl; return 1; } - //Erase shared memory - shared_memory_object::remove("shared_memory"); return 0; } //] diff --git a/example/comp_doc_anonymous_mutexB.cpp b/example/comp_doc_anonymous_mutexB.cpp new file mode 100644 index 0000000..4a7ed40 --- /dev/null +++ b/example/comp_doc_anonymous_mutexB.cpp @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_anonymous_mutexB +#include +#include +#include +#include "doc_anonymous_mutex_shared_data.hpp" +#include +#include + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Open the shared memory object. + shared_memory_object shm + (open_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_memory_log * data = static_cast(addr); + + //Write some logs + for(int i = 0; i < 100; ++i){ + //Lock the mutex + scoped_lock lock(data->mutex); + std::sprintf(data->items[(data->current_line++) % shared_memory_log::NumItems] + ,"%s_%d", "process_a", i); + if(i == (shared_memory_log::NumItems-1)) + data->end_b = true; + //Mutex is released here + } + + //Wait until the other process ends + while(1){ + scoped_lock lock(data->mutex); + if(data->end_a) + break; + } + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_semaphoreA.cpp b/example/comp_doc_anonymous_semaphoreA.cpp new file mode 100644 index 0000000..856ecfc --- /dev/null +++ b/example/comp_doc_anonymous_semaphoreA.cpp @@ -0,0 +1,64 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_anonymous_semaphoreA +#include +#include +#include +#include "doc_anonymous_semaphore_shared_data.hpp" + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a shared memory object. + shared_memory_object shm + (create_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Set size + shm.truncate(sizeof(shared_memory_buffer)); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_memory_buffer * data = new (addr) shared_memory_buffer; + + const int NumMsg = 100; + + //Insert data in the array + for(int i = 0; i < NumMsg; ++i){ + data->nempty.wait(); + data->mutex.wait(); + data->items[i % shared_memory_buffer::NumItems] = i; + data->mutex.post(); + data->nstored.post(); + } + + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_semaphoreB.cpp b/example/comp_doc_anonymous_semaphoreB.cpp new file mode 100644 index 0000000..29975f7 --- /dev/null +++ b/example/comp_doc_anonymous_semaphoreB.cpp @@ -0,0 +1,61 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_anonymous_semaphoreB +#include +#include +#include +#include "doc_anonymous_semaphore_shared_data.hpp" + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a shared memory object. + shared_memory_object shm + (open_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Obtain the shared structure + shared_memory_buffer * data = static_cast(addr); + + const int NumMsg = 100; + + int extracted_data [NumMsg]; + + //Extract the data + for(int i = 0; i < NumMsg; ++i){ + data->nstored.wait(); + data->mutex.wait(); + extracted_data[i] = data->items[i % shared_memory_buffer::NumItems]; + data->mutex.post(); + data->nempty.post(); + } + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_upgradable_mutexA.cpp b/example/comp_doc_anonymous_upgradable_mutexA.cpp new file mode 100644 index 0000000..b07d9dd --- /dev/null +++ b/example/comp_doc_anonymous_upgradable_mutexA.cpp @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +//[doc_anonymous_upgradable_mutexA +#include +#include +#include +#include "doc_upgradable_mutex_shared_data.hpp" +#include +#include + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a shared memory object. + shared_memory_object shm + (create_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Set size + shm.truncate(sizeof(shared_data)); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_data * data = new (addr) shared_data; + + //Write some logs + for(int i = 0; i < shared_data::NumItems; ++i){ + //Lock the upgradable_mutex + scoped_lock lock(data->upgradable_mutex); + std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] + ,"%s_%d", "process_a", i); + if(i == (shared_data::NumItems-1)) + data->end_a = true; + //Mutex is released here + } + + //Wait until the other process ends + while(1){ + scoped_lock lock(data->upgradable_mutex); + if(data->end_b) + break; + } + + return 0; +} +//] +#include diff --git a/example/comp_doc_anonymous_upgradable_mutexB.cpp b/example/comp_doc_anonymous_upgradable_mutexB.cpp new file mode 100644 index 0000000..e0448e7 --- /dev/null +++ b/example/comp_doc_anonymous_upgradable_mutexB.cpp @@ -0,0 +1,70 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include + +//[doc_anonymous_upgradable_mutexB +#include +#include +#include +#include "doc_upgradable_mutex_shared_data.hpp" +#include +#include + +using namespace boost::interprocess; + +int main () +{ + //Remove shared memory on destruction + struct shm_destroy + { + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Open the shared memory object. + shared_memory_object shm + (open_only //only create + ,"MySharedMemory" //name + ,read_write //read-write mode + ); + + //Map the whole shared memory in this process + mapped_region region + (shm //What to map + ,read_write //Map it as read-write + ); + + //Get the address of the mapped region + void * addr = region.get_address(); + + //Construct the shared structure in memory + shared_data * data = static_cast(addr); + + //Write some logs + for(int i = 0; i < 100; ++i){ + //Lock the upgradable_mutex + scoped_lock lock(data->upgradable_mutex); + std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] + ,"%s_%d", "process_a", i); + if(i == (shared_data::NumItems-1)) + data->end_b = true; + //Mutex is released here + } + + //Wait until the other process ends + while(1){ + scoped_lock lock(data->upgradable_mutex); + if(data->end_a) + break; + } + return 0; +} +//] + +#include diff --git a/example/doc_message_queueA.cpp b/example/comp_doc_message_queueA.cpp similarity index 100% rename from example/doc_message_queueA.cpp rename to example/comp_doc_message_queueA.cpp diff --git a/example/doc_message_queueB.cpp b/example/comp_doc_message_queueB.cpp similarity index 100% rename from example/doc_message_queueB.cpp rename to example/comp_doc_message_queueB.cpp diff --git a/example/doc_adaptive_pool.cpp b/example/doc_adaptive_pool.cpp index 9aeb0d4..e013ea3 100644 --- a/example/doc_adaptive_pool.cpp +++ b/example/doc_adaptive_pool.cpp @@ -18,46 +18,44 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a adaptive_pool that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef adaptive_pool - adaptive_pool_t; - adaptive_pool_t allocator_instance(segment.get_segment_manager()); + //Create a adaptive_pool that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef adaptive_pool + adaptive_pool_t; + adaptive_pool_t allocator_instance(segment.get_segment_manager()); - //Create another adaptive_pool. Since the segment manager address - //is the same, this adaptive_pool will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - adaptive_pool_t allocator_instance2(segment.get_segment_manager()); + //Create another adaptive_pool. Since the segment manager address + //is the same, this adaptive_pool will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + adaptive_pool_t allocator_instance2(segment.get_segment_manager()); - //Create another adaptive_pool using copy-constructor. This - //adaptive_pool will also be attached to the same pool - adaptive_pool_t allocator_instance3(allocator_instance2); + //Create another adaptive_pool using copy-constructor. This + //adaptive_pool will also be attached to the same pool + adaptive_pool_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_allocator.cpp b/example/doc_allocator.cpp index 87b071d..132658f 100644 --- a/example/doc_allocator.cpp +++ b/example/doc_allocator.cpp @@ -18,7 +18,12 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create shared memory managed_shared_memory segment(create_only, diff --git a/example/doc_anonymous_mutexB.cpp b/example/doc_anonymous_mutexB.cpp deleted file mode 100644 index c7854eb..0000000 --- a/example/doc_anonymous_mutexB.cpp +++ /dev/null @@ -1,70 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -//[doc_anonymous_mutexB -#include -#include -#include -#include "doc_anonymous_mutex_shared_data.hpp" -#include -#include - -using namespace boost::interprocess; - -int main () -{ - try{ - //Open the shared memory object. - shared_memory_object shm - (open_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_memory_log * data = static_cast(addr); - - //Write some logs - for(int i = 0; i < 100; ++i){ - //Lock the mutex - scoped_lock lock(data->mutex); - std::sprintf(data->items[(data->current_line++) % shared_memory_log::NumItems] - ,"%s_%d", "process_a", i); - if(i == (shared_memory_log::NumItems-1)) - data->end_b = true; - //Mutex is released here - } - - //Wait until the other process ends - while(1){ - scoped_lock lock(data->mutex); - if(data->end_a) - break; - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - shared_memory_object::remove("shared_memory"); - return 0; -} -//] -#include diff --git a/example/doc_anonymous_semaphoreA.cpp b/example/doc_anonymous_semaphoreA.cpp deleted file mode 100644 index f687049..0000000 --- a/example/doc_anonymous_semaphoreA.cpp +++ /dev/null @@ -1,70 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -//[doc_anonymous_semaphoreA -#include -#include -#include -#include "doc_anonymous_semaphore_shared_data.hpp" - -using namespace boost::interprocess; - -int main () -{ - try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); - - //Create a shared memory object. - shared_memory_object shm - (create_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Set size - shm.truncate(sizeof(shared_memory_buffer)); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_memory_buffer * data = new (addr) shared_memory_buffer; - - const int NumMsg = 100; - - //Insert data in the array - for(int i = 0; i < NumMsg; ++i){ - data->nempty.wait(); - data->mutex.wait(); - data->items[i % shared_memory_buffer::NumItems] = i; - data->mutex.post(); - data->nstored.post(); - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - - //Erase shared memory - shared_memory_object::remove("shared_memory"); - - return 0; -} -//] -#include diff --git a/example/doc_anonymous_semaphoreB.cpp b/example/doc_anonymous_semaphoreB.cpp deleted file mode 100644 index daf4e98..0000000 --- a/example/doc_anonymous_semaphoreB.cpp +++ /dev/null @@ -1,66 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -//[doc_anonymous_semaphoreB -#include -#include -#include -#include "doc_anonymous_semaphore_shared_data.hpp" - -using namespace boost::interprocess; - -int main () -{ - try{ - //Create a shared memory object. - shared_memory_object shm - (open_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Obtain the shared structure - shared_memory_buffer * data = static_cast(addr); - - const int NumMsg = 100; - - int extracted_data [NumMsg]; - - //Extract the data - for(int i = 0; i < NumMsg; ++i){ - data->nstored.wait(); - data->mutex.wait(); - extracted_data[i] = data->items[i % shared_memory_buffer::NumItems]; - data->mutex.post(); - data->nempty.post(); - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - - //Erase shared memory - shared_memory_object::remove("shared_memory"); - - return 0; -} -//] -#include diff --git a/example/doc_anonymous_upgradable_mutexA.cpp b/example/doc_anonymous_upgradable_mutexA.cpp deleted file mode 100644 index 158ea1c..0000000 --- a/example/doc_anonymous_upgradable_mutexA.cpp +++ /dev/null @@ -1,79 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -//[doc_anonymous_upgradable_mutexA -#include -#include -#include -#include "doc_upgradable_mutex_shared_data.hpp" -#include -#include - -using namespace boost::interprocess; - -int main () -{ - try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); - - //Create a shared memory object. - shared_memory_object shm - (create_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Set size - shm.truncate(sizeof(shared_data)); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_data * data = new (addr) shared_data; - - //Write some logs - for(int i = 0; i < shared_data::NumItems; ++i){ - //Lock the upgradable_mutex - scoped_lock lock(data->upgradable_mutex); - std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] - ,"%s_%d", "process_a", i); - if(i == (shared_data::NumItems-1)) - data->end_a = true; - //Mutex is released here - } - - //Wait until the other process ends - while(1){ - scoped_lock lock(data->upgradable_mutex); - if(data->end_b) - break; - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - - //Erase shared memory - shared_memory_object::remove("shared_memory"); - - return 0; -} -//] -#include diff --git a/example/doc_anonymous_upgradable_mutexB.cpp b/example/doc_anonymous_upgradable_mutexB.cpp deleted file mode 100644 index 1b83e11..0000000 --- a/example/doc_anonymous_upgradable_mutexB.cpp +++ /dev/null @@ -1,72 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include - -//[doc_anonymous_upgradable_mutexB -#include -#include -#include -#include "doc_upgradable_mutex_shared_data.hpp" -#include -#include - -using namespace boost::interprocess; - -int main () -{ - try{ - //Open the shared memory object. - shared_memory_object shm - (open_only //only create - ,"shared_memory" //name - ,read_write //read-write mode - ); - - //Map the whole shared memory in this process - mapped_region region - (shm //What to map - ,read_write //Map it as read-write - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - - //Construct the shared structure in memory - shared_data * data = static_cast(addr); - - //Write some logs - for(int i = 0; i < 100; ++i){ - //Lock the upgradable_mutex - scoped_lock lock(data->upgradable_mutex); - std::sprintf(data->items[(data->current_line++) % shared_data::NumItems] - ,"%s_%d", "process_a", i); - if(i == (shared_data::NumItems-1)) - data->end_b = true; - //Mutex is released here - } - - //Wait until the other process ends - while(1){ - scoped_lock lock(data->upgradable_mutex); - if(data->end_a) - break; - } - } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; - } - shared_memory_object::remove("shared_memory"); - return 0; -} -//] - -#include diff --git a/example/doc_bufferstream.cpp b/example/doc_bufferstream.cpp index 4fd6d75..9e14d6a 100644 --- a/example/doc_bufferstream.cpp +++ b/example/doc_bufferstream.cpp @@ -14,72 +14,73 @@ #include #include #include +#include using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Fill data - std::vector data, data2; - data.reserve(100); - for(int i = 0; i < 100; ++i){ - data.push_back(i); - } + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Allocate a buffer in shared memory to write data - char *my_cstring = - segment.construct("MyCString")[100*5](0); - bufferstream mybufstream(my_cstring, 100*5); - - //Now write data to the buffer - for(int i = 0; i < 100; ++i){ - mybufstream << data[i] << std::endl; - } - - //Check there was no overflow attempt - assert(mybufstream.good()); - - //Extract all values from the shared memory string - //directly to a vector. - data2.reserve(100); - std::istream_iterator it(mybufstream), itend; - std::copy(it, itend, std::back_inserter(data2)); - - //This extraction should have ended will fail error since - //the numbers formatted in the buffer end before the end - //of the buffer. (Otherwise it would trigger eofbit) - assert(mybufstream.fail()); - - //Compare data - assert(std::equal(data.begin(), data.end(), data2.begin())); - - //Clear errors and rewind - mybufstream.clear(); - mybufstream.seekp(0, std::ios::beg); - - //Now write again the data trying to do a buffer overflow - for(int i = 0; i < 500; ++i){ - mybufstream << data[i] << std::endl; - } - - //Now make sure badbit is active - //which means overflow attempt. - assert(!mybufstream.good()); - assert(mybufstream.bad()); - segment.destroy_ptr(my_cstring); + //Fill data + std::vector data; + data.reserve(100); + for(int i = 0; i < 100; ++i){ + data.push_back(i); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + const std::size_t BufferSize = 100*5; + + //Allocate a buffer in shared memory to write data + char *my_cstring = + segment.construct("MyCString")[BufferSize](0); + bufferstream mybufstream(my_cstring, BufferSize); + + //Now write data to the buffer + for(int i = 0; i < 100; ++i){ + mybufstream << data[i] << std::endl; } - shared_memory_object::remove("MySharedMemory"); + + //Check there was no overflow attempt + assert(mybufstream.good()); + + //Extract all values from the shared memory string + //directly to a vector. + std::vector data2; + std::istream_iterator it(mybufstream), itend; + std::copy(it, itend, std::back_inserter(data2)); + + //This extraction should have ended will fail error since + //the numbers formatted in the buffer end before the end + //of the buffer. (Otherwise it would trigger eofbit) + assert(mybufstream.fail()); + + //Compare data + assert(std::equal(data.begin(), data.end(), data2.begin())); + + //Clear errors and rewind + mybufstream.clear(); + mybufstream.seekp(0, std::ios::beg); + + //Now write again the data trying to do a buffer overflow + for(int i = 0, m = data.size()*5; i < m; ++i){ + mybufstream << data[i%5] << std::endl; + } + + //Now make sure badbit is active + //which means overflow attempt. + assert(!mybufstream.good()); + assert(mybufstream.bad()); + segment.destroy_ptr(my_cstring); return 0; } //] diff --git a/example/doc_cached_adaptive_pool.cpp b/example/doc_cached_adaptive_pool.cpp index c138ef0..6f0f7bf 100644 --- a/example/doc_cached_adaptive_pool.cpp +++ b/example/doc_cached_adaptive_pool.cpp @@ -18,54 +18,53 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create a cached_adaptive_pool that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef cached_adaptive_pool - cached_adaptive_pool_t; - cached_adaptive_pool_t allocator_instance(segment.get_segment_manager()); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //The max cached nodes are configurable per instance - allocator_instance.set_max_cached_nodes(3); + //Create a cached_adaptive_pool that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef cached_adaptive_pool + cached_adaptive_pool_t; + cached_adaptive_pool_t allocator_instance(segment.get_segment_manager()); - //Create another cached_adaptive_pool. Since the segment manager address - //is the same, this cached_adaptive_pool will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - cached_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); + //The max cached nodes are configurable per instance + allocator_instance.set_max_cached_nodes(3); - //The max cached nodes are configurable per instance - allocator_instance2.set_max_cached_nodes(5); + //Create another cached_adaptive_pool. Since the segment manager address + //is the same, this cached_adaptive_pool will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + cached_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); - //Create another cached_adaptive_pool using copy-constructor. This - //cached_adaptive_pool will also be attached to the same pool - cached_adaptive_pool_t allocator_instance3(allocator_instance2); + //The max cached nodes are configurable per instance + allocator_instance2.set_max_cached_nodes(5); - //We can clear the cache - allocator_instance3.deallocate_cache(); + //Create another cached_adaptive_pool using copy-constructor. This + //cached_adaptive_pool will also be attached to the same pool + cached_adaptive_pool_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //We can clear the cache + allocator_instance3.deallocate_cache(); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_cached_node_allocator.cpp b/example/doc_cached_node_allocator.cpp index 091a17e..0d19046 100644 --- a/example/doc_cached_node_allocator.cpp +++ b/example/doc_cached_node_allocator.cpp @@ -18,54 +18,53 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create a cached_node_allocator that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef cached_node_allocator - cached_node_allocator_t; - cached_node_allocator_t allocator_instance(segment.get_segment_manager()); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //The max cached nodes are configurable per instance - allocator_instance.set_max_cached_nodes(3); + //Create a cached_node_allocator that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef cached_node_allocator + cached_node_allocator_t; + cached_node_allocator_t allocator_instance(segment.get_segment_manager()); - //Create another cached_node_allocator. Since the segment manager address - //is the same, this cached_node_allocator will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - cached_node_allocator_t allocator_instance2(segment.get_segment_manager()); + //The max cached nodes are configurable per instance + allocator_instance.set_max_cached_nodes(3); - //The max cached nodes are configurable per instance - allocator_instance2.set_max_cached_nodes(5); + //Create another cached_node_allocator. Since the segment manager address + //is the same, this cached_node_allocator will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + cached_node_allocator_t allocator_instance2(segment.get_segment_manager()); - //Create another cached_node_allocator using copy-constructor. This - //cached_node_allocator will also be attached to the same pool - cached_node_allocator_t allocator_instance3(allocator_instance2); + //The max cached nodes are configurable per instance + allocator_instance2.set_max_cached_nodes(5); - //We can clear the cache - allocator_instance3.deallocate_cache(); + //Create another cached_node_allocator using copy-constructor. This + //cached_node_allocator will also be attached to the same pool + cached_node_allocator_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //We can clear the cache + allocator_instance3.deallocate_cache(); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_complex_map.cpp b/example/doc_complex_map.cpp index 1d64dac..e8d7238 100644 --- a/example/doc_complex_map.cpp +++ b/example/doc_complex_map.cpp @@ -52,28 +52,31 @@ typedef map< char_string, complex_data int main () { - shared_memory_object::remove("MySharedMemory"); - remove_shared_memory_on_destroy remove_on_destroy("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy { - //Create shared memory - managed_shared_memory segment(create_only,"MySharedMemory", 65536); + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //An allocator convertible to any allocator type - void_allocator alloc_inst (segment.get_segment_manager()); + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); - //Construct the shared memory map and fill it - complex_map_type *mymap = segment.construct - //(object name), (first ctor parameter, second ctor parameter) - ("MyMap")(std::less(), alloc_inst); + //An allocator convertible to any allocator type + void_allocator alloc_inst (segment.get_segment_manager()); - for(int i = 0; i < 100; ++i){ - //Both key(string) and value(complex_data) need an allocator in their constructors - char_string key_object(alloc_inst); - complex_data mapped_object(i, "default_name", alloc_inst); - map_value_type value(key_object, mapped_object); - //Modify values and insert them in the map - mymap->insert(value); - } + //Construct the shared memory map and fill it + complex_map_type *mymap = segment.construct + //(object name), (first ctor parameter, second ctor parameter) + ("MyMap")(std::less(), alloc_inst); + + for(int i = 0; i < 100; ++i){ + //Both key(string) and value(complex_data) need an allocator in their constructors + char_string key_object(alloc_inst); + complex_data mapped_object(i, "default_name", alloc_inst); + map_value_type value(key_object, mapped_object); + //Modify values and insert them in the map + mymap->insert(value); } return 0; } diff --git a/example/doc_cont.cpp b/example/doc_cont.cpp index 6b899ae..cd0680d 100644 --- a/example/doc_cont.cpp +++ b/example/doc_cont.cpp @@ -17,48 +17,47 @@ int main () { using namespace boost::interprocess; - shared_memory_object::remove("MySharedMemory"); - try{ - //A managed shared memory where we can construct objects - //associated with a c-string - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Alias an STL-like allocator of ints that allocates ints from the segment - typedef allocator - ShmemAllocator; + //A managed shared memory where we can construct objects + //associated with a c-string + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Alias a vector that uses the previous STL-like allocator - typedef vector MyVector; + //Alias an STL-like allocator of ints that allocates ints from the segment + typedef allocator + ShmemAllocator; - int initVal[] = {0, 1, 2, 3, 4, 5, 6 }; - const int *begVal = initVal; - const int *endVal = initVal + sizeof(initVal)/sizeof(initVal[0]); + //Alias a vector that uses the previous STL-like allocator + typedef vector MyVector; - //Initialize the STL-like allocator - const ShmemAllocator alloc_inst (segment.get_segment_manager()); + int initVal[] = {0, 1, 2, 3, 4, 5, 6 }; + const int *begVal = initVal; + const int *endVal = initVal + sizeof(initVal)/sizeof(initVal[0]); - //Construct the vector in the shared memory segment with the STL-like allocator - //from a range of iterators - MyVector *myvector = - segment.construct - ("MyVector")/*object name*/ - (begVal /*first ctor parameter*/, - endVal /*second ctor parameter*/, - alloc_inst /*third ctor parameter*/); + //Initialize the STL-like allocator + const ShmemAllocator alloc_inst (segment.get_segment_manager()); - //Use vector as your want - std::sort(myvector->rbegin(), myvector->rend()); - // . . . - //When done, destroy and delete vector from the segment - segment.destroy("MyVector"); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Construct the vector in the shared memory segment with the STL-like allocator + //from a range of iterators + MyVector *myvector = + segment.construct + ("MyVector")/*object name*/ + (begVal /*first ctor parameter*/, + endVal /*second ctor parameter*/, + alloc_inst /*third ctor parameter*/); + + //Use vector as your want + std::sort(myvector->rbegin(), myvector->rend()); + // . . . + //When done, destroy and delete vector from the segment + segment.destroy("MyVector"); return 0; } //] diff --git a/example/doc_contA.cpp b/example/doc_contA.cpp deleted file mode 100644 index 72812da..0000000 --- a/example/doc_contA.cpp +++ /dev/null @@ -1,60 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -#include -//[doc_contA -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //Shared memory front-end that is able to construct objects - //associated with a c-string. Erase previous shared memory with the name - //to be used and create the memory segment at the specified address and initialize resources - shared_memory_object::remove("MySharedMemory"); - managed_shared_memory segment - (create_only - ,"MySharedMemory" //segment name - ,65536); //segment size in bytes - - //Alias an STL compatible allocator of ints that allocates ints from the managed - //shared memory segment. This allocator will allow to place containers - //in managed shared memory segments - typedef allocator - ShmemAllocator; - - //Alias a vector that uses the previous STL-like allocator - typedef vector MyVector; - - //Initialize shared memory STL-compatible allocator - const ShmemAllocator alloc_inst (segment.get_segment_manager()); - - //Construct a shared memory - MyVector *myvector = - segment.construct("MyVector") //object name - (alloc_inst);//first ctor parameter - - //Insert data in the vector - for(int i = 0; i < 100; ++i){ - myvector->push_back(i); - } - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_contB.cpp b/example/doc_contB.cpp deleted file mode 100644 index 4aad144..0000000 --- a/example/doc_contB.cpp +++ /dev/null @@ -1,57 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -#include -//[doc_contB -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //A special shared memory where we can - //construct objects associated with a name. - //Connect to the already created shared memory segment - //and initialize needed resources - managed_shared_memory segment - (open_only - ,"MySharedMemory"); //segment name - - //Alias an STL compatible allocator of ints that allocates ints from the managed - //shared memory segment. This allocator will allow to place containers - //in managed shared memory segments - typedef allocator - ShmemAllocator; - - //Alias a vector that uses the previous STL-like allocator - typedef vector MyVector; - - //Find the vector using the c-string name - MyVector *myvector = segment.find("MyVector").first; - - //Use vector in reverse order - std::sort(myvector->rbegin(), myvector->rend()); - // . . . - - //When done, destroy the vector from the segment - segment.destroy("MyVector"); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_file_mapping.cpp b/example/doc_file_mapping.cpp index 568f577..3286cef 100644 --- a/example/doc_file_mapping.cpp +++ b/example/doc_file_mapping.cpp @@ -13,35 +13,36 @@ #include #include #include +#include +#include #include #include -#include //std::remove +#include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; - try{ - //Create a file - std::filebuf fbuf; - fbuf.open("file.bin", std::ios_base::in | std::ios_base::out - | std::ios_base::trunc | std::ios_base::binary); + const std::size_t FileSize = 10000; + if(argc == 1){ //Parent process executes this + { //Create a file + std::filebuf fbuf; + fbuf.open("file.bin", std::ios_base::in | std::ios_base::out + | std::ios_base::trunc | std::ios_base::binary); + //Set the size + fbuf.pubseekoff(FileSize-1, std::ios_base::beg); + fbuf.sputc(0); + } + //Remove file on exit + struct file_remove + { + ~file_remove (){ file_mapping::remove("file.bin"); } + } destroy_on_exit; - //Set the size - fbuf.pubseekoff(9999, std::ios_base::beg); - fbuf.sputc(0); - fbuf.close(); - - //Create a file mapping. + //Create a file mapping file_mapping m_file("file.bin", read_write); - //Map the whole file in this process - mapped_region region - (m_file //What to map - ,read_write //Map it as read-write - ); - - if(region.get_size() != 10000) - return 1; + //Map the whole file with read-write permissions in this process + mapped_region region(m_file, read_write); //Get the address of the mapped region void * addr = region.get_address(); @@ -50,12 +51,42 @@ int main () //Write all the memory to 1 std::memset(addr, 1, size); + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; } - catch(interprocess_exception &ex){ - std::remove("file.bin"); - std::cout << ex.what() << std::endl; - return 1; + else{ //Child process executes this + { //Open the file mapping and map it as read-only + file_mapping m_file ("file.bin", read_only); + mapped_region region(m_file, read_only); + + //Get the address of the mapped region + void * addr = region.get_address(); + std::size_t size = region.get_size(); + + //Check that memory was initialized to 1 + const char *mem = static_cast(addr); + for(std::size_t i = 0; i < size; ++i) + if(*mem++ != 1) + return 1; //Error checking memory + } + { //Now test it reading the file + std::filebuf fbuf; + fbuf.open("file.bin", std::ios_base::in | std::ios_base::binary); + + //Read it to memory + std::vector vect(FileSize, 0); + fbuf.sgetn(&vect[0], std::streamsize(vect.size())); + + //Check that memory was initialized to 1 + const char *mem = static_cast(&vect[0]); + for(std::size_t i = 0; i < FileSize; ++i) + if(*mem++ != 1) + return 1; //Error checking memory + } } + return 0; } //] diff --git a/example/doc_file_mapping2.cpp b/example/doc_file_mapping2.cpp deleted file mode 100644 index 058963f..0000000 --- a/example/doc_file_mapping2.cpp +++ /dev/null @@ -1,74 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -//[doc_file_mapping2 -#include -#include -#include -#include -#include -#include //std::remove -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //Open the file mapping - file_mapping m_file ("file.bin", read_only); - - //Map the whole file in this process - mapped_region region - (m_file //What to map - ,read_only //Map it as read-only - ); - - //Get the address of the mapped region - void * addr = region.get_address(); - std::size_t size = region.get_size(); - - //Check that memory was initialized to 1 - const char *mem = static_cast(addr); - for(std::size_t i = 0; i < size; ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - - //Now test it reading the file - std::filebuf fbuf; - fbuf.open("file.bin", std::ios_base::in | std::ios_base::binary); - - //Read it to memory - std::vector vect(region.get_size(), 0); - fbuf.sgetn(&vect[0], std::streamsize(vect.size())); - - //Check that memory was initialized to 1 - mem = static_cast(&vect[0]); - for(std::size_t i = 0; i < size; ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - - std::cout << "Test successful!" << std::endl; - } - catch(interprocess_exception &ex){ - std::remove("file.bin"); - std::cout << "Unexpected exception: " << ex.what() << std::endl; - return 1; - } - std::remove("file.bin"); - return 0; -} -//] -#include diff --git a/example/doc_intrusive.cpp b/example/doc_intrusive.cpp index 1f898ad..1548959 100644 --- a/example/doc_intrusive.cpp +++ b/example/doc_intrusive.cpp @@ -7,6 +7,7 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// + #include #include //[doc_intrusive @@ -68,42 +69,40 @@ class intrusive_ptr_owner : m_intrusive_ptr(ptr){} }; -int main () +int main() { - shared_memory_object::remove("my_shmem"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory shmem(create_only, "my_shmem", 10000); + //Create shared memory + managed_shared_memory shmem(create_only, "MySharedMemory", 10000); - //Create the unique reference counted object in shared memory - N::reference_counted_class *ref_counted = - shmem.construct - ("ref_counted")(shmem.get_segment_manager()); + //Create the unique reference counted object in shared memory + N::reference_counted_class *ref_counted = + shmem.construct + ("ref_counted")(shmem.get_segment_manager()); - //Create an array of ten intrusive pointer owners in shared memory - intrusive_ptr_owner *intrusive_owner_array = - shmem.construct - (anonymous_instance)[10](ref_counted); + //Create an array of ten intrusive pointer owners in shared memory + intrusive_ptr_owner *intrusive_owner_array = + shmem.construct + (anonymous_instance)[10](ref_counted); - //Now test that reference count is ten - if(ref_counted->use_count() != 10) - return 1; + //Now test that reference count is ten + if(ref_counted->use_count() != 10) + return 1; - //Now destroy the array of intrusive pointer owners - //This should destroy every intrusive_ptr and because of - //that reference_counted_class will be destroyed - shmem.destroy_ptr(intrusive_owner_array); + //Now destroy the array of intrusive pointer owners + //This should destroy every intrusive_ptr and because of + //that reference_counted_class will be destroyed + shmem.destroy_ptr(intrusive_owner_array); - //Now the reference counted object should have been destroyed - if(shmem.find("ref_counted").first) - return 1; - } - catch(...){ - shared_memory_object::remove("my_shmem"); - throw; - } - shared_memory_object::remove("my_shmem"); + //Now the reference counted object should have been destroyed + if(shmem.find("ref_counted").first) + return 1; //Success! return 0; } diff --git a/example/doc_ipc_message.cpp b/example/doc_ipc_message.cpp new file mode 100644 index 0000000..edceb85 --- /dev/null +++ b/example/doc_ipc_message.cpp @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[run_ipc_message +#include +#include //std::system +#include + +int main (int argc, char *argv[]) +{ + using namespace boost::interprocess; + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a managed shared memory segment + managed_shared_memory segment(create_only, "MySharedMemory", 65536); + + //Allocate a portion of the segment (raw memory) + std::size_t free_memory = segment.get_free_memory(); + void * shptr = segment.allocate(1024/*bytes to allocate*/); + + //Check invariant + if(free_memory <= segment.get_free_memory()) + return 1; + + //An handle from the base address can identify any byte of the shared + //memory segment even if it is mapped in different base addresses + managed_shared_memory::handle_t handle = segment.get_handle_from_address(shptr); + std::stringstream s; + s << argv[0] << " " << handle << std::ends; + + //Launch child process + if(0 != std::system(s.str().c_str())) + return 1; + //Check memory has been freed + if(free_memory != segment.get_free_memory()) + return 1; + } + else{ + //Open managed segment + managed_shared_memory segment(open_only, "MySharedMemory"); + + //An handle from the base address can identify any byte of the shared + //memory segment even if it is mapped in different base addresses + managed_shared_memory::handle_t handle = 0; + + //Obtain handle value + std::stringstream s; s << argv[1]; s >> handle; + + //Get buffer local address from handle + void *msg = segment.get_address_from_handle(handle); + + //Deallocate previously allocated memory + segment.deallocate(msg); + } + return 0; +} +//] +#include diff --git a/example/doc_ipc_messageA.cpp b/example/doc_ipc_messageA.cpp deleted file mode 100644 index 3a730f1..0000000 --- a/example/doc_ipc_messageA.cpp +++ /dev/null @@ -1,55 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -#include -//[doc_ipc_messageA -#include - -int main () -{ - using namespace boost::interprocess; - - //A special shared memory from which we are - //able to allocate raw memory buffers. - //First remove any old shared memory of the same name, create - //the shared memory segment and initialize needed resources - shared_memory_object::remove("MySharedMemory"); - try{ - managed_shared_memory segment - (create_only, - "MySharedMemory", //segment name - 65536); //segment size in bytes - - //Allocate a portion of the segment - void * shptr = segment.allocate(1024/*bytes to allocate*/); - - //An handle from the base address can identify any byte of the shared - //memory segment even if it is mapped in different base addresses - managed_shared_memory::handle_t handle = segment.get_handle_from_address(shptr); - (void)handle; - // Copy message to buffer - // . . . - // Send handle to other process - // . . . - // Wait response from other process - // . . . - - //Deallocate the portion previously allocated - segment.deallocate(shptr); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_ipc_messageB.cpp b/example/doc_ipc_messageB.cpp deleted file mode 100644 index 2c30d1a..0000000 --- a/example/doc_ipc_messageB.cpp +++ /dev/null @@ -1,47 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -#include -//[doc_ipc_messageB -#include - -int main () -{ - using namespace boost::interprocess; - - try{ - //A special shared memory from which we are - //able to allocate raw memory buffers. - //Connect to the already created shared memory segment - //and initialize needed resources - managed_shared_memory segment(open_only, "MySharedMemory"); //segment name - - //An handle from the base address can identify any byte of the shared - //memory segment even if it is mapped in different base addresses - managed_shared_memory::handle_t handle = 0; - - //Wait handle msg from the other process and put it in - //"handle" local variable - //Get buffer local address from handle - void *msg = segment.get_address_from_handle(handle); - (void)msg; - //Do anything with msg - //. . . - //Send ack to sender process - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_managed_aligned_allocation.cpp b/example/doc_managed_aligned_allocation.cpp index 2af9266..f94f569 100644 --- a/example/doc_managed_aligned_allocation.cpp +++ b/example/doc_managed_aligned_allocation.cpp @@ -16,53 +16,52 @@ int main() { using namespace boost::interprocess; + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Managed memory segment that allocates portions of a shared memory //segment with the default management algorithm - shared_memory_object::remove("MyManagedShm"); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 65536); - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 65536); + const std::size_t Alignment = 128; - const std::size_t Alignment = 128; + //Allocate 100 bytes aligned to Alignment from segment, throwing version + void *ptr = managed_shm.allocate_aligned(100, Alignment); - //Allocate 100 bytes aligned to Alignment from segment, throwing version - void *ptr = managed_shm.allocate_aligned(100, Alignment); + //Check alignment + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); - //Check alignment - assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); + //Deallocate it + managed_shm.deallocate(ptr); - //Deallocate it - managed_shm.deallocate(ptr); + //Non throwing version + ptr = managed_shm.allocate_aligned(100, Alignment, std::nothrow); - //Non throwing version - ptr = managed_shm.allocate_aligned(100, Alignment, std::nothrow); + //Check alignment + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); - //Check alignment - assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); + //Deallocate it + managed_shm.deallocate(ptr); - //Deallocate it - managed_shm.deallocate(ptr); + //If we want to efficiently allocate aligned blocks of memory + //use managed_shared_memory::PayloadPerAllocation value + assert(Alignment > managed_shared_memory::PayloadPerAllocation); - //If we want to efficiently allocate aligned blocks of memory - //use managed_shared_memory::PayloadPerAllocation value - assert(Alignment > managed_shared_memory::PayloadPerAllocation); + //This allocation will maximize the size of the aligned memory + //and will increase the possibility of finding more aligned memory + ptr = managed_shm.allocate_aligned + (3*Alignment - managed_shared_memory::PayloadPerAllocation, Alignment); - //This allocation will maximize the size of the aligned memory - //and will increase the possibility of finding more aligned memory - ptr = managed_shm.allocate_aligned - (3*Alignment - managed_shared_memory::PayloadPerAllocation, Alignment); + //Check alignment + assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); - //Check alignment - assert((static_cast(ptr)-static_cast(0)) % Alignment == 0); + //Deallocate it + managed_shm.deallocate(ptr); - //Deallocate it - managed_shm.deallocate(ptr); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); return 0; } //] diff --git a/example/doc_managed_allocation_command.cpp b/example/doc_managed_allocation_command.cpp index b77f838..8023c6d 100644 --- a/example/doc_managed_allocation_command.cpp +++ b/example/doc_managed_allocation_command.cpp @@ -16,73 +16,71 @@ int main() { using namespace boost::interprocess; + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Managed memory segment that allocates portions of a shared memory //segment with the default management algorithm - shared_memory_object::remove("MyManagedShm"); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 10000*sizeof(std::size_t)); - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 10000*sizeof(std::size_t)); + //Allocate at least 100 bytes, 1000 bytes if possible + std::size_t received_size, min_size = 100, preferred_size = 1000; + std::size_t *ptr = managed_shm.allocation_command + (boost::interprocess::allocate_new, min_size, preferred_size, received_size).first; - //Allocate at least 100 bytes, 1000 bytes if possible - std::size_t received_size, min_size = 100, preferred_size = 1000; - std::size_t *ptr = managed_shm.allocation_command - (allocate_new, min_size, preferred_size, received_size).first; + //Received size must be bigger than min_size + assert(received_size >= min_size); - //Received size must be bigger than min_size - assert(received_size >= min_size); + //Get free memory + std::size_t free_memory_after_allocation = managed_shm.get_free_memory(); - //Get free memory - std::size_t free_memory_after_allocation = managed_shm.get_free_memory(); + //Now write the data + for(std::size_t i = 0; i < received_size; ++i) ptr[i] = i; - //Now write the data - for(std::size_t i = 0; i < received_size; ++i) ptr[i] = i; + //Now try to triplicate the buffer. We won't admit an expansion + //lower to the double of the original buffer. + //This "should" be successful since no other class is allocating + //memory from the segment + std::size_t expanded_size; + std::pair ret = managed_shm.allocation_command + (boost::interprocess::expand_fwd, received_size*2, received_size*3, expanded_size, ptr); - //Now try to triplicate the buffer. We won't admit an expansion - //lower to the double of the original buffer. - //This "should" be successful since no other class is allocating - //memory from the segment - std::size_t expanded_size; - std::pair ret = managed_shm.allocation_command - (expand_fwd, received_size*2, received_size*3, expanded_size, ptr); + //Check invariants + assert(ret.second == true); + assert(ret.first == ptr); + assert(expanded_size >= received_size*2); - //Check invariants - assert(ret.second == true); - assert(ret.first == ptr); - assert(expanded_size >= received_size*2); + //Get free memory and compare + std::size_t free_memory_after_expansion = managed_shm.get_free_memory(); + assert(free_memory_after_expansion < free_memory_after_allocation); - //Get free memory and compare - std::size_t free_memory_after_expansion = managed_shm.get_free_memory(); - assert(free_memory_after_expansion < free_memory_after_allocation); + //Write new values + for(std::size_t i = received_size; i < expanded_size; ++i) ptr[i] = i; - //Write new values - for(std::size_t i = received_size; i < expanded_size; ++i) ptr[i] = i; + //Try to shrink approximately to min_size, but the new size + //should be smaller than min_size*2. + //This "should" be successful since no other class is allocating + //memory from the segment + std::size_t shrunk_size; + ret = managed_shm.allocation_command + (boost::interprocess::shrink_in_place, min_size*2, min_size, shrunk_size, ptr); - //Try to shrink approximately to min_size, but the new size - //should be smaller than min_size*2. - //This "should" be successful since no other class is allocating - //memory from the segment - std::size_t shrunk_size; - ret = managed_shm.allocation_command - (shrink_in_place, min_size*2, min_size, shrunk_size, ptr); + //Check invariants + assert(ret.second == true); + assert(ret.first == ptr); + assert(shrunk_size <= min_size*2); + assert(shrunk_size >= min_size); - //Check invariants - assert(ret.second == true); - assert(ret.first == ptr); - assert(shrunk_size <= min_size*2); - assert(shrunk_size >= min_size); + //Get free memory and compare + std::size_t free_memory_after_shrinking = managed_shm.get_free_memory(); + assert(free_memory_after_shrinking > free_memory_after_expansion); - //Get free memory and compare - std::size_t free_memory_after_shrinking = managed_shm.get_free_memory(); - assert(free_memory_after_shrinking > free_memory_after_expansion); - - //Deallocate the buffer - managed_shm.deallocate(ptr); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); + //Deallocate the buffer + managed_shm.deallocate(ptr); return 0; } //] diff --git a/example/doc_managed_construction_info.cpp b/example/doc_managed_construction_info.cpp index 8a3f711..f573181 100644 --- a/example/doc_managed_construction_info.cpp +++ b/example/doc_managed_construction_info.cpp @@ -21,41 +21,39 @@ class my_class int main() { using namespace boost::interprocess; - typedef managed_shared_memory msm; - shared_memory_object::remove("MyManagedShm"); - try{ - msm managed_shm(create_only, "MyManagedShm", 10000*sizeof(std::size_t)); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Construct objects - my_class *named_object = managed_shm.construct("Object name")[1](); - my_class *unique_object = managed_shm.construct(unique_instance)[2](); - my_class *anon_object = managed_shm.construct(anonymous_instance)[3](); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 10000*sizeof(std::size_t)); - //Now test "get_instance_name" function. - assert(0 == std::strcmp(msm::get_instance_name(named_object), "Object name")); - assert(0 == msm::get_instance_name(unique_object)); - assert(0 == msm::get_instance_name(anon_object)); + //Construct objects + my_class *named_object = managed_shm.construct("Object name")[1](); + my_class *unique_object = managed_shm.construct(unique_instance)[2](); + my_class *anon_object = managed_shm.construct(anonymous_instance)[3](); - //Now test "get_instance_type" function. - assert(named_type == msm::get_instance_type(named_object)); - assert(unique_type == msm::get_instance_type(unique_object)); - assert(anonymous_type == msm::get_instance_type(anon_object)); + //Now test "get_instance_name" function. + assert(0 == std::strcmp(managed_shared_memory::get_instance_name(named_object), "Object name")); + assert(0 == managed_shared_memory::get_instance_name(unique_object)); + assert(0 == managed_shared_memory::get_instance_name(anon_object)); - //Now test "get_instance_length" function. - assert(1 == msm::get_instance_length(named_object)); - assert(2 == msm::get_instance_length(unique_object)); - assert(3 == msm::get_instance_length(anon_object)); + //Now test "get_instance_type" function. + assert(named_type == managed_shared_memory::get_instance_type(named_object)); + assert(unique_type == managed_shared_memory::get_instance_type(unique_object)); + assert(anonymous_type == managed_shared_memory::get_instance_type(anon_object)); - managed_shm.destroy_ptr(named_object); - managed_shm.destroy_ptr(unique_object); - managed_shm.destroy_ptr(anon_object); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); + //Now test "get_instance_length" function. + assert(1 == managed_shared_memory::get_instance_length(named_object)); + assert(2 == managed_shared_memory::get_instance_length(unique_object)); + assert(3 == managed_shared_memory::get_instance_length(anon_object)); + + managed_shm.destroy_ptr(named_object); + managed_shm.destroy_ptr(unique_object); + managed_shm.destroy_ptr(anon_object); return 0; } //] diff --git a/example/doc_managed_copy_on_write.cpp b/example/doc_managed_copy_on_write.cpp index 304be95..7daa76e 100644 --- a/example/doc_managed_copy_on_write.cpp +++ b/example/doc_managed_copy_on_write.cpp @@ -11,7 +11,6 @@ //[doc_managed_copy_on_write #include #include //std::fstream -#include //std::remove #include //std::distance int main() @@ -19,8 +18,8 @@ int main() using namespace boost::interprocess; //Try to erase any previous managed segment with the same name - std::remove("MyManagedFile"); - std::remove("MyManagedFile2"); + file_mapping::remove("MyManagedFile"); + file_mapping::remove("MyManagedFile2"); remove_file_on_destroy destroyer1("MyManagedFile"); remove_file_on_destroy destroyer2("MyManagedFile2"); diff --git a/example/doc_managed_external_buffer.cpp b/example/doc_managed_external_buffer.cpp index 051b430..f9e9855 100644 --- a/example/doc_managed_external_buffer.cpp +++ b/example/doc_managed_external_buffer.cpp @@ -43,7 +43,9 @@ int main() //be stored in the static_buffer! MyBufferList *list = objects_in_static_memory.construct(L"MyList") (objects_in_static_memory.get_segment_manager()); - + //<- + (void)list; + //-> //Since the allocation algorithm from wmanaged_external_buffer uses relative //pointers and all the pointers constructed int the static memory point //to objects in the same segment, we can create another static buffer diff --git a/example/doc_managed_grow.cpp b/example/doc_managed_grow.cpp index ee7a31e..1523222 100644 --- a/example/doc_managed_grow.cpp +++ b/example/doc_managed_grow.cpp @@ -21,48 +21,49 @@ class MyClass int main() { using namespace boost::interprocess; - try{ - { //Remove old shared memory if present - shared_memory_object::remove("MyManagedShm"); - //Create a managed shared memory - managed_shared_memory shm(create_only, "MyManagedShm", 1000); - //Check size - assert(shm.get_size() == 1000); - //Construct a named object - MyClass *myclass = shm.construct("MyClass")(); - //The managed segment is unmapped here - } - { - //Now that the segment is not mapped grow it adding extra 500 bytes - managed_shared_memory::grow("MyManagedShm", 500); - //Map it again - managed_shared_memory shm(open_only, "MyManagedShm"); - //Check size - assert(shm.get_size() == 1500); - //Check "MyClass" is still there - MyClass *myclass = shm.find("MyClass").first; - assert(myclass != 0); - //The managed segment is unmapped here - } - { - //Now minimize the size of the segment - managed_shared_memory::shrink_to_fit("MyManagedShm"); - //Map it again - managed_shared_memory shm(open_only, "MyManagedShm"); - //Check size - assert(shm.get_size() < 1000); - //Check "MyClass" is still there - MyClass *myclass = shm.find("MyClass").first; - assert(myclass != 0); - //The managed segment is unmapped here - } + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + { + //Create a managed shared memory + managed_shared_memory shm(create_only, "MySharedMemory", 1000); + //Check size + assert(shm.get_size() == 1000); + //Construct a named object + MyClass *myclass = shm.construct("MyClass")(); + //The managed segment is unmapped here + //<- + (void)myclass; + //-> } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; + { + //Now that the segment is not mapped grow it adding extra 500 bytes + managed_shared_memory::grow("MySharedMemory", 500); + //Map it again + managed_shared_memory shm(open_only, "MySharedMemory"); + //Check size + assert(shm.get_size() == 1500); + //Check "MyClass" is still there + MyClass *myclass = shm.find("MyClass").first; + assert(myclass != 0); + //The managed segment is unmapped here + } + { + //Now minimize the size of the segment + managed_shared_memory::shrink_to_fit("MySharedMemory"); + //Map it again + managed_shared_memory shm(open_only, "MySharedMemory"); + //Check size + assert(shm.get_size() < 1000); + //Check "MyClass" is still there + MyClass *myclass = shm.find("MyClass").first; + assert(myclass != 0); + //The managed segment is unmapped here } - //Remove the managed segment - shared_memory_object::remove("MyManagedShm"); return 0; } //] diff --git a/example/doc_managed_mapped_file.cpp b/example/doc_managed_mapped_file.cpp index 2dacbd0..091a7eb 100644 --- a/example/doc_managed_mapped_file.cpp +++ b/example/doc_managed_mapped_file.cpp @@ -24,59 +24,67 @@ int main () { const char *FileName = "file_mapping"; const std::size_t FileSize = 1000; - std::remove(FileName); + file_mapping::remove(FileName); try{ - managed_mapped_file mfile_memory(create_only, FileName, FileSize); - MyList * mylist = mfile_memory.construct("MyList") - (mfile_memory.get_segment_manager()); + std::size_t old_size = 0; + managed_mapped_file::handle_t list_handle; + { + managed_mapped_file mfile_memory(create_only, FileName, FileSize); + MyList *mylist = mfile_memory.construct("MyList") + (mfile_memory.get_segment_manager()); - //Obtain handle, that identifies the list in the buffer - managed_mapped_file::handle_t list_handle = mfile_memory.get_handle_from_address(mylist); + //Obtain handle, that identifies the list in the buffer + list_handle = mfile_memory.get_handle_from_address(mylist); - //Fill list until there is no more room in the file - try{ - while(1) { - mylist->insert(mylist->begin(), 0); + //Fill list until there is no more room in the file + try{ + while(1) { + mylist->insert(mylist->begin(), 0); + } } + catch(const bad_alloc &){ + //mapped file is full + } + //Let's obtain the size of the list + old_size = mylist->size(); } - catch(const bad_alloc &){ - //mapped file is full - } - //Let's obtain the size of the list - std::size_t old_size = mylist->size(); - //To make the list bigger, let's increase the mapped file //in FileSize bytes more. - //mfile_memory.grow(FileSize); + managed_mapped_file::grow(FileName, FileSize*2); - //If mapping address has changed, the old pointer is invalid, - //so use previously obtained handle to find the new pointer. - mylist = static_cast - (mfile_memory.get_address_from_handle(list_handle)); - - //Fill list until there is no more room in the file - try{ - while(1) { - mylist->insert(mylist->begin(), 0); + { + managed_mapped_file mfile_memory(open_only, FileName); + + + //If mapping address has changed, the old pointer is invalid, + //so use previously obtained handle to find the new pointer. + MyList *mylist = static_cast + (mfile_memory.get_address_from_handle(list_handle)); + + //Fill list until there is no more room in the file + try{ + while(1) { + mylist->insert(mylist->begin(), 0); + } } + catch(const bad_alloc &){ + //mapped file is full + } + + //Let's obtain the new size of the list + std::size_t new_size = mylist->size(); + + assert(new_size > old_size); + + //Destroy list + mfile_memory.destroy_ptr(mylist); } - catch(const bad_alloc &){ - //mapped file is full - } - - //Let's obtain the new size of the list - std::size_t new_size = mylist->size(); - - assert(new_size > old_size); - - //Destroy list - mfile_memory.destroy_ptr(mylist); } catch(...){ - std::remove(FileName); + file_mapping::remove(FileName); throw; } - std::remove(FileName); + file_mapping::remove(FileName); return 0; } diff --git a/example/doc_managed_multiple_allocation.cpp b/example/doc_managed_multiple_allocation.cpp index 3d508cf..e1ac02f 100644 --- a/example/doc_managed_multiple_allocation.cpp +++ b/example/doc_managed_multiple_allocation.cpp @@ -10,69 +10,59 @@ #include //[doc_managed_multiple_allocation #include +#include //boost::interprocess::move #include //assert #include //std::memset #include //std::nothrow #include //std::vector + int main() { using namespace boost::interprocess; - typedef managed_shared_memory::multiallocation_iterator multiallocation_iterator; + typedef managed_shared_memory::multiallocation_chain multiallocation_chain; - //Try to erase any previous managed segment with the same name - shared_memory_object::remove("MyManagedShm"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 65536); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 65536); - //Allocate 16 elements of 100 bytes in a single call. Non-throwing version. - multiallocation_iterator beg_it = managed_shm.allocate_many(100, 16, std::nothrow); + //Allocate 16 elements of 100 bytes in a single call. Non-throwing version. + multiallocation_chain chain(managed_shm.allocate_many(100, 16, std::nothrow)); - //To check for an error, we can use a boolean expression - //or compare it with a default constructed iterator - assert(!beg_it == (beg_it == multiallocation_iterator())); - - //Check if the memory allocation was successful - if(!beg_it) return 1; + //Check if the memory allocation was successful + if(chain.empty()) return 1; - //Allocated buffers - std::vector allocated_buffers; + //Allocated buffers + std::vector allocated_buffers; - //Initialize our data - for( multiallocation_iterator it = beg_it, end_it; it != end_it; ){ - allocated_buffers.push_back(&*it); - //The iterator must be incremented before overwriting memory - //because otherwise, the iterator is invalidated. - std::memset(&*it++, 0, 100); - } - - //Now deallocate - while(!allocated_buffers.empty()){ - managed_shm.deallocate(allocated_buffers.back()); - allocated_buffers.pop_back(); - } - - //Allocate 10 buffers of different sizes in a single call. Throwing version - std::size_t sizes[10]; - for(std::size_t i = 0; i < 10; ++i) - sizes[i] = i*3; - - beg_it = managed_shm.allocate_many(sizes, 10); - - //Iterate each allocated buffer and deallocate - //The "end" condition can be also checked with operator! - for(multiallocation_iterator it = beg_it; it;){ - //The iterator must be incremented before overwriting memory - //because otherwise, the iterator is invalidated. - managed_shm.deallocate(&*it++); - } + //Initialize our data + while(!chain.empty()){ + void *buf = chain.front(); + chain.pop_front(); + allocated_buffers.push_back(buf); + //The iterator must be incremented before overwriting memory + //because otherwise, the iterator is invalidated. + std::memset(buf, 0, 100); } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; + + //Now deallocate + while(!allocated_buffers.empty()){ + managed_shm.deallocate(allocated_buffers.back()); + allocated_buffers.pop_back(); } - shared_memory_object::remove("MyManagedShm"); + + //Allocate 10 buffers of different sizes in a single call. Throwing version + std::size_t sizes[10]; + for(std::size_t i = 0; i < 10; ++i) + sizes[i] = i*3; + + chain = managed_shm.allocate_many(sizes, 10); + managed_shm.deallocate_many(boost::interprocess::move(chain)); return 0; } //] diff --git a/example/doc_managed_raw_allocation.cpp b/example/doc_managed_raw_allocation.cpp index 0c31b12..ac7cf24 100644 --- a/example/doc_managed_raw_allocation.cpp +++ b/example/doc_managed_raw_allocation.cpp @@ -15,29 +15,28 @@ int main() { using namespace boost::interprocess; + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Managed memory segment that allocates portions of a shared memory //segment with the default management algorithm - shared_memory_object::remove("MyManagedShm"); - try{ - managed_shared_memory managed_shm(create_only, "MyManagedShm", 65536); + managed_shared_memory managed_shm(create_only, "MySharedMemory", 65536); - //Allocate 100 bytes of memory from segment, throwing version - void *ptr = managed_shm.allocate(100); + //Allocate 100 bytes of memory from segment, throwing version + void *ptr = managed_shm.allocate(100); - //Deallocate it - managed_shm.deallocate(ptr); + //Deallocate it + managed_shm.deallocate(ptr); - //Non throwing version - ptr = managed_shm.allocate(100, std::nothrow); + //Non throwing version + ptr = managed_shm.allocate(100, std::nothrow); - //Deallocate it - managed_shm.deallocate(ptr); - } - catch(...){ - shared_memory_object::remove("MyManagedShm"); - throw; - } - shared_memory_object::remove("MyManagedShm"); + //Deallocate it + managed_shm.deallocate(ptr); return 0; } //] diff --git a/example/doc_map.cpp b/example/doc_map.cpp index 5a7da62..a1b2b14 100644 --- a/example/doc_map.cpp +++ b/example/doc_map.cpp @@ -19,56 +19,55 @@ int main () { using namespace boost::interprocess; + + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + //Shared memory front-end that is able to construct objects //associated with a c-string. Erase previous shared memory with the name //to be used and create the memory segment at the specified address and initialize resources - shared_memory_object::remove("MySharedMemory"); + managed_shared_memory segment + (create_only + ,"MySharedMemory" //segment name + ,65536); //segment size in bytes - try{ - managed_shared_memory segment - (create_only - ,"MySharedMemory" //segment name - ,65536); //segment size in bytes + //Note that map's value_type is std::pair, + //so the allocator must allocate that pair. + typedef int KeyType; + typedef float MappedType; + typedef std::pair ValueType; - //Note that map's value_type is std::pair, - //so the allocator must allocate that pair. - typedef int KeyType; - typedef float MappedType; - typedef std::pair ValueType; + //Alias an STL compatible allocator of for the map. + //This allocator will allow to place containers + //in managed shared memory segments + typedef allocator + ShmemAllocator; - //Alias an STL compatible allocator of for the map. - //This allocator will allow to place containers - //in managed shared memory segments - typedef allocator - ShmemAllocator; + //Alias a map of ints that uses the previous STL-like allocator. + //Note that the third parameter argument is the ordering function + //of the map, just like with std::map, used to compare the keys. + typedef map, ShmemAllocator> MyMap; - //Alias a map of ints that uses the previous STL-like allocator. - //Note that the third parameter argument is the ordering function - //of the map, just like with std::map, used to compare the keys. - typedef map, ShmemAllocator> MyMap; + //Initialize the shared memory STL-compatible allocator + ShmemAllocator alloc_inst (segment.get_segment_manager()); - //Initialize the shared memory STL-compatible allocator - ShmemAllocator alloc_inst (segment.get_segment_manager()); + //Construct a shared memory map. + //Note that the first parameter is the comparison function, + //and the second one the allocator. + //This the same signature as std::map's constructor taking an allocator + MyMap *mymap = + segment.construct("MyMap") //object name + (std::less() //first ctor parameter + ,alloc_inst); //second ctor parameter - //Construct a shared memory map. - //Note that the first parameter is the comparison function, - //and the second one the allocator. - //This the same signature as std::map's constructor taking an allocator - MyMap *mymap = - segment.construct("MyMap") //object name - (std::less() //first ctor parameter - ,alloc_inst); //second ctor parameter - - //Insert data in the map - for(int i = 0; i < 100; ++i){ - mymap->insert(std::pair(i, (float)i)); - } + //Insert data in the map + for(int i = 0; i < 100; ++i){ + mymap->insert(std::pair(i, (float)i)); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_move_containers.cpp b/example/doc_move_containers.cpp index aeadf61..c831bda 100644 --- a/example/doc_move_containers.cpp +++ b/example/doc_move_containers.cpp @@ -28,58 +28,57 @@ int main () typedef allocator StringAllocator; typedef vector MyShmStringVector; - //Remove old shared memory and create new one - shared_memory_object::remove("myshm"); - try{ - managed_shared_memory shm(create_only, "myshm", 10000); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create allocators - CharAllocator charallocator (shm.get_segment_manager()); - StringAllocator stringallocator(shm.get_segment_manager()); + managed_shared_memory shm(create_only, "MySharedMemory", 10000); - //Create a vector of strings in shared memory. - MyShmStringVector *myshmvector = - shm.construct("myshmvector")(stringallocator); + //Create allocators + CharAllocator charallocator (shm.get_segment_manager()); + StringAllocator stringallocator(shm.get_segment_manager()); - //Insert 50 strings in shared memory. The strings will be allocated - //only once and no string copy-constructor will be called when inserting - //strings, leading to a great performance. - MyShmString string_to_compare(charallocator); - string_to_compare = "this is a long, long, long, long, long, long, string..."; - - myshmvector->reserve(50); - for(int i = 0; i < 50; ++i){ - MyShmString move_me(string_to_compare); - //In the following line, no string copy-constructor will be called. - //"move_me"'s contents will be transferred to the string created in - //the vector - myshmvector->push_back(boost::interprocess::move(move_me)); + //Create a vector of strings in shared memory. + MyShmStringVector *myshmvector = + shm.construct("myshmvector")(stringallocator); - //The source string is in default constructed state - assert(move_me.empty()); + //Insert 50 strings in shared memory. The strings will be allocated + //only once and no string copy-constructor will be called when inserting + //strings, leading to a great performance. + MyShmString string_to_compare(charallocator); + string_to_compare = "this is a long, long, long, long, long, long, string..."; + + myshmvector->reserve(50); + for(int i = 0; i < 50; ++i){ + MyShmString move_me(string_to_compare); + //In the following line, no string copy-constructor will be called. + //"move_me"'s contents will be transferred to the string created in + //the vector + myshmvector->push_back(boost::interprocess::move(move_me)); - //The newly created string will be equal to the "move_me"'s old contents - assert(myshmvector->back() == string_to_compare); - } + //The source string is in default constructed state + assert(move_me.empty()); - //Now erase a string... - myshmvector->pop_back(); - - //...And insert one in the first position. - //No string copy-constructor or assignments will be called, but - //move constructors and move-assignments. No memory allocation - //function will be called in this operations!! - myshmvector->insert(myshmvector->begin(), boost::interprocess::move(string_to_compare)); - - //Destroy vector. This will free all strings that the vector contains - shm.destroy_ptr(myshmvector); + //The newly created string will be equal to the "move_me"'s old contents + assert(myshmvector->back() == string_to_compare); } - catch(...){ - shared_memory_object::remove("myshmvector"); - throw; - } - shared_memory_object::remove("myshmvector"); + + //Now erase a string... + myshmvector->pop_back(); + + //...And insert one in the first position. + //No string copy-constructor or assignments will be called, but + //move constructors and move-assignments. No memory allocation + //function will be called in this operations!! + myshmvector->insert(myshmvector->begin(), boost::interprocess::move(string_to_compare)); + + //Destroy vector. This will free all strings that the vector contains + shm.destroy_ptr(myshmvector); return 0; } //] #include + diff --git a/example/doc_multi_index.cpp b/example/doc_multi_index.cpp index 24cbd63..dff5bd4 100644 --- a/example/doc_multi_index.cpp +++ b/example/doc_multi_index.cpp @@ -61,30 +61,27 @@ typedef bmi::multi_index_container< int main () { - //Erase previous shared memory with the name - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only,"MySharedMemory", 65536); + //Create shared memory + managed_shared_memory segment(create_only,"MySharedMemory", 65536); - //Construct the multi_index in shared memory - employee_set *es = segment.construct - ("My MultiIndex Container") //Container's name in shared memory - ( employee_set::ctor_args_list() - , segment.get_allocator()); //Ctor parameters + //Construct the multi_index in shared memory + employee_set *es = segment.construct + ("My MultiIndex Container") //Container's name in shared memory + ( employee_set::ctor_args_list() + , segment.get_allocator()); //Ctor parameters - //Now insert elements - char_allocator ca(segment.get_allocator()); - es->insert(employee(0,31, "Joe", ca)); - es->insert(employee(1,27, "Robert", ca)); - es->insert(employee(2,40, "John", ca)); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Now insert elements + char_allocator ca(segment.get_allocator()); + es->insert(employee(0,31, "Joe", ca)); + es->insert(employee(1,27, "Robert", ca)); + es->insert(employee(2,40, "John", ca)); return 0; } //] diff --git a/example/doc_named_allocA.cpp b/example/doc_named_alloc.cpp similarity index 50% rename from example/doc_named_allocA.cpp rename to example/doc_named_alloc.cpp index 84eb889..30767a8 100644 --- a/example/doc_named_allocA.cpp +++ b/example/doc_named_alloc.cpp @@ -9,24 +9,28 @@ ////////////////////////////////////////////////////////////////////////////// #include #include -//[doc_named_allocA +//[doc_named_alloc #include +#include //std::system +#include +#include #include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; typedef std::pair MyType; - try{ - //A special shared memory where we can - //construct objects associated with a name. - //First remove any old shared memory of the same name, create - //the shared memory segment and initialize needed resources - shared_memory_object::remove("MySharedMemory"); - managed_shared_memory segment - //create segment name segment size - (create_only, "MySharedMemory", 65536); + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Construct managed shared memory + managed_shared_memory segment(create_only, "MySharedMemory", 65536); //Create an object of MyType initialized to {0.0, 0} MyType *instance = segment.construct @@ -49,12 +53,50 @@ int main () [3] //number of elements ( &float_initializer[0] //Iterator for the 1st ctor argument , &int_initializer[0]); //Iterator for the 2nd ctor argument + + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; + + //<- + (void)instance; + (void)array; + (void)array_it; + //-> + + //Check child has destroyed all objects + if(segment.find("MyType array").first || + segment.find("MyType instance").first || + segment.find("MyType array from it").first) + return 1; } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + else{ + //Open managed shared memory + managed_shared_memory segment(open_only, "MySharedMemory"); + + std::pair res; + + //Find the array + res = segment.find ("MyType array"); + //Length should be 10 + if(res.second != 10) return 1; + + //Find the object + res = segment.find ("MyType instance"); + //Length should be 1 + if(res.second != 1) return 1; + + //Find the array constructed from iterators + res = segment.find ("MyType array from it"); + //Length should be 3 + if(res.second != 3) return 1; + + //We're done, delete all the objects + segment.destroy("MyType array"); + segment.destroy("MyType instance"); + segment.destroy("MyType array from it"); } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_named_allocB.cpp b/example/doc_named_allocB.cpp deleted file mode 100644 index 8b6bb65..0000000 --- a/example/doc_named_allocB.cpp +++ /dev/null @@ -1,63 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -#include -//[doc_named_allocB -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - typedef std::pair MyType; - - try{ - //A special shared memory where we can - //construct objects associated with a name. - //Connect to the already created shared memory segment - //and initialize needed resources - managed_shared_memory segment(open_only, "MySharedMemory"); - - std::pair res; - - //Find the array - res = segment.find ("MyType array"); - //Length should be 10 - assert(res.second == 10); - - //Find the object - res = segment.find ("MyType instance"); - //Length should be 1 - assert(res.second == 1); - - //Find the array constructed from iterators - res = segment.find ("MyType array from it"); - //Length should be 3 - assert(res.second == 3); - - //Use data - // . . . - - //We're done, delete all the objects - segment.destroy("MyType array"); - segment.destroy("MyType instance"); - segment.destroy("MyType array from it"); - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); - return 0; -} -//] -#include diff --git a/example/doc_named_mutex.cpp b/example/doc_named_mutex.cpp index 80e7f98..3ff1fa6 100644 --- a/example/doc_named_mutex.cpp +++ b/example/doc_named_mutex.cpp @@ -13,6 +13,7 @@ #include #include #include +#include int main () { @@ -37,10 +38,12 @@ int main () } catch(interprocess_exception &ex){ named_mutex::remove("fstream_named_mutex"); + std::remove("file_name"); std::cout << ex.what() << std::endl; return 1; } named_mutex::remove("fstream_named_mutex"); + std::remove("file_name"); return 0; } //] diff --git a/example/doc_node_allocator.cpp b/example/doc_node_allocator.cpp index 00ba3da..68087a0 100644 --- a/example/doc_node_allocator.cpp +++ b/example/doc_node_allocator.cpp @@ -18,46 +18,44 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a node_allocator that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef node_allocator - node_allocator_t; - node_allocator_t allocator_instance(segment.get_segment_manager()); + //Create a node_allocator that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef node_allocator + node_allocator_t; + node_allocator_t allocator_instance(segment.get_segment_manager()); - //Create another node_allocator. Since the segment manager address - //is the same, this node_allocator will be - //attached to the same pool so "allocator_instance2" can deallocate - //nodes allocated by "allocator_instance" - node_allocator_t allocator_instance2(segment.get_segment_manager()); + //Create another node_allocator. Since the segment manager address + //is the same, this node_allocator will be + //attached to the same pool so "allocator_instance2" can deallocate + //nodes allocated by "allocator_instance" + node_allocator_t allocator_instance2(segment.get_segment_manager()); - //Create another node_allocator using copy-constructor. This - //node_allocator will also be attached to the same pool - node_allocator_t allocator_instance3(allocator_instance2); + //Create another node_allocator using copy-constructor. This + //node_allocator will also be attached to the same pool + node_allocator_t allocator_instance3(allocator_instance2); - //All allocators are equal - assert(allocator_instance == allocator_instance2); - assert(allocator_instance2 == allocator_instance3); + //All allocators are equal + assert(allocator_instance == allocator_instance2); + assert(allocator_instance2 == allocator_instance3); - //So memory allocated with one can be deallocated with another - allocator_instance2.deallocate(allocator_instance.allocate(1), 1); - allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); + //So memory allocated with one can be deallocated with another + allocator_instance2.deallocate(allocator_instance.allocate(1), 1); + allocator_instance3.deallocate(allocator_instance2.allocate(1), 1); - //The common pool will be destroyed here, since no allocator is - //attached to the pool - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //The common pool will be destroyed here, since no allocator is + //attached to the pool return 0; } //] diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index efa7930..8931177 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -24,45 +24,41 @@ struct list_node int main () { - //Destroy any previous shared memory with the name to be used. - //Create a special shared memory from which we can - //allocate buffers of raw memory. - shared_memory_object::remove("MySharedMemory"); - try{ - managed_shared_memory segment( - create_only, - "MySharedMemory", //segment name - 65536); //segment size in bytes + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create linked list with 10 nodes in shared memory - offset_ptr prev = 0, current, first; + managed_shared_memory segment( + create_only, + "MySharedMemory", //segment name + 65536); //segment size in bytes - int i; - for(i = 0; i < 10; ++i, prev = current){ - current = static_cast(segment.allocate(sizeof(list_node))); - current->value = i; - current->next = 0; + //Create linked list with 10 nodes in shared memory + offset_ptr prev = 0, current, first; - if(!prev) - first = current; - else - prev->next = current; - } + int i; + for(i = 0; i < 10; ++i, prev = current){ + current = static_cast(segment.allocate(sizeof(list_node))); + current->value = i; + current->next = 0; - //Communicate list to other processes - //. . . - //When done, destroy list - for(current = first; current; /**/){ - prev = current; - current = current->next; - segment.deallocate(prev.get()); - } + if(!prev) + first = current; + else + prev->next = current; } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + + //Communicate list to other processes + //. . . + //When done, destroy list + for(current = first; current; /**/){ + prev = current; + current = current->next; + segment.deallocate(prev.get()); } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_private_adaptive_pool.cpp b/example/doc_private_adaptive_pool.cpp index 8a5ac1e..38303ea 100644 --- a/example/doc_private_adaptive_pool.cpp +++ b/example/doc_private_adaptive_pool.cpp @@ -18,42 +18,40 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a private_adaptive_pool that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef private_adaptive_pool - private_adaptive_pool_t; - private_adaptive_pool_t allocator_instance(segment.get_segment_manager()); + //Create a private_adaptive_pool that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef private_adaptive_pool + private_adaptive_pool_t; + private_adaptive_pool_t allocator_instance(segment.get_segment_manager()); - //Create another private_adaptive_pool. - private_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); + //Create another private_adaptive_pool. + private_adaptive_pool_t allocator_instance2(segment.get_segment_manager()); - //Although the segment manager address - //is the same, this private_adaptive_pool will have its own pool so - //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". - //"allocator_instance2" is NOT equal to "allocator_instance" - assert(allocator_instance != allocator_instance2); + //Although the segment manager address + //is the same, this private_adaptive_pool will have its own pool so + //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". + //"allocator_instance2" is NOT equal to "allocator_instance" + assert(allocator_instance != allocator_instance2); - //Create another adaptive_pool using copy-constructor. - private_adaptive_pool_t allocator_instance3(allocator_instance2); + //Create another adaptive_pool using copy-constructor. + private_adaptive_pool_t allocator_instance3(allocator_instance2); - //This allocator is also unequal to allocator_instance2 - assert(allocator_instance2 != allocator_instance3); + //This allocator is also unequal to allocator_instance2 + assert(allocator_instance2 != allocator_instance3); - //Pools are destroyed with the allocators - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Pools are destroyed with the allocators return 0; } //] diff --git a/example/doc_private_node_allocator.cpp b/example/doc_private_node_allocator.cpp index e35f804..bbb7648 100644 --- a/example/doc_private_node_allocator.cpp +++ b/example/doc_private_node_allocator.cpp @@ -18,42 +18,40 @@ using namespace boost::interprocess; int main () { - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only, - "MySharedMemory", //segment name - 65536); + //Create shared memory + managed_shared_memory segment(create_only, + "MySharedMemory", //segment name + 65536); - //Create a private_node_allocator that allocates ints from the managed segment - //The number of chunks per segment is the default value - typedef private_node_allocator - private_node_allocator_t; - private_node_allocator_t allocator_instance(segment.get_segment_manager()); + //Create a private_node_allocator that allocates ints from the managed segment + //The number of chunks per segment is the default value + typedef private_node_allocator + private_node_allocator_t; + private_node_allocator_t allocator_instance(segment.get_segment_manager()); - //Create another private_node_allocator. - private_node_allocator_t allocator_instance2(segment.get_segment_manager()); + //Create another private_node_allocator. + private_node_allocator_t allocator_instance2(segment.get_segment_manager()); - //Although the segment manager address - //is the same, this private_node_allocator will have its own pool so - //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". - //"allocator_instance2" is NOT equal to "allocator_instance" - assert(allocator_instance != allocator_instance2); + //Although the segment manager address + //is the same, this private_node_allocator will have its own pool so + //"allocator_instance2" CAN'T deallocate nodes allocated by "allocator_instance". + //"allocator_instance2" is NOT equal to "allocator_instance" + assert(allocator_instance != allocator_instance2); - //Create another node_allocator using copy-constructor. - private_node_allocator_t allocator_instance3(allocator_instance2); + //Create another node_allocator using copy-constructor. + private_node_allocator_t allocator_instance3(allocator_instance2); - //This allocator is also unequal to allocator_instance2 - assert(allocator_instance2 != allocator_instance3); + //This allocator is also unequal to allocator_instance2 + assert(allocator_instance2 != allocator_instance3); - //Pools are destroyed with the allocators - } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); + //Pools are destroyed with the allocators return 0; } //] diff --git a/example/doc_scoped_ptr.cpp b/example/doc_scoped_ptr.cpp index 3eb423f..d4a577e 100644 --- a/example/doc_scoped_ptr.cpp +++ b/example/doc_scoped_ptr.cpp @@ -47,60 +47,59 @@ class my_deleter int main () { //Create shared memory - shared_memory_object::remove("my_shmem"); - try{ - managed_shared_memory shmem(create_only, "my_shmem", 10000); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //In the first try, there will be no exceptions - //in the second try we will throw an exception - for(int i = 0; i < 2; ++i){ - //Create an object in shared memory - my_class * my_object = shmem.construct("my_object")(); - my_class * my_object2 = shmem.construct(anonymous_instance)(); - shmem.destroy_ptr(my_object2); - - //Since the next shared memory allocation can throw - //assign it to a scoped_ptr so that if an exception occurs - //we destroy the object automatically - my_deleter d(shmem.get_segment_manager()); + managed_shared_memory shmem(create_only, "MySharedMemory", 10000); - try{ - scoped_ptr > s_ptr(my_object, d); - //Let's emulate a exception capable operation - //In the second try, throw an exception - if(i == 1){ - throw(my_exception()); - } - //If we have passed the dangerous zone - //we can release the scoped pointer - //to avoid destruction - s_ptr.release(); + //In the first try, there will be no exceptions + //in the second try we will throw an exception + for(int i = 0; i < 2; ++i){ + //Create an object in shared memory + my_class * my_object = shmem.construct("my_object")(); + my_class * my_object2 = shmem.construct(anonymous_instance)(); + shmem.destroy_ptr(my_object2); + + //Since the next shared memory allocation can throw + //assign it to a scoped_ptr so that if an exception occurs + //we destroy the object automatically + my_deleter d(shmem.get_segment_manager()); + + try{ + scoped_ptr > s_ptr(my_object, d); + //Let's emulate a exception capable operation + //In the second try, throw an exception + if(i == 1){ + throw(my_exception()); } - catch(const my_exception &){} - //Here, scoped_ptr is destroyed - //so it we haven't thrown an exception - //the object should be there, otherwise, destroyed - if(i == 0){ - //Make sure the object is alive - if(!shmem.find("my_object").first){ - return 1; - } - //Now we can use it and delete it manually - shmem.destroy("my_object"); + //If we have passed the dangerous zone + //we can release the scoped pointer + //to avoid destruction + s_ptr.release(); + } + catch(const my_exception &){} + //Here, scoped_ptr is destroyed + //so it we haven't thrown an exception + //the object should be there, otherwise, destroyed + if(i == 0){ + //Make sure the object is alive + if(!shmem.find("my_object").first){ + return 1; } - else{ - //Make sure the object has been deleted - if(shmem.find("my_object").first){ - return 1; - } + //Now we can use it and delete it manually + shmem.destroy("my_object"); + } + else{ + //Make sure the object has been deleted + if(shmem.find("my_object").first){ + return 1; } } } - catch(...){ - shared_memory_object::remove("my_shmem"); - throw; - } - shared_memory_object::remove("my_shmem"); return 0; } //] diff --git a/example/doc_shared_memory.cpp b/example/doc_shared_memory.cpp index 3b5b7bc..053c031 100644 --- a/example/doc_shared_memory.cpp +++ b/example/doc_shared_memory.cpp @@ -11,18 +11,24 @@ //[doc_shared_memory #include #include -#include #include +#include +#include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; - try{ - //Erase previous shared memory - shared_memory_object::remove("shared_memory"); + + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; //Create a shared memory object. - shared_memory_object shm (create_only, "shared_memory", read_write); + shared_memory_object shm (create_only, "MySharedMemory", read_write); //Set size shm.truncate(1000); @@ -32,11 +38,24 @@ int main () //Write all the memory to 1 std::memset(region.get_address(), 1, region.get_size()); + + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; } - catch(interprocess_exception &ex){ - shared_memory_object::remove("shared_memory"); - std::cout << ex.what() << std::endl; - return 1; + else{ + //Open already created shared memory object. + shared_memory_object shm (open_only, "MySharedMemory", read_only); + + //Map the whole shared memory in this process + mapped_region region(shm, read_only); + + //Check that memory was initialized to 1 + char *mem = static_cast(region.get_address()); + for(std::size_t i = 0; i < region.get_size(); ++i) + if(*mem++ != 1) + return 1; //Error checking memory } return 0; } diff --git a/example/doc_shared_memory2.cpp b/example/doc_shared_memory2.cpp deleted file mode 100644 index c977095..0000000 --- a/example/doc_shared_memory2.cpp +++ /dev/null @@ -1,48 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -//[doc_shared_memory2 -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - shared_memory_object::remove("shared_memory"); - try{ - //Open already created shared memory object. - shared_memory_object shm (open_only, "shared_memory", read_only); - - //Map the whole shared memory in this process - mapped_region region(shm, read_only); - - //Check that memory was initialized to 1 - const char *mem = static_cast(region.get_address()); - for(std::size_t i = 0; i < region.get_size(); ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - std::cout << "Test successful!" << std::endl; - } - catch(interprocess_exception &ex){ - std::cout << "Unexpected exception: " << ex.what() << std::endl; - shared_memory_object::remove("shared_memory"); - return 1; - } - shared_memory_object::remove("shared_memory"); - return 0; -} -//] - -#include diff --git a/example/doc_shared_ptr.cpp b/example/doc_shared_ptr.cpp index ebdf6d5..3f41829 100644 --- a/example/doc_shared_ptr.cpp +++ b/example/doc_shared_ptr.cpp @@ -16,7 +16,6 @@ #include #include #include -#include //std::remove using namespace boost::interprocess; @@ -47,7 +46,7 @@ struct shared_ptr_owner int main () { //Destroy any previous file with the name to be used. - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); { managed_mapped_file file(create_only, "MyMappedFile", 4096); @@ -114,7 +113,7 @@ int main () //The reference count will be deallocated when all weak pointers //disappear. After that, the file is unmapped. } - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); return 0; } //] diff --git a/example/doc_shared_ptr_explicit.cpp b/example/doc_shared_ptr_explicit.cpp index 4a4121e..d1d97c7 100644 --- a/example/doc_shared_ptr_explicit.cpp +++ b/example/doc_shared_ptr_explicit.cpp @@ -31,8 +31,13 @@ typedef shared_ptr my_shared_ptr; int main () { - //Destroy any previous segment with the name to be used. - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + managed_shared_memory segment(create_only, "MySharedMemory", 4096); //Create a shared pointer in shared memory @@ -49,7 +54,6 @@ int main () //Destroy "shared ptr". "object to share" will be automatically destroyed segment.destroy_ptr(&shared_ptr_instance); - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_spawn_vector.cpp b/example/doc_spawn_vector.cpp new file mode 100644 index 0000000..6ec0789 --- /dev/null +++ b/example/doc_spawn_vector.cpp @@ -0,0 +1,79 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +//[run_doc_spawn_vector +#include +#include +#include +#include +#include //std::system + +using namespace boost::interprocess; + +//Define an STL compatible allocator of ints that allocates from the managed_shared_memory. +//This allocator will allow placing containers in the segment +typedef allocator ShmemAllocator; + +//Alias a vector that uses the previous STL-like allocator so that allocates +//its values from the segment +typedef vector MyVector; + +//Main function. For parent process argc == 1, for child process argc == 2 +int main(int argc, char *argv[]) +{ + if(argc == 1){ //Parent process + //Remove shared memory on construction and destruction + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + //Create a new segment with given name and size + managed_shared_memory segment(create_only ,"MySharedMemory", 65536); + + //Initialize shared memory STL-compatible allocator + const ShmemAllocator alloc_inst (segment.get_segment_manager()); + + //Construct a vector named "MyVector" in shared memory with argument alloc_inst + MyVector *myvector = segment.construct("MyVector")(alloc_inst); + + for(int i = 0; i < 100; ++i) //Insert data in the vector + myvector->push_back(i); + + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; + + //Check child has destroyed the vector + if(segment.find("MyVector").first) + return 1; + } + else{ //Child process + //Open the managed segment + managed_shared_memory segment(open_only, "MySharedMemory"); + + //Find the vector using the c-string name + MyVector *myvector = segment.find("MyVector").first; + + //Use vector in reverse order + std::sort(myvector->rbegin(), myvector->rend()); + + //When done, destroy the vector from the segment + segment.destroy("MyVector"); + } + + return 0; +}; + +//] +#include diff --git a/example/doc_unique_ptr.cpp b/example/doc_unique_ptr.cpp index 0b6d5b5..9506297 100644 --- a/example/doc_unique_ptr.cpp +++ b/example/doc_unique_ptr.cpp @@ -18,7 +18,6 @@ #include #include #include -#include //std::remove using namespace boost::interprocess; @@ -49,7 +48,7 @@ typedef list int main () { //Destroy any previous file with the name to be used. - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); { managed_mapped_file file(create_only, "MyMappedFile", 65536); @@ -72,9 +71,8 @@ int main () //Now insert all values for(int i = 0; i < 100; ++i){ - unique_vector->push_back( - make_managed_unique_ptr(file.construct(anonymous_instance)(i), file) - ); + unique_ptr_type p(make_managed_unique_ptr(file.construct(anonymous_instance)(i), file)); + unique_vector->push_back(boost::interprocess::move(p)); assert(unique_vector->back()->number_ == i); } @@ -84,7 +82,7 @@ int main () //Pass ownership of all values to the list for(int i = 99; !unique_vector->empty(); --i){ - unique_list->push_front(move(unique_vector->back())); + unique_list->push_front(boost::interprocess::move(unique_vector->back())); //The unique ptr of the vector is now empty... assert(unique_vector->back() == 0); unique_vector->pop_back(); @@ -114,7 +112,7 @@ int main () //Now destroy the list. All elements will be automatically deallocated. file.destroy_ptr(unique_list); } - std::remove("MyMappedFile"); + file_mapping::remove("MyMappedFile"); return 0; } //] diff --git a/example/doc_unordered_map.cpp b/example/doc_unordered_map.cpp index 3839c6f..03e289f 100644 --- a/example/doc_unordered_map.cpp +++ b/example/doc_unordered_map.cpp @@ -20,46 +20,43 @@ int main () { using namespace boost::interprocess; - //Erase previous shared memory with the name - shared_memory_object::remove("MySharedMemory"); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - try{ - //Create shared memory - managed_shared_memory segment(create_only ,"MySharedMemory" ,65536); + //Create shared memory + managed_shared_memory segment(create_only ,"MySharedMemory" ,65536); - //Note that unordered_map's value_type is std::pair, - //so the allocator must allocate that pair. - typedef int KeyType; - typedef float MappedType; - typedef std::pair ValueType; + //Note that unordered_map's value_type is std::pair, + //so the allocator must allocate that pair. + typedef int KeyType; + typedef float MappedType; + typedef std::pair ValueType; - //Typedef the allocator - typedef allocator ShmemAllocator; + //Typedef the allocator + typedef allocator ShmemAllocator; - //Alias an unordered_map of ints that uses the previous STL-like allocator. - typedef boost::unordered_map - < KeyType , MappedType - , boost::hash ,std::equal_to - , ShmemAllocator> - MyHashMap; + //Alias an unordered_map of ints that uses the previous STL-like allocator. + typedef boost::unordered_map + < KeyType , MappedType + , boost::hash ,std::equal_to + , ShmemAllocator> + MyHashMap; - //Construct a shared memory hash map. - //Note that the first parameter is the initial bucket count and - //after that, the hash function, the equality function and the allocator - MyHashMap *myhashmap = segment.construct("MyHashMap") //object name - ( 3, boost::hash(), std::equal_to() // - , segment.get_allocator()); //allocator instance + //Construct a shared memory hash map. + //Note that the first parameter is the initial bucket count and + //after that, the hash function, the equality function and the allocator + MyHashMap *myhashmap = segment.construct("MyHashMap") //object name + ( 3, boost::hash(), std::equal_to() // + , segment.get_allocator()); //allocator instance - //Insert data in the hash map - for(int i = 0; i < 100; ++i){ - myhashmap->insert(ValueType(i, (float)i)); - } + //Insert data in the hash map + for(int i = 0; i < 100; ++i){ + myhashmap->insert(ValueType(i, (float)i)); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; - } - shared_memory_object::remove("MySharedMemory"); return 0; } //] diff --git a/example/doc_vectorstream.cpp b/example/doc_vectorstream.cpp index 5c4ed1f..f0021f6 100644 --- a/example/doc_vectorstream.cpp +++ b/example/doc_vectorstream.cpp @@ -30,83 +30,81 @@ typedef basic_vectorstream MyVectorStream; int main () { - //Create shared memory - shared_memory_object::remove("MySharedMemory"); - try{ - managed_shared_memory segment( - create_only, - "MySharedMemory", //segment name - 65536); //segment size in bytes + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Construct shared memory vector - MyVector *myvector = - segment.construct("MyVector") - (IntAllocator(segment.get_segment_manager())); + managed_shared_memory segment( + create_only, + "MySharedMemory", //segment name + 65536); //segment size in bytes - //Fill vector - myvector->reserve(100); - for(int i = 0; i < 100; ++i){ - myvector->push_back(i); - } + //Construct shared memory vector + MyVector *myvector = + segment.construct("MyVector") + (IntAllocator(segment.get_segment_manager())); - //Create the vectorstream. To create the internal shared memory - //basic_string we need to pass the shared memory allocator as - //a constructor argument - MyVectorStream myvectorstream(CharAllocator(segment.get_segment_manager())); - - //Reserve the internal string - myvectorstream.reserve(100*5); - - //Write all vector elements as text in the internal string - //Data will be directly written in shared memory, because - //internal string's allocator is a shared memory allocator - for(std::size_t i = 0, max = myvector->size(); i < max; ++i){ - myvectorstream << (*myvector)[i] << std::endl; - } - - //Auxiliary vector to compare original data - MyVector *myvector2 = - segment.construct("MyVector2") - (IntAllocator(segment.get_segment_manager())); - - //Avoid reallocations - myvector2->reserve(100); - - //Extract all values from the internal - //string directly to a shared memory vector. - std::istream_iterator it(myvectorstream), itend; - std::copy(it, itend, std::back_inserter(*myvector2)); - - //Compare vectors - assert(std::equal(myvector->begin(), myvector->end(), myvector2->begin())); - - //Create a copy of the internal string - MyString stringcopy (myvectorstream.vector()); - - //Now we create a new empty shared memory string... - MyString *mystring = - segment.construct("MyString") - (CharAllocator(segment.get_segment_manager())); - - //...and we swap vectorstream's internal string - //with the new one: after this statement mystring - //will be the owner of the formatted data. - //No reallocations, no data copies - myvectorstream.swap_vector(*mystring); - - //Let's compare both strings - assert(stringcopy == *mystring); - - //Done, destroy and delete vectors and string from the segment - segment.destroy_ptr(myvector2); - segment.destroy_ptr(myvector); - segment.destroy_ptr(mystring); + //Fill vector + myvector->reserve(100); + for(int i = 0; i < 100; ++i){ + myvector->push_back(i); } - catch(...){ - shared_memory_object::remove("MySharedMemory"); - throw; + + //Create the vectorstream. To create the internal shared memory + //basic_string we need to pass the shared memory allocator as + //a constructor argument + MyVectorStream myvectorstream(CharAllocator(segment.get_segment_manager())); + + //Reserve the internal string + myvectorstream.reserve(100*5); + + //Write all vector elements as text in the internal string + //Data will be directly written in shared memory, because + //internal string's allocator is a shared memory allocator + for(std::size_t i = 0, max = myvector->size(); i < max; ++i){ + myvectorstream << (*myvector)[i] << std::endl; } - shared_memory_object::remove("MySharedMemory"); + + //Auxiliary vector to compare original data + MyVector *myvector2 = + segment.construct("MyVector2") + (IntAllocator(segment.get_segment_manager())); + + //Avoid reallocations + myvector2->reserve(100); + + //Extract all values from the internal + //string directly to a shared memory vector. + std::istream_iterator it(myvectorstream), itend; + std::copy(it, itend, std::back_inserter(*myvector2)); + + //Compare vectors + assert(std::equal(myvector->begin(), myvector->end(), myvector2->begin())); + + //Create a copy of the internal string + MyString stringcopy (myvectorstream.vector()); + + //Now we create a new empty shared memory string... + MyString *mystring = + segment.construct("MyString") + (CharAllocator(segment.get_segment_manager())); + + //...and we swap vectorstream's internal string + //with the new one: after this statement mystring + //will be the owner of the formatted data. + //No reallocations, no data copies + myvectorstream.swap_vector(*mystring); + + //Let's compare both strings + assert(stringcopy == *mystring); + + //Done, destroy and delete vectors and string from the segment + segment.destroy_ptr(myvector2); + segment.destroy_ptr(myvector); + segment.destroy_ptr(mystring); return 0; } //] diff --git a/example/doc_where_allocate.cpp b/example/doc_where_allocate.cpp index 7f14148..570de8e 100644 --- a/example/doc_where_allocate.cpp +++ b/example/doc_where_allocate.cpp @@ -29,45 +29,44 @@ int main () MyShmStringVector; //Open shared memory - shared_memory_object::remove("myshm"); - try{ - managed_shared_memory shm(create_only, "myshm", 10000); + //Remove shared memory on construction and destruction + struct shm_destroy + { + shm_destroy() { shared_memory_object::remove("MySharedMemory"); } + ~shm_destroy(){ shared_memory_object::remove("MySharedMemory"); } + } remover; - //Create allocators - CharAllocator charallocator (shm.get_segment_manager()); - StringAllocator stringallocator(shm.get_segment_manager()); + managed_shared_memory shm(create_only, "MySharedMemory", 10000); - //This string is in only in this process (the pointer pointing to the - //buffer that will hold the text is not in shared memory). - //But the buffer that will hold "this is my text" is allocated from - //shared memory - MyShmString mystring(charallocator); - mystring = "this is my text"; + //Create allocators + CharAllocator charallocator (shm.get_segment_manager()); + StringAllocator stringallocator(shm.get_segment_manager()); - //This vector is only in this process (the pointer pointing to the - //buffer that will hold the MyShmString-s is not in shared memory). - //But the buffer that will hold 10 MyShmString-s is allocated from - //shared memory using StringAllocator. Since strings use a shared - //memory allocator (CharAllocator) the 10 buffers that hold - //"this is my text" text are also in shared memory. - MyShmStringVector myvector(stringallocator); - myvector.insert(myvector.begin(), 10, mystring); + //This string is in only in this process (the pointer pointing to the + //buffer that will hold the text is not in shared memory). + //But the buffer that will hold "this is my text" is allocated from + //shared memory + MyShmString mystring(charallocator); + mystring = "this is my text"; - //This vector is fully constructed in shared memory. All pointers - //buffers are constructed in the same shared memory segment - //This vector can be safely accessed from other processes. - MyShmStringVector *myshmvector = - shm.construct("myshmvector")(stringallocator); - myshmvector->insert(myshmvector->begin(), 10, mystring); + //This vector is only in this process (the pointer pointing to the + //buffer that will hold the MyShmString-s is not in shared memory). + //But the buffer that will hold 10 MyShmString-s is allocated from + //shared memory using StringAllocator. Since strings use a shared + //memory allocator (CharAllocator) the 10 buffers that hold + //"this is my text" text are also in shared memory. + MyShmStringVector myvector(stringallocator); + myvector.insert(myvector.begin(), 10, mystring); - //Destroy vector. This will free all strings that the vector contains - shm.destroy_ptr(myshmvector); - } - catch(...){ - shared_memory_object::remove("myshm"); - throw; - } - shared_memory_object::remove("myshm"); + //This vector is fully constructed in shared memory. All pointers + //buffers are constructed in the same shared memory segment + //This vector can be safely accessed from other processes. + MyShmStringVector *myshmvector = + shm.construct("myshmvector")(stringallocator); + myshmvector->insert(myshmvector->begin(), 10, mystring); + + //Destroy vector. This will free all strings that the vector contains + shm.destroy_ptr(myshmvector); return 0; } //] diff --git a/example/doc_windows_shared_memory.cpp b/example/doc_windows_shared_memory.cpp index 94cd380..28da11e 100644 --- a/example/doc_windows_shared_memory.cpp +++ b/example/doc_windows_shared_memory.cpp @@ -8,41 +8,61 @@ // ////////////////////////////////////////////////////////////////////////////// #include -#include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS + //[doc_windows_shared_memory #include #include -#include #include +#include +#include -int main () +int main(int argc, char *argv[]) { using namespace boost::interprocess; - try{ + + if(argc == 1){ //Parent process //Create a native windows shared memory object. - windows_shared_memory shm (create_only, "shared_memory", read_write, 1000); + windows_shared_memory shm (create_only, "MySharedMemory", read_write, 1000); //Map the whole shared memory in this process mapped_region region(shm, read_write); //Write all the memory to 1 - std::memset(region.get_address(), 1, 1000); + std::memset(region.get_address(), 1, region.get_size()); - //Launch the client process and wait until finishes... - //... + //Launch child process + std::string s(argv[0]); s += " child"; + if(0 != std::system(s.c_str())) + return 1; + //windows_shared_memory is destroyed when the last attached process dies... } - catch(interprocess_exception &ex){ - std::cout << ex.what() << std::endl; - return 1; + else{ + //Open already created shared memory object. + windows_shared_memory shm (open_only, "MySharedMemory", read_only); + + //Map the whole shared memory in this process + mapped_region region(shm, read_only); + + //Check that memory was initialized to 1 + char *mem = static_cast(region.get_address()); + for(std::size_t i = 0; i < region.get_size(); ++i) + if(*mem++ != 1) + return 1; //Error checking memory + return 0; } return 0; } //] -#else //#ifdef BOOST_WINDOWS + +#else //BOOST_INTERPROCESS_WINDOWS + int main() -{ return 0; } -#endif//#ifdef BOOST_WINDOWS +{ + return 0; +} + +#endif //BOOST_INTERPROCESS_WINDOWS #include diff --git a/example/doc_windows_shared_memory2.cpp b/example/doc_windows_shared_memory2.cpp deleted file mode 100644 index 405f244..0000000 --- a/example/doc_windows_shared_memory2.cpp +++ /dev/null @@ -1,55 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2006-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. -// -////////////////////////////////////////////////////////////////////////////// -#include -#include - -#ifdef BOOST_WINDOWS -//[doc_windows_shared_memory2 -#include -#include -#include -#include - -int main () -{ - using namespace boost::interprocess; - try{ - //Open already created shared memory object. - windows_shared_memory shm(open_only, "shared_memory", read_only); - - //Map the whole shared memory in this process - mapped_region region (shm, read_only); - - //Check that memory was initialized to 1 - const char *mem = static_cast(region.get_address()); - for(std::size_t i = 0; i < 1000; ++i){ - if(*mem++ != 1){ - std::cout << "Error checking memory!" << std::endl; - return 1; - } - } - - std::cout << "Test successful!" << std::endl; - } - catch(interprocess_exception &ex){ - std::cout << "Unexpected exception: " << ex.what() << std::endl; - return 1; - } - - return 0; -} -//] -#else //#ifdef BOOST_WINDOWS -int main() -{ return 0; } -#endif//#ifdef BOOST_WINDOWS - -#include - diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index fab13ca..cf12947 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -80,9 +82,9 @@ class adaptive_pool_base public: //------- - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -92,13 +94,9 @@ class adaptive_pool_base typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef boost::interprocess::version_type version; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains adaptive_pool_base from //!adaptive_pool_base @@ -266,7 +264,7 @@ class adaptive_pool typedef detail::adaptive_pool_base < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -388,7 +386,7 @@ class adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -399,12 +397,12 @@ class adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -412,7 +410,7 @@ class adaptive_pool //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -425,7 +423,7 @@ class adaptive_pool //!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_iterator allocate_individual(std::size_t num_elements); + 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 @@ -438,7 +436,7 @@ class adaptive_pool //!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_iterator it); + void deallocate_individual(multiallocation_chain it); #endif }; diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index 60c7fb6..2918689 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -18,15 +18,17 @@ #include #include +#include + #include -#include +#include +#include #include -#include +#include #include #include #include #include -#include #include #include @@ -64,11 +66,11 @@ class allocator //Typedef to const void pointer typedef typename - detail::pointer_to_other + boost::pointer_to_other ::type cvoid_ptr; //Pointer to the allocator - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type alloc_ptr_t; //Not assignable from related allocator @@ -84,9 +86,9 @@ class allocator public: typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef typename detail::add_reference ::type reference; @@ -95,20 +97,13 @@ class allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; + typedef boost::interprocess::version_type version; /// @cond //Experimental. Don't use. - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef detail::multiallocation_chain_adaptor - multiallocation_chain; - + typedef boost::interprocess::detail::transform_multiallocation_chain + multiallocation_chain; /// @endcond //!Obtains an allocator that allocates @@ -174,7 +169,7 @@ class allocator } std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) @@ -189,19 +184,19 @@ class allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements) + multiallocation_chain allocate_many + (size_type elem_size, std::size_t num_elements) { - return multiallocation_iterator - (mp_mngr->allocate_many(sizeof(T)*elem_size, 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + multiallocation_chain allocate_many + (const size_type *elem_sizes, size_type n_elements) { - return multiallocation_iterator - (mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); + multiallocation_chain(mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T))); } //!Allocates many elements of size elem_size in a contiguous block @@ -210,8 +205,10 @@ class allocator //!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_iterator it) - { return mp_mngr->deallocate_many(it.base()); } + 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(). @@ -225,7 +222,8 @@ class allocator //!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_iterator allocate_individual(std::size_t num_elements) + multiallocation_chain allocate_individual + (std::size_t num_elements) { return this->allocate_many(1, num_elements); } //!Deallocates memory previously allocated with allocate_one(). @@ -240,8 +238,8 @@ class allocator //!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_iterator it) - { return this->deallocate_many(it); } + void deallocate_individual(multiallocation_chain chain) + { return this->deallocate_many(boost::interprocess::move(chain)); } //!Returns address of mutable object. //!Never throws diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index fc94fb7..f2fa301 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -143,7 +143,7 @@ class cached_adaptive_pool , 2> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -267,7 +267,7 @@ class cached_adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -278,12 +278,12 @@ class cached_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -291,7 +291,7 @@ class cached_adaptive_pool //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -304,7 +304,7 @@ class cached_adaptive_pool //!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_iterator allocate_individual(std::size_t num_elements); + 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 @@ -317,7 +317,7 @@ class cached_adaptive_pool //!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_iterator it); + 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); diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index 3801dc6..5799d6b 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -115,7 +115,7 @@ class cached_node_allocator , 2> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -238,7 +238,7 @@ class cached_node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -249,12 +249,12 @@ class cached_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -262,7 +262,7 @@ class cached_node_allocator //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -275,7 +275,7 @@ class cached_node_allocator //!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_iterator allocate_individual(std::size_t num_elements); + 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 @@ -288,7 +288,7 @@ class cached_node_allocator //!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_iterator it); + 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); diff --git a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp index 30a6c07..6a20fb8 100644 --- a/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/adaptive_node_pool.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +55,6 @@ class private_adaptive_node_pool_impl public: typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: @@ -200,8 +201,9 @@ class private_adaptive_node_pool_impl //!Deallocates an array pointed by ptr. Never throws void deallocate_node(void *pElem) { - this->priv_reinsert_nodes_in_block - (multiallocation_iterator::create_simple_range(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); @@ -209,13 +211,14 @@ class private_adaptive_node_pool_impl priv_invariants(); } - //!Allocates a singly linked list of n nodes ending in null pointer. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) + //!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(); - std::size_t i = 0; while(i != n){ //If there are no free nodes we allocate all needed blocks if (m_block_multiset.empty()){ @@ -230,9 +233,9 @@ class private_adaptive_node_pool_impl for(std::size_t j = 0; j != num_elems; ++j){ void *new_node = &free_nodes.front(); free_nodes.pop_front(); - nodes.push_back(new_node); + chain.push_back(new_node); } - + if(free_nodes.empty()){ m_block_multiset.erase(m_block_multiset.begin()); } @@ -240,41 +243,23 @@ class private_adaptive_node_pool_impl } } catch(...){ - this->deallocate_nodes(nodes, nodes.size()); + this->deallocate_nodes(chain, i); throw; } priv_invariants(); - } - - //!Allocates n nodes, pointed by the multiallocation_iterator. - //!Can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) - { - multiallocation_chain chain; - this->allocate_nodes(chain, n); - return chain.get_it(); + return boost::interprocess::move(chain); } //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes) + void deallocate_nodes(multiallocation_chain nodes) { - this->deallocate_nodes(nodes.get_it()); - nodes.reset(); + 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) { - assert(nodes.size() >= n); - for(std::size_t i = 0; i < n; ++i){ - this->deallocate_node(nodes.pop_front()); - } - } - - //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) - { - this->priv_reinsert_nodes_in_block(it); + 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); } @@ -331,13 +316,12 @@ class private_adaptive_node_pool_impl } } - void priv_reinsert_nodes_in_block(multiallocation_iterator it) + void priv_reinsert_nodes_in_block(multiallocation_chain &chain, std::size_t n) { - multiallocation_iterator itend; block_iterator block_it(m_block_multiset.end()); - while(it != itend){ - void *pElem = &*it; - ++it; + 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); @@ -484,6 +468,7 @@ class private_adaptive_node_pool_impl 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; } @@ -565,7 +550,7 @@ class private_adaptive_node_pool_impl } private: - typedef typename pointer_to_other + typedef typename boost::pointer_to_other ::type segment_mngr_base_ptr_t; const std::size_t m_max_free_blocks; diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index f5ccddd..998c415 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -8,25 +8,63 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP -#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP +#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP +#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP #include #include -#include + +#include + #include -#include //pointer_to_other, get_pointer +#include //get_pointer #include //std::pair #include //boost::addressof #include //BOOST_ASSERT #include //bad_alloc #include //scoped_lock -#include //allocation_type +#include //boost::interprocess::allocation_type +#include +#include #include //std::swap +#include +#include +#include namespace boost { namespace interprocess { + +template +struct sizeof_value +{ + static const std::size_t value = sizeof(T); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + +template <> +struct sizeof_value +{ + static const std::size_t value = sizeof(void*); +}; + namespace detail { //!Object function that creates the node allocator if it is not created and @@ -41,7 +79,7 @@ struct get_or_create_node_pool_func { //Find or create the node_pool_t mp_node_pool = mp_segment_manager->template find_or_construct - (unique_instance)(mp_segment_manager); + (boost::interprocess::unique_instance)(mp_segment_manager); //If valid, increment link count if(mp_node_pool != 0) mp_node_pool->inc_ref_count(); @@ -78,7 +116,7 @@ struct destroy_if_last_link_func 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(unique_instance); + mp_node_pool->get_segment_manager()->template destroy(boost::interprocess::unique_instance); } //!Constructor. Initializes function @@ -106,16 +144,15 @@ template class cache_impl { typedef typename NodePool::segment_manager:: - void_pointer void_pointer; + void_pointer void_pointer; typedef typename pointer_to_other - ::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; + ::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::multiallocation_iterator multiallocation_iterator; typedef typename NodePool::segment_manager segment_manager; cache_impl(segment_manager *segment_mngr, std::size_t max_cached_nodes) @@ -149,31 +186,34 @@ class cache_impl { //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()){ - mp_node_pool->allocate_nodes(m_cached_nodes, m_max_cached_nodes/2); + m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2); } - return m_cached_nodes.pop_front(); + void *ret = detail::get_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); + return ret; } - multiallocation_iterator cached_allocation(std::size_t n) + multiallocation_chain cached_allocation(std::size_t n) { multiallocation_chain chain; - std::size_t count = n; + 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 = m_cached_nodes.pop_front(); + void *ret = detail::get_pointer(m_cached_nodes.front()); + m_cached_nodes.pop_front(); chain.push_back(ret); + ++allocated; } - if(chain.size() != n){ - mp_node_pool->allocate_nodes(chain, n - chain.size()); + 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); } - assert(chain.size() == n); - chain.splice_back(m_cached_nodes); - return multiallocation_iterator(chain.get_it()); + return boost::interprocess::move(chain); } BOOST_CATCH(...){ - this->cached_deallocation(multiallocation_iterator(chain.get_it())); + this->cached_deallocation(boost::interprocess::move(chain)); BOOST_RETHROW } BOOST_CATCH_END @@ -192,15 +232,9 @@ class cache_impl m_cached_nodes.push_front(ptr); } - void cached_deallocation(multiallocation_iterator it) + void cached_deallocation(multiallocation_chain chain) { - multiallocation_iterator itend; - - while(it != itend){ - void *addr = &*it; - ++it; - m_cached_nodes.push_front(addr); - } + 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){ @@ -225,7 +259,7 @@ class cache_impl void deallocate_all_cached_nodes() { if(m_cached_nodes.empty()) return; - mp_node_pool->deallocate_nodes(m_cached_nodes); + mp_node_pool->deallocate_nodes(boost::interprocess::move(m_cached_nodes)); } private: @@ -257,9 +291,9 @@ class array_allocation_impl typedef typename SegmentManager::void_pointer void_pointer; public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -268,12 +302,9 @@ class array_allocation_impl ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; + public: //!Returns maximum the number of objects the previously allocated memory @@ -285,7 +316,7 @@ class array_allocation_impl } std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) @@ -300,19 +331,17 @@ class array_allocation_impl //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements) + multiallocation_chain allocate_many(size_type elem_size, std::size_t num_elements) { - return multiallocation_iterator - (this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements) + multiallocation_chain allocate_many(const size_type *elem_sizes, size_type n_elements) { - return multiallocation_iterator - (this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T))); + 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 @@ -321,8 +350,8 @@ class array_allocation_impl //!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_iterator it) - { return this->derived()->get_segment_manager()->deallocate_many(it.base()); } + void deallocate_many(multiallocation_chain chain) + { return this->derived()->get_segment_manager()->deallocate_many(boost::interprocess::move(chain)); } //!Returns the number of elements that could be //!allocated. Never throws @@ -369,13 +398,13 @@ class node_pool_allocation_impl { return static_cast(this); } typedef typename SegmentManager::void_pointer void_pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type cvoid_pointer; public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -384,12 +413,9 @@ class node_pool_allocation_impl ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; + template struct node_pool @@ -445,11 +471,11 @@ class node_pool_allocation_impl //!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_iterator allocate_individual(std::size_t num_elements) + 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_iterator(pool->allocate_nodes(num_elements)); + return multiallocation_chain(pool->allocate_nodes(num_elements)); } //!Deallocates memory previously allocated with allocate_one(). @@ -468,8 +494,11 @@ class node_pool_allocation_impl //!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_iterator it) - { node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes(it.base()); } + 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() @@ -497,11 +526,10 @@ class cached_allocator_impl typedef NodePool node_pool_t; typedef typename NodePool::segment_manager segment_manager; typedef typename segment_manager::void_pointer void_pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type cvoid_pointer; typedef typename base_t::pointer pointer; typedef typename base_t::size_type size_type; - typedef typename base_t::multiallocation_iterator multiallocation_iterator; typedef typename base_t::multiallocation_chain multiallocation_chain; typedef typename base_t::value_type value_type; @@ -587,8 +615,8 @@ class cached_allocator_impl //!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_iterator allocate_individual(std::size_t num_elements) - { return multiallocation_iterator(this->m_cache.cached_allocation(num_elements)); } + 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 @@ -602,8 +630,12 @@ class cached_allocator_impl //!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_iterator it) - { m_cache.cached_deallocation(it.base()); } + void deallocate_individual(multiallocation_chain chain) + { + typename node_pool_t::multiallocation_chain mem + (chain.extract_multiallocation_chain()); + m_cache.cached_deallocation(boost::interprocess::move(mem)); + } //!Deallocates all free blocks of the pool void deallocate_free_blocks() @@ -655,11 +687,10 @@ class shared_pool_impl { public: //!Segment manager typedef - typedef typename private_node_allocator_t::segment_manager segment_manager; typedef typename private_node_allocator_t:: - multiallocation_iterator multiallocation_iterator; + segment_manager segment_manager; typedef typename private_node_allocator_t:: - multiallocation_chain multiallocation_chain; + multiallocation_chain multiallocation_chain; private: typedef typename segment_manager::mutex_family::mutex_type mutex_type; @@ -691,7 +722,7 @@ class shared_pool_impl //----------------------- 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) @@ -701,10 +732,10 @@ class shared_pool_impl //----------------------- return private_node_allocator_t::allocate_nodes(nodes, n); } - - //!Allocates n nodes, pointed by the multiallocation_iterator. +*/ + //!Allocates n nodes. //!Can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) + multiallocation_chain allocate_nodes(const std::size_t n) { //----------------------- boost::interprocess::scoped_lock guard(m_header); @@ -721,22 +752,13 @@ class shared_pool_impl private_node_allocator_t::deallocate_nodes(nodes, num); } - //!Deallocates a linked list of nodes ending in null pointer. Never throws - void deallocate_nodes(multiallocation_chain &nodes) - { - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - private_node_allocator_t::deallocate_nodes(nodes); - } - //!Deallocates the nodes pointed by the multiallocation iterator. Never throws - void deallocate_nodes(multiallocation_iterator it) + void deallocate_nodes(multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - private_node_allocator_t::deallocate_nodes(it); + private_node_allocator_t::deallocate_nodes(boost::interprocess::move(chain)); } //!Deallocates all the free blocks of memory. Never throws @@ -814,4 +836,4 @@ class shared_pool_impl #include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOCATOR_COMMON_HPP +#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP diff --git a/include/boost/interprocess/allocators/detail/node_pool.hpp b/include/boost/interprocess/allocators/detail/node_pool.hpp index bf6c758..7d7631b 100644 --- a/include/boost/interprocess/allocators/detail/node_pool.hpp +++ b/include/boost/interprocess/allocators/detail/node_pool.hpp @@ -18,14 +18,17 @@ #include #include +#include +#include +#include + #include #include #include -#include -#include #include #include #include +#include #include #include #include @@ -53,7 +56,6 @@ class private_node_pool_impl typedef typename node_slist::slist_hook_t slist_hook_t; typedef typename node_slist::node_t node_t; typedef typename node_slist::node_slist_t free_nodes_t; - typedef typename SegmentManagerBase::multiallocation_iterator multiallocation_iterator; typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; private: @@ -112,25 +114,9 @@ class private_node_pool_impl --m_allocated; } - //!Allocates a singly linked list of n nodes ending in null pointer and pushes them in the chain. - //!can throw boost::interprocess::bad_alloc - void allocate_nodes(multiallocation_chain &nodes, const std::size_t n) - { - std::size_t i = 0; - try{ - for(; i < n; ++i){ - nodes.push_front(this->allocate_node()); - } - } - catch(...){ - this->deallocate_nodes(nodes, i); - throw; - } - } - //!Allocates a singly linked list of n nodes ending in null pointer //!can throw boost::interprocess::bad_alloc - multiallocation_iterator allocate_nodes(const std::size_t n) + multiallocation_chain allocate_nodes(const std::size_t n) { multiallocation_chain nodes; std::size_t i = 0; @@ -143,32 +129,26 @@ class private_node_pool_impl this->deallocate_nodes(nodes, i); throw; } - return nodes.get_it(); - } - - //!Deallocates a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes) - { - this->deallocate_nodes(nodes.get_it()); - nodes.reset(); + return boost::interprocess::move(nodes); } //!Deallocates the first n nodes of a linked list of nodes. Never throws - void deallocate_nodes(multiallocation_chain &nodes, std::size_t num) + void deallocate_nodes(multiallocation_chain &nodes, std::size_t n) { - assert(nodes.size() >= num); - for(std::size_t i = 0; i < num; ++i){ - deallocate_node(nodes.pop_front()); + 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_iterator it) + void deallocate_nodes(multiallocation_chain chain) { - multiallocation_iterator itend; - while(it != itend){ - void *addr = &*it; - ++it; + while(!chain.empty()){ + void *addr = detail::get_pointer(chain.front()); + chain.pop_front(); deallocate_node(addr); } } @@ -347,7 +327,7 @@ class private_node_pool_impl } private: - typedef typename pointer_to_other + typedef typename boost::pointer_to_other ::type segment_mngr_base_ptr_t; const std::size_t m_nodes_per_block; diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index 0ee43c3..49bb201 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -77,9 +79,9 @@ class node_allocator_base public: //------- - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -89,13 +91,9 @@ class node_allocator_base typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef boost::interprocess::version_type version; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator_base from //!node_allocator_base @@ -251,7 +249,7 @@ class node_allocator typedef detail::node_allocator_base < 2, T, SegmentManager, NodesPerBlock> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -373,7 +371,7 @@ class node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -384,12 +382,12 @@ class node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -397,7 +395,7 @@ class node_allocator //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -410,7 +408,7 @@ class node_allocator //!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_iterator allocate_individual(std::size_t num_elements); + 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 @@ -423,7 +421,7 @@ class node_allocator //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index c9b4e18..d958fdb 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -78,9 +80,9 @@ class private_adaptive_pool_base /// @endcond public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -89,14 +91,10 @@ class private_adaptive_pool_base ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type + typedef boost::interprocess::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator from other node_allocator template @@ -264,7 +262,7 @@ class private_adaptive_pool typedef detail::private_adaptive_pool_base < 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -388,7 +386,7 @@ class private_adaptive_pool size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -399,12 +397,12 @@ class private_adaptive_pool //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -412,7 +410,7 @@ class private_adaptive_pool //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -425,7 +423,7 @@ class private_adaptive_pool //!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_iterator allocate_individual(std::size_t num_elements); + 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 @@ -438,7 +436,7 @@ class private_adaptive_pool //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index a7320f1..e8c3c5e 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -72,9 +74,9 @@ class private_node_allocator_base /// @endcond public: - typedef typename detail:: + typedef typename boost:: pointer_to_other::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef T value_type; typedef typename detail::add_reference @@ -83,14 +85,10 @@ class private_node_allocator_base ::type const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type + typedef boost::interprocess::version_type version; - typedef transform_iterator - < typename SegmentManager:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - typedef typename SegmentManager:: - multiallocation_chain multiallocation_chain; + typedef detail::transform_multiallocation_chain + multiallocation_chain; //!Obtains node_allocator from other node_allocator template @@ -240,7 +238,7 @@ class private_node_allocator typedef detail::private_node_allocator_base < 2, T, SegmentManager, NodesPerBlock> base_t; public: - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -364,7 +362,7 @@ class private_node_allocator size_type size(const pointer &p) const; std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0); @@ -375,12 +373,12 @@ class private_node_allocator //!preferred_elements. The number of actually allocated elements is //!will be assigned to received_size. The elements must be deallocated //!with deallocate(...) - multiallocation_iterator allocate_many(size_type elem_size, std::size_t num_elements); + 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_iterator allocate_many(const size_type *elem_sizes, size_type n_elements); + 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, @@ -388,7 +386,7 @@ class private_node_allocator //!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_iterator it); + void deallocate_many(multiallocation_chain chain); //!Allocates just one object. Memory allocated with this function //!must be deallocated only with deallocate_one(). @@ -401,7 +399,7 @@ class private_node_allocator //!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_iterator allocate_individual(std::size_t num_elements); + 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 @@ -414,7 +412,7 @@ class private_node_allocator //!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_iterator it); + void deallocate_individual(multiallocation_chain chain); #endif }; diff --git a/include/boost/interprocess/anonymous_shared_memory.hpp b/include/boost/interprocess/anonymous_shared_memory.hpp index e933e3c..0c19a35 100644 --- a/include/boost/interprocess/anonymous_shared_memory.hpp +++ b/include/boost/interprocess/anonymous_shared_memory.hpp @@ -19,7 +19,7 @@ #include #include -#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) # include //open, O_CREAT, O_*... # include //mmap # include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, @@ -42,12 +42,7 @@ namespace detail{ class raw_mapped_region_creator { public: - static - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - mapped_region - #else - move_return - #endif + static mapped_region create_posix_mapped_region(void *address, offset_t offset, std::size_t size) { mapped_region region; @@ -67,14 +62,10 @@ namespace detail{ //!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 -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE -mapped_region -#else -detail::move_return -#endif +//static mapped_region +static mapped_region anonymous_shared_memory(std::size_t size, void *address = 0) -#if (!defined(BOOST_WINDOWS)) || defined(BOOST_DISABLE_WIN32) +#if (!defined(BOOST_INTERPROCESS_WINDOWS)) { int flags; int fd = -1; @@ -115,8 +106,7 @@ anonymous_shared_memory(std::size_t size, void *address = 0) #else { windows_shared_memory anonymous_mapping(create_only, 0, read_write, size); - mapped_region region(anonymous_mapping, read_write, 0, size, address); - return region; + return mapped_region(anonymous_mapping, read_write, 0, size, address); } #endif diff --git a/include/boost/interprocess/containers/allocation_type.hpp b/include/boost/interprocess/containers/allocation_type.hpp new file mode 100644 index 0000000..a22425f --- /dev/null +++ b/include/boost/interprocess/containers/allocation_type.hpp @@ -0,0 +1,40 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +/// @cond +typedef int allocation_type; +/// @endcond +static const allocation_type allocate_new = boost::interprocess_container::allocate_new; +static const allocation_type expand_fwd = boost::interprocess_container::expand_fwd; +static const allocation_type expand_bwd = boost::interprocess_container::expand_bwd; +static const allocation_type shrink_in_place = boost::interprocess_container::shrink_in_place; +static const allocation_type try_shrink_in_place= boost::interprocess_container::try_shrink_in_place; +static const allocation_type nothrow_allocation = boost::interprocess_container::nothrow_allocation; +static const allocation_type zero_memory = boost::interprocess_container::zero_memory; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/containers_fwd.hpp b/include/boost/interprocess/containers/container/containers_fwd.hpp new file mode 100644 index 0000000..3e2eb21 --- /dev/null +++ b/include/boost/interprocess/containers/container/containers_fwd.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP +#define BOOST_CONTAINERS_CONTAINERS_FWD_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +////////////////////////////////////////////////////////////////////////////// +// Standard predeclarations +////////////////////////////////////////////////////////////////////////////// + +/// @cond + +namespace boost{ +namespace intrusive{ + //Create namespace to avoid compilation errors +}} + +namespace boost{ namespace interprocess_container{ namespace containers_detail{ + +namespace bi = boost::intrusive; + +}}} + +namespace std { + +template +class allocator; + +template +struct less; + +template +struct pair; + +template +struct char_traits; + +} //namespace std { + +/// @endcond + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +//vector class +template > +class vector; + +//vector class +template > +class deque; + +//list class +template > +class list; + +//slist class +template > +class slist; + +//set class +template + ,class Alloc = std::allocator > +class set; + +//multiset class +template + ,class Alloc = std::allocator > +class multiset; + +//map class +template + ,class Alloc = std::allocator > > +class map; + +//multimap class +template + ,class Alloc = std::allocator > > +class multimap; + +//flat_set class +template + ,class Alloc = std::allocator > +class flat_set; + +//flat_multiset class +template + ,class Alloc = std::allocator > +class flat_multiset; + +//flat_map class +template + ,class Alloc = std::allocator > > +class flat_map; + +//flat_multimap class +template + ,class Alloc = std::allocator > > +class flat_multimap; + +//basic_string class +template + ,class Alloc = std::allocator > +class basic_string; + +//string class +typedef basic_string + + ,std::allocator > +string; + +}} //namespace boost { namespace interprocess_container { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINERS_FWD_HPP + diff --git a/include/boost/interprocess/containers/container/deque.hpp b/include/boost/interprocess/containers/container/deque.hpp new file mode 100644 index 0000000..0963e18 --- /dev/null +++ b/include/boost/interprocess/containers/container/deque.hpp @@ -0,0 +1,1482 @@ +/* + * + * 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/container 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_CONTAINERS_DEQUE_HPP +#define BOOST_CONTAINERS_DEQUE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +template +class deque; + +template +struct deque_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + boost::interprocess::has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::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 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 + ::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::other allocator_type; + typedef allocator_type stored_allocator_type; + + protected: + + typedef deque_value_traits traits_t; + typedef typename Alloc::template + rebind::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 + { + public: + static std::size_t s_buffer_size() { return deque_base::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; + friend class deque_base; + + protected: + val_alloc_ptr m_cur; + val_alloc_ptr m_first; + val_alloc_ptr m_last; + index_pointer m_node; + + public: + const_iterator(val_alloc_ptr x, index_pointer y) + : m_cur(x), m_first(*y), + m_last(*y + s_buffer_size()), m_node(y) {} + + const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} + + const_iterator(const const_iterator& x) + : m_cur(x.m_cur), m_first(x.m_first), + m_last(x.m_last), m_node(x.m_node) {} + + reference operator*() const + { return *this->m_cur; } + + pointer operator->() const + { return this->m_cur; } + + difference_type operator-(const self_t& x) const + { + 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; + friend class deque_base; + + private: + explicit iterator(const const_iterator& x) : const_iterator(x){} + + public: + //Constructors + iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} + iterator() : const_iterator(){} + //iterator(const const_iterator &cit) : const_iterator(cit){} + iterator(const iterator& x) : const_iterator(x){} + + //Pointer like operators + reference operator*() const { return *this->m_cur; } + pointer operator->() const { return this->m_cur; } + + reference operator[](difference_type n) const { return *(*this + n); } + + //Increment / Decrement + iterator& operator++() + { this->const_iterator::operator++(); return *this; } + + iterator operator++(int) + { iterator tmp = *this; ++*this; return tmp; } + + iterator& operator--() + { this->const_iterator::operator--(); return *this; } + + iterator operator--(int) + { iterator tmp = *this; --*this; return tmp; } + + // Arithmetic + iterator& operator+=(difference_type off) + { this->const_iterator::operator+=(off); return *this; } + + iterator operator+(difference_type off) const + { return iterator(this->const_iterator::operator+(off)); } + + friend iterator operator+(difference_type off, const iterator& right) + { return iterator(off+static_cast(right)); } + + iterator& operator-=(difference_type off) + { this->const_iterator::operator-=(off); return *this; } + + iterator operator-(difference_type off) const + { return iterator(this->const_iterator::operator-(off)); } + + difference_type operator-(const const_iterator& right) const + { return static_cast(*this) - right; } + }; + + deque_base(const allocator_type& a, std::size_t num_elements) + : 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 = containers_detail::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 deque : protected deque_base +{ + /// @cond + typedef deque_base Base; + + public: // Basic types + typedef typename Alloc::value_type val_alloc_val; + typedef typename Alloc::pointer val_alloc_ptr; + typedef typename Alloc::const_pointer val_alloc_cptr; + typedef typename Alloc::reference val_alloc_ref; + typedef typename Alloc::const_reference val_alloc_cref; + typedef typename Alloc::template + rebind::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_reverse_iterator; + typedef std::reverse_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 containers_detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef repeat_iterator r_iterator; + typedef boost::interprocess::move_iterator move_it; + + /// @endcond + + allocator_type get_allocator() const { return Base::alloc(); } + + public: // Basic accessors + BOOST_INTERPROCESS_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); + } + } + + deque(BOOST_INTERPROCESS_RV_REF(deque) mx) + : Base(mx.alloc()) + { this->swap(mx); } + + 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 + deque(InpIt first, InpIt last, const allocator_type& a = allocator_type()) + : Base(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ 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; + } + + deque& operator= (BOOST_INTERPROCESS_RV_REF(deque) x) + { + this->clear(); + this->swap(x); + return *this; + } + + void swap(deque &x) + { + 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 + void assign(InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ 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); + } + } + + void push_back(BOOST_INTERPROCESS_RV_REF(value_type) t) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(boost::interprocess::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); + } + } + + void push_front(BOOST_INTERPROCESS_RV_REF(value_type) t) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(boost::interprocess::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; + containers_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) { + containers_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); + } + } + + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) mx) + { + if (position == cbegin()) { + this->push_front(boost::interprocess::move(mx)); + return begin(); + } + else if (position == cend()) { + this->push_back(boost::interprocess::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 + void insert(const_iterator pos, InpIt first, InpIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + template + void emplace_back(Args&&... args) + { + if(this->priv_push_back_simple_available()){ + new(this->priv_push_back_simple_pos())value_type(boost::interprocess::forward(args)...); + this->priv_push_back_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(this->cend(), 1, proxy); + } + } + + template + void emplace_front(Args&&... args) + { + if(this->priv_push_front_simple_available()){ + new(this->priv_push_front_simple_pos())value_type(boost::interprocess::forward(args)...); + this->priv_push_front_simple_commit(); + } + else{ + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(this->cbegin(), 1, proxy); + } + } + + template + iterator emplace(const_iterator p, Args&&... args) + { + if(p == this->cbegin()){ + this->emplace_front(boost::interprocess::forward(args)...); + return this->begin(); + } + else if(p == this->cend()){ + this->emplace_back(boost::interprocess::forward(args)...); + return (this->end()-1); + } + else{ + size_type n = p - this->cbegin(); + containers_detail::advanced_insert_aux_emplace proxy(boost::interprocess::forward(args)...); + this->priv_insert_aux_impl(p, 1, proxy); + return iterator(this->begin() + n); + } + } + + #else //#ifdef BOOST_CONTAINERS_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{ + containers_detail::advanced_insert_aux_emplace 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{ + containers_detail::advanced_insert_aux_emplace 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(); + containers_detail::advanced_insert_aux_emplace 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 \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_back_simple_available()){ \ + new(priv_push_back_simple_pos())value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_push_back_simple_commit(); \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cend(), 1, proxy); \ + } \ + } \ + \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(priv_push_front_simple_available()){ \ + new(priv_push_front_simple_pos())value_type \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_push_front_simple_commit(); \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_insert_aux_impl(cbegin(), 1, proxy); \ + } \ + } \ + \ + template \ + iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + if(p == this->cbegin()){ \ + this->emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + return this->begin(); \ + } \ + else if(p == cend()){ \ + this->emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + return (this->end()-1); \ + } \ + else{ \ + size_type pos_num = p - this->cbegin(); \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + this->priv_insert_aux_impl(p, 1, proxy); \ + return iterator(this->begin() + pos_num); \ + } \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_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(); + containers_detail::default_construct_aux_proxy 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::interprocess::move_backward(begin(), iterator(pos), iterator(next)); + pop_front(); + } + else { + boost::interprocess::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(this->size() - n) - elems_before) { + boost::interprocess::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::interprocess::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(containers_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(containers_detail::get_pointer(this->members_.m_start.m_cur) - 1); } + + void priv_push_front_simple_commit() + { --this->members_.m_start.m_cur; } + + template + void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, boost::interprocess::move(value_type(*first))); + } + } + + template + 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 + void priv_initialize_dispatch(Integer n, Integer x, containers_detail::true_) + { + this->priv_initialize_map(n); + this->priv_fill_initialize(x); + } + + template + void priv_initialize_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_initialize(first, last, ItCat()); + } + + void priv_destroy_range(iterator p, iterator p2) + { + for(;p != p2; ++p) + containers_detail::get_pointer(&*p)->~value_type(); + } + + void priv_destroy_range(pointer p, pointer p2) + { + for(;p != p2; ++p) + containers_detail::get_pointer(&*p)->~value_type(); + } + + template + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) + { + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first) + *cur = *first; + if (first == last) + this->erase(cur, cend()); + else + this->insert(cend(), first, last); + } + + template + 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 + void priv_insert_dispatch(const_iterator pos, Integer n, Integer x, containers_detail::true_) + { this->priv_fill_insert(pos, (size_type) n, (value_type) x); } + + template + void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, containers_detail::false_) + { + typedef typename std::iterator_traits::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 c_it; + this->priv_insert_aux(pos, c_it(x, n), c_it()); + } + + //Just forward all operations to priv_insert_aux_impl + template + void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) + { + containers_detail::advanced_insert_aux_proxy 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(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::interprocess::uninitialized_move(this->members_.m_start, start_n, new_start); + this->members_.m_start = new_start; + boost::interprocess::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::interprocess::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::interprocess::uninitialized_move(finish_n, this->members_.m_finish, this->members_.m_finish); + this->members_.m_finish = new_finish; + boost::interprocess::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::interprocess::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 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 + void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) + { + this->priv_initialize_map(0); + BOOST_TRY { + for ( ; first != last; ++first) + this->push_back(*first); + } + BOOST_CATCH(...){ + this->clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = 0; + n = std::distance(first, last); + this->priv_initialize_map(n); + + index_pointer cur_node; + BOOST_TRY { + for (cur_node = this->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::interprocess::uninitialized_copy_or_move(first, mid, *cur_node); + first = mid; + } + boost::interprocess::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; + containers_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() + { + containers_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::interprocess::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + else + boost::interprocess::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 + containers_detail::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::interprocess::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 +inline bool operator==(const deque& x, + const deque& y) +{ + return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool operator<(const deque& x, + const deque& y) +{ + return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const deque& x, + const deque& y) + { return !(x == y); } + +template +inline bool operator>(const deque& x, + const deque& y) + { return y < x; } + +template +inline bool operator<=(const deque& x, + const deque& y) + { return !(y < x); } + +template +inline bool operator>=(const deque& x, + const deque& y) + { return !(x < y); } + + +template +inline void swap(deque& x, deque& y) +{ x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + enum { value = has_trivial_destructor::value }; +}; + +}} + +/// @endcond + +#include + +#endif // #ifndef BOOST_CONTAINERS_DEQUE_HPP diff --git a/include/boost/interprocess/detail/advanced_insert_int.hpp b/include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp similarity index 77% rename from include/boost/interprocess/detail/advanced_insert_int.hpp rename to include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp index 42b2f31..35ed645 100644 --- a/include/boost/interprocess/detail/advanced_insert_int.hpp +++ b/include/boost/interprocess/containers/container/detail/advanced_insert_int.hpp @@ -4,26 +4,26 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP -#define BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP +#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP +#define BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include #include #include //std::iterator_traits #include //std::copy, std::uninitialized_copy #include //placement new #include -namespace boost { namespace interprocess { namespace detail { +namespace boost { namespace interprocess_container { namespace containers_detail { //This class will be interface for operations dependent on FwdIt types used advanced_insert_aux_impl template @@ -51,21 +51,21 @@ struct advanced_insert_aux_proxy {} virtual void copy_all_to(Iterator p) - { *std::copy(first_, last_, p); } + { std::copy(first_, last_, p); } virtual void uninitialized_copy_all_to(Iterator p) - { std::uninitialized_copy(first_, last_, p); } + { boost::interprocess::uninitialized_copy_or_move(first_, last_, p); } virtual void uninitialized_copy_some_and_update(Iterator pos, difference_type division_count, bool first_n) { FwdIt mid = first_; std::advance(mid, division_count); if(first_n){ - std::uninitialized_copy(first_, mid, pos); + boost::interprocess::uninitialized_copy_or_move(first_, mid, pos); first_ = mid; } else{ - std::uninitialized_copy(mid, last_, pos); + boost::interprocess::uninitialized_copy_or_move(mid, last_, pos); last_ = mid; } } @@ -104,12 +104,12 @@ struct default_construct_aux_proxy SizeType i = 0; try{ for(; i < n; ++i, ++p){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); } } catch(...){ while(i--){ - detail::get_pointer(&*orig_p++)->~T(); + containers_detail::get_pointer(&*orig_p++)->~T(); } throw; } @@ -159,18 +159,18 @@ struct default_construct_aux_proxy SizeType count_; }; -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include #include #include //#include //For debugging purposes namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { //This class template will adapt each FwIt types to advanced_insert_aux_int template @@ -204,8 +204,8 @@ struct advanced_insert_aux_emplace void priv_copy_all_to(const index_tuple&, Iterator p) { if(!used_){ - T object(detail::forward_impl(get(args_))...); - *p = detail::move_impl(object); + T object(boost::interprocess::forward(get(args_))...); + *p = boost::interprocess::move(object); used_ = true; } } @@ -214,7 +214,7 @@ struct advanced_insert_aux_emplace void priv_uninitialized_copy_all_to(const index_tuple&, Iterator p) { if(!used_){ - new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward(get(args_))...); used_ = true; } } @@ -225,7 +225,7 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - new(detail::get_pointer(&*p))T(detail::forward_impl(get(args_))...); + new(containers_detail::get_pointer(&*p))T(boost::interprocess::forward(get(args_))...); used_ = true; } } @@ -237,8 +237,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - T object(detail::forward_impl(get(args_))...); - *p = detail::move_impl(object); + T object(boost::interprocess::forward(get(args_))...); + *p = boost::interprocess::move(object); used_ = true; } } @@ -247,25 +247,16 @@ struct advanced_insert_aux_emplace bool used_; }; -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include +#include namespace boost { -namespace interprocess { -namespace detail { - -template -struct value_init_helper -{ - value_init_helper() - : m_t() - {} - - T m_t; -}; +namespace interprocess_container { +namespace containers_detail { //This class template will adapt each FwIt types to advanced_insert_aux_int template @@ -283,8 +274,8 @@ struct advanced_insert_aux_emplace virtual void copy_all_to(Iterator p) { if(!used_){ - value_init_helperv; - *p = detail::move_impl(v.m_t); + value_initv; + *p = boost::interprocess::move(v.m_t); used_ = true; } } @@ -292,7 +283,7 @@ struct advanced_insert_aux_emplace virtual void uninitialized_copy_all_to(Iterator p) { if(!used_){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); used_ = true; } } @@ -302,7 +293,7 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - new(detail::get_pointer(&*p))T(); + new(containers_detail::get_pointer(&*p))T(); used_ = true; } } @@ -313,8 +304,8 @@ struct advanced_insert_aux_emplace assert(division_count <=1); if((first_n && division_count == 1) || (!first_n && division_count == 0)){ if(!used_){ - value_init_helperv; - *p = detail::move_impl(v.m_t); + value_initv; + *p = boost::interprocess::move(v.m_t); used_ = true; } } @@ -331,14 +322,14 @@ struct advanced_insert_aux_emplace typedef typename advanced_insert_aux_int::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, _) {} \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \ + : used_(false), BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \ \ virtual void copy_all_to(Iterator p) \ { \ if(!used_){ \ - T v(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_MEMBER_FORWARD, _)); \ - *p = detail::move_impl(v); \ + T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + *p = boost::interprocess::move(v); \ used_ = true; \ } \ } \ @@ -346,8 +337,8 @@ struct advanced_insert_aux_emplace 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, _)); \ + new(containers_detail::get_pointer(&*p))T \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ used_ = true; \ } \ } \ @@ -358,8 +349,8 @@ struct advanced_insert_aux_emplace 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, _)); \ + new(containers_detail::get_pointer(&*p))T \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ used_ = true; \ } \ } \ @@ -371,25 +362,25 @@ struct advanced_insert_aux_emplace 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 = detail::move_impl(v); \ + T v(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + *p = boost::interprocess::move(v); \ used_ = true; \ } \ } \ } \ \ bool used_; \ - BOOST_PP_REPEAT(n, BOOST_INTERPROCESS_AUX_PARAM_DEFINE, _) \ + BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \ }; \ //! -#define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() -}}} //namespace boost { namespace interprocess { namespace detail { +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { -#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING +#endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_ADVANCED_INSERT_INT_HPP +#endif //#ifndef BOOST_CONTAINERS_ADVANCED_INSERT_INT_HPP diff --git a/include/boost/interprocess/detail/algorithms.hpp b/include/boost/interprocess/containers/container/detail/algorithms.hpp similarity index 70% rename from include/boost/interprocess/detail/algorithms.hpp rename to include/boost/interprocess/containers/container/detail/algorithms.hpp index 534dfef..d3baff3 100644 --- a/include/boost/interprocess/detail/algorithms.hpp +++ b/include/boost/interprocess/containers/container/detail/algorithms.hpp @@ -6,59 +6,63 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP -#define BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP +#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP +#define BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include -#include -#include +#include +#include + #include #include #include #include + +#include +#include +#include + + #include namespace boost { -namespace interprocess { - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) +namespace interprocess_container { +#if !defined(BOOST_HAS_RVALUE_REFS) template struct has_own_construct_from_it { static const bool value = false; }; -namespace detail { +namespace containers_detail { template -inline void construct_in_place_impl(T* dest, const InpIt &source, detail::true_) +inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::true_) { T::construct(dest, *source); } template -inline void construct_in_place_impl(T* dest, const InpIt &source, detail::false_) +inline void construct_in_place_impl(T* dest, const InpIt &source, containers_detail::false_) { new((void*)dest)T(*source); } -} //namespace detail { +} //namespace containers_detail { template inline void construct_in_place(T* dest, InpIt source) { - typedef detail::bool_::value> boolean_t; - detail::construct_in_place_impl(dest, source, boolean_t()); + typedef containers_detail::bool_::value> boolean_t; + containers_detail::construct_in_place_impl(dest, source, boolean_t()); } #else @@ -73,6 +77,12 @@ inline void construct_in_place(T *dest, default_construct_iterator) new((void*)dest)T(); } +template +inline void construct_in_place(T *dest, emplace_iterator ei) +{ + ei.construct_in_place(dest); +} + template struct optimize_assign { @@ -108,7 +118,7 @@ struct optimize_copy {}; template inline -OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, detail::bool_) +OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::difference_type length, OutIt dest, containers_detail::bool_) { for (; length--; ++dest, ++first) *dest = *first; @@ -116,7 +126,7 @@ OutIt copy_n_dispatch(InIt first, typename std::iterator_traits::differenc } template inline -T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +T *copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, containers_detail::bool_) { std::size_t size = length*sizeof(T); return (static_cast(std::memmove(dest, first, size))) + size; @@ -126,14 +136,14 @@ template inline OutIt copy_n(InIt first, typename std::iterator_traits::difference_type length, OutIt dest) { const bool do_optimized_assign = optimize_assign::value; - return copy_n_dispatch(first, length, dest, detail::bool_()); + return copy_n_dispatch(first, length, dest, containers_detail::bool_()); } template inline FwdIt uninitialized_copy_n_dispatch (InIt first, typename std::iterator_traits::difference_type count, - FwdIt dest, detail::bool_) + FwdIt dest, containers_detail::bool_) { typedef typename std::iterator_traits::value_type value_type; //Save initial destination position @@ -143,14 +153,14 @@ FwdIt uninitialized_copy_n_dispatch BOOST_TRY{ //Try to build objects for (; --new_count; ++dest, ++first){ - construct_in_place(detail::get_pointer(&*dest), first); + construct_in_place(containers_detail::get_pointer(&*dest), first); } } BOOST_CATCH(...){ //Call destructors new_count = count - new_count; for (; new_count--; ++dest_init){ - detail::get_pointer(&*dest_init)->~value_type(); + containers_detail::get_pointer(&*dest_init)->~value_type(); } BOOST_RETHROW } @@ -158,7 +168,7 @@ FwdIt uninitialized_copy_n_dispatch return dest; } template inline -T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, detail::bool_) +T *uninitialized_copy_n_dispatch(const T *first, typename std::iterator_traits::difference_type length, T *dest, containers_detail::bool_) { std::size_t size = length*sizeof(T); return (static_cast(std::memmove(dest, first, size))) + size; @@ -171,7 +181,7 @@ FwdIt uninitialized_copy_n FwdIt dest) { const bool do_optimized_copy = optimize_copy::value; - return uninitialized_copy_n_dispatch(first, count, dest, detail::bool_()); + return uninitialized_copy_n_dispatch(first, count, dest, containers_detail::bool_()); } // uninitialized_copy_copy @@ -189,17 +199,17 @@ FwdIt uninitialized_copy_copy } BOOST_CATCH(...){ for(;result != mid; ++result){ - detail::get_pointer(&*result)->~value_type(); + containers_detail::get_pointer(&*result)->~value_type(); } BOOST_RETHROW } BOOST_CATCH_END } -} //namespace interprocess { +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ALGORITHMS_HPP +#endif //#ifndef BOOST_CONTAINERS_DETAIL_ALGORITHMS_HPP diff --git a/include/boost/interprocess/allocators/allocation_type.hpp b/include/boost/interprocess/containers/container/detail/allocation_type.hpp similarity index 75% rename from include/boost/interprocess/allocators/allocation_type.hpp rename to include/boost/interprocess/containers/container/detail/allocation_type.hpp index 1894d11..7cbffb3 100644 --- a/include/boost/interprocess/allocators/allocation_type.hpp +++ b/include/boost/interprocess/containers/container/detail/allocation_type.hpp @@ -4,22 +4,22 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // /////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_TYPE_COMMAND_HPP -#define BOOST_INTERPROCESS_TYPE_COMMAND_HPP +#ifndef BOOST_CONTAINERS_ALLOCATION_TYPE_HPP +#define BOOST_CONTAINERS_ALLOCATION_TYPE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include namespace boost { -namespace interprocess { +namespace interprocess_container { /// @cond enum allocation_type_v @@ -46,10 +46,9 @@ static const allocation_type try_shrink_in_place= (allocation_type)try_shrink_in 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 interprocess_container { } //namespace boost { -#include - -#endif //BOOST_INTERPROCESS_TYPE_COMMAND_HPP +#include +#endif //BOOST_CONTAINERS_ALLOCATION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/detail/config_begin.hpp b/include/boost/interprocess/containers/container/detail/config_begin.hpp new file mode 100644 index 0000000..814b00c --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/config_begin.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED +#define BOOST_CONTAINERS_CONTAINER_DETAIL_CONFIG_INCLUDED +#include +#endif + +#ifdef BOOST_MSVC + #ifndef _CRT_SECURE_NO_DEPRECATE + #define BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #define _CRT_SECURE_NO_DEPRECATE + #endif + #pragma warning (push) + #pragma warning (disable : 4702) // unreachable code + #pragma warning (disable : 4706) // assignment within conditional expression + #pragma warning (disable : 4127) // conditional expression is constant + #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" + #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data + #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" + #pragma warning (disable : 4355) // "this" : used in base member initializer list + #pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated + #pragma warning (disable : 4511) // copy constructor could not be generated + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4514) // unreferenced inline removed + #pragma warning (disable : 4521) // Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) // "class" : multiple assignment operators specified + #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter + #pragma warning (disable : 4710) // function not inlined + #pragma warning (disable : 4711) // function selected for automatic inline expansion + #pragma warning (disable : 4786) // identifier truncated in debug info + #pragma warning (disable : 4996) // "function": was declared deprecated + #pragma warning (disable : 4197) // top-level volatile in cast is ignored + #pragma warning (disable : 4541) // 'typeid' used on polymorphic type 'boost::exception' + // with /GR-; unpredictable behavior may result + #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site + #pragma warning (disable : 4671) // the copy constructor is inaccessible +#endif diff --git a/include/boost/interprocess/containers/container/detail/config_end.hpp b/include/boost/interprocess/containers/container/detail/config_end.hpp new file mode 100644 index 0000000..a6c46ef --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/config_end.hpp @@ -0,0 +1,17 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) + #ifdef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #undef BOOST_CONTAINERS_DETAIL_CRT_SECURE_NO_DEPRECATE + #undef _CRT_SECURE_NO_DEPRECATE + #endif +#endif + diff --git a/include/boost/interprocess/containers/container/detail/destroyers.hpp b/include/boost/interprocess/containers/container/detail/destroyers.hpp new file mode 100644 index 0000000..c16139b --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/destroyers.hpp @@ -0,0 +1,154 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DESTROYERS_HPP +#define BOOST_CONTAINERS_DESTROYERS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an array of objects using a STL allocator. +template +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 +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 +struct scoped_destructor_n +{ + typedef typename Allocator::pointer pointer; + typedef typename Allocator::value_type value_type; + typedef typename Allocator::size_type size_type; + + pointer m_p; + size_type m_n; + + scoped_destructor_n(pointer p, size_type n) + : m_p(p), m_n(n) + {} + + void release() + { m_p = 0; } + + void increment_size(size_type inc) + { m_n += inc; } + + ~scoped_destructor_n() + { + if(!m_p) return; + value_type *raw_ptr = containers_detail::get_pointer(m_p); + for(std::size_t i = 0; i < m_n; ++i, ++raw_ptr) + raw_ptr->~value_type(); + } +}; + +//!A deleter for scoped_ptr that destroys +//!an object using a STL allocator. +template +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 allocator_destroyer +{ + typedef typename A::value_type value_type; + typedef containers_detail::integral_constant::value> alloc_version; + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + + private: + A & a_; + + private: + void priv_deallocate(const typename A::pointer &p, allocator_v1) + { a_.deallocate(p, 1); } + + void priv_deallocate(const typename A::pointer &p, allocator_v2) + { a_.deallocate_one(p); } + + public: + allocator_destroyer(A &a) + : a_(a) + {} + + void operator()(const typename A::pointer &p) + { + containers_detail::get_pointer(p)->~value_type(); + priv_deallocate(p, alloc_version()); + } +}; + + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DESTROYERS_HPP diff --git a/include/boost/interprocess/containers/detail/flat_tree.hpp b/include/boost/interprocess/containers/container/detail/flat_tree.hpp similarity index 80% rename from include/boost/interprocess/containers/detail/flat_tree.hpp rename to include/boost/interprocess/containers/container/detail/flat_tree.hpp index c2ebfc1..438fa75 100644 --- a/include/boost/interprocess/containers/detail/flat_tree.hpp +++ b/include/boost/interprocess/containers/container/detail/flat_tree.hpp @@ -4,7 +4,7 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // //////////////////////////////////////////////////////////////////////////////// // The Loki Library @@ -25,35 +25,40 @@ // //////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_TREE_HPP -#define BOOST_INTERPROCESS_FLAT_TREE_HPP +#ifndef BOOST_CONTAINERS_FLAT_TREE_HPP +#define BOOST_CONTAINERS_FLAT_TREE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include -#include -#include -#include -#include #include #include #include +#include +#include + +#include +#include +#include +#include +#include + namespace boost { -namespace interprocess { +namespace interprocess_container { -namespace detail { +namespace containers_detail { template class flat_tree { - typedef boost::interprocess::vector vector_t; + typedef boost::interprocess_container::vector vector_t; typedef Alloc allocator_t; public: @@ -105,6 +110,7 @@ class flat_tree Data m_data; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(flat_tree) typedef typename vector_t::value_type value_type; typedef typename vector_t::pointer pointer; @@ -133,15 +139,9 @@ class flat_tree : m_data(x.m_data, x.m_data.m_vect) { } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree(detail::moved_object x) - : m_data(detail::move_impl(x.get().m_data)) + flat_tree(BOOST_INTERPROCESS_RV_REF(flat_tree) x) + : m_data(boost::interprocess::move(x.m_data)) { } - #else - flat_tree(flat_tree &&x) - : m_data(detail::move_impl(x.m_data)) - { } - #endif ~flat_tree() { } @@ -149,13 +149,8 @@ class flat_tree flat_tree& operator=(const flat_tree& x) { m_data = x.m_data; return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - flat_tree& operator=(detail::moved_object mx) - { m_data = detail::move_impl(mx.get().m_data); return *this; } - #else - flat_tree& operator=(flat_tree &&mx) - { m_data = detail::move_impl(mx.m_data); return *this; } - #endif + flat_tree& operator=(BOOST_INTERPROCESS_RV_REF(flat_tree) mx) + { m_data = boost::interprocess::move(mx.m_data); return *this; } public: // accessors: @@ -220,20 +215,12 @@ class flat_tree { value_compare& mycomp = this->m_data; value_compare& othercomp = other.m_data; - detail::do_swap(mycomp, othercomp); + containers_detail::do_swap(mycomp, othercomp); vector_t & myvect = this->m_data.m_vect; vector_t & othervect = other.m_data.m_vect; myvect.swap(othervect); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object other) - { this->swap(other.get()); } - #else - void swap(flat_tree &&other) - { this->swap(other); } - #endif - public: // insert/erase std::pair insert_unique(const value_type& val) @@ -246,18 +233,12 @@ class flat_tree return ret; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - std::pair insert_unique(detail::moved_object mval) + std::pair insert_unique(BOOST_INTERPROCESS_RV_REF(value_type) val) { - value_type &val = mval.get(); - #else - std::pair insert_unique(value_type && val) - { - #endif insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret; } @@ -270,21 +251,12 @@ class flat_tree return i; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(detail::moved_object 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 insert_equal(BOOST_INTERPROCESS_RV_REF(value_type) mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, detail::move_impl(mval)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(mval)); return i; } - #endif iterator insert_unique(const_iterator pos, const value_type& val) { @@ -296,27 +268,15 @@ class flat_tree return ret.first; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_unique(const_iterator pos, detail::moved_object mval) - { - insert_commit_data data; - std::pair 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) + iterator insert_unique(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval) { insert_commit_data data; std::pair ret = priv_insert_unique_prepare(pos, mval, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(mval)); + ret.first = priv_insert_commit(data, boost::interprocess::move(mval)); } return ret.first; } - #endif iterator insert_equal(const_iterator pos, const value_type& val) { @@ -325,21 +285,12 @@ class flat_tree return priv_insert_commit(data, val); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - iterator insert_equal(const_iterator pos, detail::moved_object 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) + iterator insert_equal(const_iterator pos, BOOST_INTERPROCESS_RV_REF(value_type) mval) { insert_commit_data data; priv_insert_equal_prepare(pos, mval, data); - return priv_insert_commit(data, detail::move_impl(mval)); + return priv_insert_commit(data, boost::interprocess::move(mval)); } - #endif template void insert_unique(InIt first, InIt last) @@ -356,17 +307,17 @@ class flat_tree priv_insert_equal(first, last, ItCat()); } - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template iterator emplace_unique(Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } @@ -374,11 +325,11 @@ class flat_tree template iterator emplace_hint_unique(const_iterator hint, Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; std::pair ret = priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } @@ -386,115 +337,115 @@ class flat_tree template iterator emplace_equal(Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); return i; } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - value_type val(detail::forward_impl(args)...); + value_type val(boost::interprocess::forward(args)...); insert_commit_data data; priv_insert_equal_prepare(hint, val, data); - return priv_insert_commit(data, detail::move_impl(val)); + return priv_insert_commit(data, boost::interprocess::move(val)); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator emplace_unique() { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; std::pair ret = priv_insert_unique_prepare(val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } iterator emplace_hint_unique(const_iterator hint) { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; std::pair ret = priv_insert_unique_prepare(hint, val, data); if(ret.second){ - ret.first = priv_insert_commit(data, detail::move_impl(val)); + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); } return ret.first; } iterator emplace_equal() { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); return i; } iterator emplace_hint_equal(const_iterator hint) { - detail::value_init vval; + containers_detail::value_init vval; value_type &val = vval.m_t; insert_commit_data data; priv_insert_equal_prepare(hint, val, data); - return priv_insert_commit(data, detail::move_impl(val)); + return priv_insert_commit(data, boost::interprocess::move(val)); } #define BOOST_PP_LOCAL_MACRO(n) \ template \ - iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ std::pair ret = priv_insert_unique_prepare(val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); \ } \ return ret.first; \ } \ \ template \ iterator emplace_hint_unique(const_iterator hint, \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ std::pair ret = priv_insert_unique_prepare(hint, val, data); \ if(ret.second){ \ - ret.first = priv_insert_commit(data, detail::move_impl(val)); \ + ret.first = priv_insert_commit(data, boost::interprocess::move(val)); \ } \ return ret.first; \ } \ \ template \ - iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ iterator i = this->upper_bound(KeyOfValue()(val)); \ - i = this->m_data.m_vect.insert(i, detail::move_impl(val)); \ + i = this->m_data.m_vect.insert(i, boost::interprocess::move(val)); \ return i; \ } \ \ template \ iterator emplace_hint_equal(const_iterator hint, \ - BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - value_type val(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + value_type val(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ insert_commit_data data; \ priv_insert_equal_prepare(hint, val, data); \ - return priv_insert_commit(data, detail::move_impl(val)); \ + return priv_insert_commit(data, boost::interprocess::move(val)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator erase(const_iterator position) { return this->m_data.m_vect.erase(position); } @@ -682,17 +633,14 @@ class flat_tree } } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator priv_insert_commit - (insert_commit_data &commit_data, const Convertible &convertible) - { return this->m_data.m_vect.insert(commit_data.position, convertible); } - #else - template - iterator priv_insert_commit - (insert_commit_data &commit_data, Convertible &&convertible) - { return this->m_data.m_vect.insert(commit_data.position, detail::forward_impl(convertible)); } - #endif + (insert_commit_data &commit_data, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible) + { + return this->m_data.m_vect.insert + ( commit_data.position + , boost::interprocess::forward(convertible)); + } template RanIt priv_lower_bound(RanIt first, RanIt last, @@ -865,23 +813,25 @@ swap(flat_tree& x, flat_tree& y) { x.swap(y); } -} //namespace detail { +} //namespace containers_detail { + +} //namespace interprocess_container { + +namespace interprocess { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class C, class A> +struct has_trivial_destructor_after_move > { - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; }; } //namespace interprocess { } //namespace boost { -#include +#include -#endif // BOOST_INTERPROCESS_FLAT_TREE_HPP +#endif // BOOST_CONTAINERS_FLAT_TREE_HPP diff --git a/include/boost/interprocess/detail/iterators.hpp b/include/boost/interprocess/containers/container/detail/iterators.hpp similarity index 65% rename from include/boost/interprocess/detail/iterators.hpp rename to include/boost/interprocess/containers/container/detail/iterators.hpp index c566159..64841b1 100644 --- a/include/boost/interprocess/detail/iterators.hpp +++ b/include/boost/interprocess/containers/container/detail/iterators.hpp @@ -7,27 +7,31 @@ // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP -#define BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP +#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP +#define BOOST_CONTAINERS_DETAIL_ITERATORS_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include +#include +#include +#include -#include +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#else +#include +#endif #include -#include namespace boost { -namespace interprocess { +namespace interprocess_container { template class constant_iterator @@ -324,152 +328,165 @@ class repeat_iterator { return m_num - other.m_num; } }; -template -struct operator_arrow_proxy +template +class emplace_iterator + : public std::iterator + { - operator_arrow_proxy(const PseudoReference &px) - : m_value(px) - {} + typedef emplace_iterator this_type; - 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 -struct operator_arrow_proxy -{ - 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 transform_iterator - : public UnaryFunction - , public std::iterator - < typename Iterator::iterator_category - , typename detail::remove_reference::type - , typename Iterator::difference_type - , operator_arrow_proxy - , typename UnaryFunction::result_type> -{ public: - explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction()) - : UnaryFunction(f), m_it(it) - {} + explicit emplace_iterator(E&e) + : m_num(1), m_pe(&e){} - explicit transform_iterator() - : UnaryFunction(), m_it() - {} + emplace_iterator() + : m_num(0), m_pe(0){} - //Constructors - transform_iterator& operator++() + this_type& operator++() { increment(); return *this; } - - transform_iterator operator++(int) + + this_type operator++(int) { - transform_iterator result (*this); + this_type result (*this); increment(); return result; } - friend bool operator== (const transform_iterator& i, const transform_iterator& i2) + friend bool operator== (const this_type& i, const this_type& i2) { return i.equal(i2); } - friend bool operator!= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator!= (const this_type& i, const this_type& i2) { return !(i == i2); } -/* - friend bool operator> (const transform_iterator& i, const transform_iterator& 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 transform_iterator& i, const transform_iterator& i2) + friend bool operator<= (const this_type& i, const this_type& i2) { return !(i > i2); } - friend bool operator>= (const transform_iterator& i, const transform_iterator& i2) + friend bool operator>= (const this_type& i, const this_type& i2) { return !(i < i2); } -*/ - friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2) + + friend std::ptrdiff_t operator- (const this_type& i, const this_type& i2) { return i2.distance_to(i); } //Arithmetic - transform_iterator& operator+=(typename Iterator::difference_type off) + this_type& operator+=(std::ptrdiff_t off) { this->advance(off); return *this; } - transform_iterator operator+(typename Iterator::difference_type off) const + this_type operator+(std::ptrdiff_t off) const { - transform_iterator other(*this); + this_type other(*this); other.advance(off); return other; } - friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right) + friend this_type operator+(std::ptrdiff_t off, const this_type& right) { return right + off; } - transform_iterator& operator-=(typename Iterator::difference_type off) + this_type& operator-=(std::ptrdiff_t off) { this->advance(-off); return *this; } - transform_iterator operator-(typename Iterator::difference_type off) const + this_type operator-(std::ptrdiff_t off) const { return *this + (-off); } - typename UnaryFunction::result_type operator*() const + const T& operator*() const { return dereference(); } - operator_arrow_proxy - operator->() const - { return operator_arrow_proxy(dereference()); } + const T* operator->() const + { return &(dereference()); } - Iterator & base() - { return m_it; } - - const Iterator & base() const - { return m_it; } + void construct_in_place(T* ptr) + { (*m_pe)(ptr); } private: - Iterator m_it; + std::ptrdiff_t m_num; + E * m_pe; void increment() - { ++m_it; } + { --m_num; } void decrement() - { --m_it; } + { ++m_num; } - bool equal(const transform_iterator &other) const - { return m_it == other.m_it; } + bool equal(const this_type &other) const + { return m_num == other.m_num; } - bool less(const transform_iterator &other) const - { return other.m_it < m_it; } + bool less(const this_type &other) const + { return other.m_num < m_num; } - typename UnaryFunction::result_type dereference() const - { return UnaryFunction::operator()(*m_it); } + const T & dereference() const + { + static T dummy; + return dummy; + } - void advance(typename Iterator::difference_type n) - { std::advance(m_it, n); } + void advance(std::ptrdiff_t n) + { m_num -= n; } - typename Iterator::difference_type distance_to(const transform_iterator &other)const - { return std::distance(other.m_it, m_it); } + std::ptrdiff_t distance_to(const this_type &other)const + { return m_num - other.m_num; } }; -template -transform_iterator -make_transform_iterator(Iterator it, UnaryFunc fun) -{ - return transform_iterator(it, fun); -} +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING -} //namespace interprocess { +template +struct emplace_functor +{ + typedef typename containers_detail::build_number_seq::type index_tuple_t; + + emplace_functor(Args&&... args) + : args_(args...) + {} + + void operator()(T *ptr) + { emplace_functor::inplace_impl(ptr, index_tuple_t()); } + + template + void inplace_impl(T* ptr, const containers_detail::index_tuple&) + { ::new(ptr) T(boost::interprocess::forward(containers_detail::get(args_))...); } + + containers_detail::tuple args_; +}; + +#else + +template +struct emplace_functor +{ + emplace_functor() + {} + void operator()(T *ptr) + { new(ptr) T(); } +}; + +#define BOOST_PP_LOCAL_MACRO(n) \ + template \ + struct BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + { \ + BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + ( BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _) ) \ + : BOOST_PP_ENUM(n, BOOST_CONTAINERS_AUX_PARAM_INIT, _) {} \ + \ + void operator()(T *ptr) \ + { \ + new(ptr)T (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_MEMBER_FORWARD, _)); \ + } \ + BOOST_PP_REPEAT(n, BOOST_CONTAINERS_AUX_PARAM_DEFINE, _) \ + }; \ + //! +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) +#include BOOST_PP_LOCAL_ITERATE() + +#endif + +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif //#ifndef BOOST_INTERPROCESS_DETAIL_ITERATORS_HPP +#endif //#ifndef BOOST_CONTAINERS_DETAIL_ITERATORS_HPP diff --git a/include/boost/interprocess/containers/container/detail/mpl.hpp b/include/boost/interprocess/containers/container/detail/mpl.hpp new file mode 100644 index 0000000..fbdcb44 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/mpl.hpp @@ -0,0 +1,152 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP +#define BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct integral_constant +{ + static const T value = val; + typedef integral_constant type; +}; + +template< bool C_ > +struct bool_ : integral_constant +{ + static const bool value = C_; +}; + +typedef bool_ true_; +typedef bool_ false_; + +typedef true_ true_type; +typedef false_ false_type; + +typedef char yes_type; +struct no_type +{ + char padding[8]; +}; + +template +struct enable_if_c { + typedef T type; +}; + +template +struct enable_if_c {}; + +template +struct enable_if : public enable_if_c {}; + +template +struct disable_if : public enable_if_c {}; + +template +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 +{ + typedef T2 type; +}; + +template< + typename T1 + , typename T2 + , typename T3 + > +struct if_ +{ + typedef typename if_c<0 != T1::value, T2, T3>::type type; +}; + + +template +struct select1st +// : public std::unary_function +{ + template + 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 +struct identity +// : public std::unary_function +{ + typedef T type; + const T& operator()(const T& x) const + { return x; } +}; + +template +struct ls_zeros +{ + static const std::size_t value = (S & std::size_t(1)) ? 0 : (1u + ls_zeros<(S >> 1u)>::value); +}; + +template<> +struct ls_zeros<0> +{ + static const std::size_t value = 0; +}; + +template<> +struct ls_zeros<1> +{ + static const std::size_t value = 0; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_MPL_HPP + diff --git a/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp b/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp new file mode 100644 index 0000000..1f3f2c5 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/multiallocation_chain.hpp @@ -0,0 +1,554 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP +#define BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +class basic_multiallocation_slist +{ +public: + typedef VoidPointer void_pointer; + +private: + static VoidPointer &priv_get_ref(const VoidPointer &p) + { return *static_cast(containers_detail::get_pointer(p)); } + + basic_multiallocation_slist(basic_multiallocation_slist &); + basic_multiallocation_slist &operator=(basic_multiallocation_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist) + + //!This iterator is returned by "allocate_many" functions so that + //!the user can access the multiple buffers allocated in a single call + class iterator + : public std::iterator + { + friend class basic_multiallocation_slist; + 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(containers_detail::get_pointer(next_node_)); + return *this; + } + + iterator operator++(int) + { + iterator result(*this); + ++*this; + return result; + } + + bool operator== (const iterator& other) const + { return next_node_ == other.next_node_; } + + bool operator!= (const iterator& other) const + { return !operator== (other); } + + reference operator*() const + { return *static_cast(containers_detail::get_pointer(next_node_)); } + + operator unspecified_bool_type() const + { return next_node_? &iterator::unspecified_bool_type_func : 0; } + + pointer operator->() const + { return &(*(*this)); } + + private: + void_pointer next_node_; + }; + +private: + iterator it_; + +public: + basic_multiallocation_slist() + : it_(iterator()) + {} + + basic_multiallocation_slist(void_pointer p) + : it_(p ? iterator_to(p) : iterator()) + {} + + basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + : it_(iterator()) + { this->swap(other); } + + basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + { + basic_multiallocation_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return !it_; } + + iterator before_begin() const + { return iterator(void_pointer(const_cast(static_cast(&it_.next_node_)))); } + + iterator begin() const + { return it_; } + + iterator end() const + { return iterator(); } + + void clear() + { this->it_.next_node_ = void_pointer(0); } + + iterator insert_after(iterator it, void_pointer m) + { + priv_get_ref(m) = priv_get_ref(it.next_node_); + priv_get_ref(it.next_node_) = m; + return iterator(m); + } + + void push_front(void_pointer m) + { + priv_get_ref(m) = this->it_.next_node_; + this->it_.next_node_ = m; + } + + void pop_front() + { ++it_; } + + void *front() const + { return containers_detail::get_pointer(it_.next_node_); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if (after_this != before_begin && after_this != before_end && before_begin != before_end) { + void_pointer next_b = priv_get_ref(before_begin.next_node_); + void_pointer next_e = priv_get_ref(before_end.next_node_); + void_pointer next_p = priv_get_ref(after_this.next_node_); + priv_get_ref(before_begin.next_node_) = next_e; + priv_get_ref(before_end.next_node_) = next_p; + priv_get_ref(after_this.next_node_) = next_b; + } + } + + void swap(basic_multiallocation_slist &other_chain) + { + std::swap(this->it_, other_chain.it_); + } + + static iterator iterator_to(void_pointer p) + { return iterator(p); } + + void_pointer extract_data() + { + void_pointer ret = empty() ? void_pointer(0) : void_pointer(&*it_); + it_ = iterator(); + return ret; + } +}; + +template +class basic_multiallocation_cached_slist +{ +private: + basic_multiallocation_slist slist_; + typename basic_multiallocation_slist::iterator last_; + + basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &); + basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist) + + typedef typename basic_multiallocation_slist::void_pointer void_pointer; + typedef typename basic_multiallocation_slist::iterator iterator; + + basic_multiallocation_cached_slist() + : slist_(), last_(slist_.before_begin()) + {} + /* + basic_multiallocation_cached_slist(iterator first_node) + : slist_(first_node), last_(slist_.before_begin()) + { + iterator end; + while(first_node != end){ + ++last_; + } + }*/ + + basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2) + : slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin()) + {} + + basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + : slist_(), last_(slist_.before_begin()) + { this->swap(other); } + + basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + { + basic_multiallocation_cached_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return slist_.empty(); } + + iterator before_begin() const + { return slist_.before_begin(); } + + iterator begin() const + { return slist_.begin(); } + + iterator end() const + { return slist_.end(); } + + iterator last() const + { return last_; } + + void clear() + { + slist_.clear(); + last_ = slist_.before_begin(); + } + + iterator insert_after(iterator it, void_pointer m) + { + slist_.insert_after(it, m); + if(it == last_){ + last_ = slist_.iterator_to(m); + } + return iterator_to(m); + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(last_, m); } + + void pop_front() + { + if(last_ == slist_.begin()){ + last_ = slist_.before_begin(); + } + slist_.pop_front(); + } + + void *front() const + { return slist_.front(); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if(before_begin == before_end) + return; + if(after_this == last_){ + last_ = before_end; + } + slist_.splice_after(after_this, before_begin, before_end); + } + + void swap(basic_multiallocation_cached_slist &x) + { + slist_.swap(x.slist_); + using std::swap; + swap(last_, x.last_); + if(last_ == x.before_begin()){ + last_ = this->before_begin(); + } + if(x.last_ == this->before_begin()){ + x.last_ = x.before_begin(); + } + } + + static iterator iterator_to(void_pointer p) + { return basic_multiallocation_slist::iterator_to(p); } + + std::pair extract_data() + { + if(this->empty()){ + return std::pair(void_pointer(0), void_pointer(0)); + } + else{ + void_pointer p1 = slist_.extract_data(); + void_pointer p2 = void_pointer(&*last_); + last_ = iterator(); + return std::pair(p1, p2); + } + } +}; + +template +class basic_multiallocation_cached_counted_slist +{ +private: + MultiallocatorCachedSlist cached_slist_; + std::size_t size_; + + basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &); + basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &); + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist) + + typedef typename MultiallocatorCachedSlist::void_pointer void_pointer; + typedef typename MultiallocatorCachedSlist::iterator iterator; + + basic_multiallocation_cached_counted_slist() + : cached_slist_(), size_(0) + {} + + basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n) + : cached_slist_(p1, p2), size_(n) + {} + + basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + : cached_slist_(), size_(0) + { this->swap(other); } + + basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + { + basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n) + : cached_slist_(boost::interprocess::move(mem)), size_(n) + {} + + bool empty() const + { return cached_slist_.empty(); } + + std::size_t size() const + { return size_; } + + iterator before_begin() const + { return cached_slist_.before_begin(); } + + iterator begin() const + { return cached_slist_.begin(); } + + iterator end() const + { return cached_slist_.end(); } + + iterator last() const + { return cached_slist_.last(); } + + void clear() + { + cached_slist_.clear(); + size_ = 0; + } + + iterator insert_after(iterator it, void_pointer m) + { + iterator ret = cached_slist_.insert_after(it, m); + ++size_; + return ret; + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void pop_front() + { + cached_slist_.pop_front(); + --size_; + } + + void *front() const + { return cached_slist_.front(); } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end) + { + std::size_t n = static_cast(std::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 extract_data() + { + size_ = 0; + return cached_slist_.extract_data(); + } +}; + +template +struct cast_functor +{ + typedef typename containers_detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + + +template +class transform_multiallocation_chain +{ +private: + + MultiallocationChain holder_; + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::pointer_to_other + ::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(containers_detail::get_pointer(p))); + } + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain) + + typedef transform_iterator + < typename MultiallocationChain::iterator + , containers_detail::cast_functor > iterator; + + transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n) + : holder_(p1, p2, n) + {} + + transform_multiallocation_chain() + : holder_() + {} + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + : holder_() + { this->swap(other); } + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other) + : holder_(boost::interprocess::move(other)) + {} + + transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + { + transform_multiallocation_chain tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + void push_front(pointer mem) + { holder_.push_front(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + /* + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); } + */ + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n) + { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } + + void pop_front() + { holder_.pop_front(); } + + pointer front() const + { return cast(holder_.front()); } + + bool empty() const + { return holder_.empty(); } + + iterator before_begin() const + { return iterator(holder_.before_begin()); } + + iterator begin() const + { return iterator(holder_.begin()); } + + iterator end() const + { return iterator(holder_.end()); } + + iterator last() const + { return iterator(holder_.last()); } + + std::size_t size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } + + iterator insert_after(iterator it, pointer m) + { return iterator(holder_.insert_after(it.base(), m)); } + + static iterator iterator_to(pointer p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { return holder_.extract_data(); } + + MultiallocationChain extract_multiallocation_chain() + { + return MultiallocationChain(boost::interprocess::move(holder_)); + } +}; + +}}} + +// namespace containers_detail { +// namespace interprocess_container { +// namespace boost { + +#include + +#endif //BOOST_CONTAINERS_DETAIL_MULTIALLOCATION_CHAIN_HPP diff --git a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp b/include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp similarity index 58% rename from include/boost/interprocess/containers/detail/node_alloc_holder.hpp rename to include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp index 6e88903..6a5160d 100644 --- a/include/boost/interprocess/containers/detail/node_alloc_holder.hpp +++ b/include/boost/interprocess/containers/container/detail/node_alloc_holder.hpp @@ -4,36 +4,137 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ -#define BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ +#ifndef BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ +#define BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +#include + namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { + +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_deallocator +{ + typedef typename Allocator::pointer pointer; + typedef containers_detail::integral_constant::value> alloc_version; + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + + private: + void priv_deallocate(allocator_v1) + { m_alloc.deallocate(m_ptr, 1); } + + void priv_deallocate(allocator_v2) + { m_alloc.deallocate_one(m_ptr); } + + scoped_deallocator(scoped_deallocator &); + scoped_deallocator& operator=(scoped_deallocator &); + + public: + + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_deallocator) + + pointer m_ptr; + Allocator& m_alloc; + + scoped_deallocator(pointer p, Allocator& a) + : m_ptr(p), m_alloc(a) + {} + + ~scoped_deallocator() + { if (m_ptr)priv_deallocate(alloc_version()); } + + scoped_deallocator(BOOST_INTERPROCESS_RV_REF(scoped_deallocator) o) + : m_ptr(o.m_ptr), m_alloc(o.m_alloc) + { o.release(); } + + pointer get() const + { return m_ptr; } + + void release() + { m_ptr = 0; } +}; + +template +class allocator_destroyer_and_chain_builder +{ + typedef typename A::value_type value_type; + typedef typename A::multiallocation_chain multiallocation_chain; + + A & a_; + multiallocation_chain &c_; + + public: + allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) + : a_(a), c_(c) + {} + + void operator()(const typename A::pointer &p) + { + value_type *vp = containers_detail::get_pointer(p); + vp->~value_type(); + c_.push_front(vp); + } +}; + +template +class 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 chain_builder; + + A & a_; + multiallocation_chain c_; + + public: + allocator_multialloc_chain_node_deallocator(A &a) + : a_(a), c_() + {} + + chain_builder get_chain_builder() + { return chain_builder(a_, c_); } + + ~allocator_multialloc_chain_node_deallocator() + { + if(!c_.empty()) + a_.deallocate_individual(boost::interprocess::move(c_)); + } +}; + template struct node_compare @@ -66,18 +167,25 @@ struct node_alloc_holder typedef typename A::template rebind::other NodeAlloc; typedef A ValAlloc; typedef typename NodeAlloc::pointer NodePtr; - typedef detail::scoped_deallocator Deallocator; + typedef containers_detail::scoped_deallocator Deallocator; typedef typename NodeAlloc::size_type size_type; typedef typename NodeAlloc::difference_type difference_type; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; typedef typename ICont::iterator icont_iterator; typedef typename ICont::const_iterator icont_citerator; typedef allocator_destroyer Destroyer; + private: + node_alloc_holder(node_alloc_holder&); + node_alloc_holder & operator=(node_alloc_holder&); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(node_alloc_holder) + node_alloc_holder(const ValAlloc &a) : members_(a) {} @@ -86,32 +194,19 @@ struct node_alloc_holder : members_(other.node_alloc()) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - node_alloc_holder(detail::moved_object other) - : members_(detail::move_impl(other.get().node_alloc())) - { this->swap(other.get()); } - #else - node_alloc_holder(node_alloc_holder &&other) - : members_(detail::move_impl(other.node_alloc())) + node_alloc_holder(BOOST_INTERPROCESS_RV_REF(node_alloc_holder) other) + : members_(boost::interprocess::move(other.node_alloc())) { this->swap(other); } - #endif template node_alloc_holder(const ValAlloc &a, const Pred &c) : members_(a, typename ICont::value_compare(c)) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - node_alloc_holder(detail::moved_object a, const Pred &c) - : members_(a.get(), typename ICont::value_compare(c)) - {} - #else - template - node_alloc_holder(ValAlloc &&a, const Pred &c) + node_alloc_holder(BOOST_INTERPROCESS_RV_REF(ValAlloc) a, const Pred &c) : members_(a, typename ICont::value_compare(c)) {} - #endif template node_alloc_holder(const node_alloc_holder &other, const Pred &c) @@ -142,46 +237,27 @@ struct node_alloc_holder void deallocate_one(NodePtr p, allocator_v2) { this->node_alloc().deallocate_one(p); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - static void construct(const NodePtr &ptr, detail::moved_object > 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(nodeptr))hook_type(); - //Now construct pair members_holder - value_type *valueptr = &nodeptr->get_data(); - new((void*)&valueptr->first) first_type(detail::move_impl(value.get().first)); - BOOST_TRY{ - new((void*)&valueptr->second) second_type(detail::move_impl(value.get().second)); - } - BOOST_CATCH(...){ - valueptr->first.~first_type(); - static_cast(nodeptr)->~hook_type(); - BOOST_RETHROW - } - BOOST_CATCH_END - } - #else - template - static void construct(const NodePtr &ptr, std::pair &&value) + static void construct(const NodePtr &ptr, + #ifdef BOOST_HAS_RVALUE_REFS + std::pair && + #else + boost::interprocess::rv > & + #endif + value) { typedef typename Node::hook_type hook_type; typedef typename Node::value_type::first_type first_type; typedef typename Node::value_type::second_type second_type; - Node *nodeptr = detail::get_pointer(ptr); + Node *nodeptr = containers_detail::get_pointer(ptr); //Hook constructor does not throw new(static_cast(nodeptr))hook_type(); //Now construct pair members_holder value_type *valueptr = &nodeptr->get_data(); - new((void*)&valueptr->first) first_type(detail::move_impl(value.first)); + new((void*)&valueptr->first) first_type(boost::interprocess::move(value.first)); BOOST_TRY{ - new((void*)&valueptr->second) second_type(detail::move_impl(value.second)); + new((void*)&valueptr->second) second_type(boost::interprocess::move(value.second)); } BOOST_CATCH(...){ valueptr->first.~first_type(); @@ -190,44 +266,35 @@ struct node_alloc_holder } BOOST_CATCH_END } - #endif static void destroy(const NodePtr &ptr) - { detail::get_pointer(ptr)->~Node(); } + { containers_detail::get_pointer(ptr)->~Node(); } - - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - Deallocator - #else - move_return - #endif - create_node_and_deallocator() + Deallocator create_node_and_deallocator() { - NodePtr p = this->allocate_one(); - Deallocator node_deallocator(p, this->node_alloc()); - return node_deallocator; + return Deallocator(this->allocate_one(), this->node_alloc()); } - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template static void construct(const NodePtr &ptr, Args &&...args) - { new((void*)detail::get_pointer(ptr)) Node(detail::forward_impl(args)...); } + { new((void*)containers_detail::get_pointer(ptr)) Node(boost::interprocess::forward(args)...); } template NodePtr create_node(Args &&...args) { NodePtr p = this->allocate_one(); Deallocator node_deallocator(p, this->node_alloc()); - self_t::construct(p, detail::forward_impl(args)...); + self_t::construct(p, boost::interprocess::forward(args)...); node_deallocator.release(); return (p); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING static void construct(const NodePtr &ptr) - { new((void*)detail::get_pointer(ptr)) Node(); } + { new((void*)containers_detail::get_pointer(ptr)) Node(); } NodePtr create_node() { @@ -240,37 +307,37 @@ struct node_alloc_holder #define BOOST_PP_LOCAL_MACRO(n) \ template \ - void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + void construct(const NodePtr &ptr, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - new((void*)detail::get_pointer(ptr)) \ - Node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + new((void*)containers_detail::get_pointer(ptr)) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() #define BOOST_PP_LOCAL_MACRO(n) \ template \ - NodePtr create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + NodePtr create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ NodePtr p = this->allocate_one(); \ Deallocator node_deallocator(p, this->node_alloc()); \ - self_t::construct(p, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ + self_t::construct(p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ node_deallocator.release(); \ return (p); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template 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); + ::boost::interprocess_container::construct_in_place(containers_detail::get_pointer(p), it); node_deallocator.release(); return (p); } @@ -287,7 +354,7 @@ struct node_alloc_holder NodeAlloc& other_alloc = x.node_alloc(); if (this_alloc != other_alloc){ - detail::do_swap(this_alloc, other_alloc); + containers_detail::do_swap(this_alloc, other_alloc); } this->icont().swap(x.icont()); @@ -298,19 +365,19 @@ struct node_alloc_holder (FwdIterator beg, difference_type n, Inserter inserter) { if(n){ - typedef typename NodeAlloc::multiallocation_iterator multiallocation_iterator; + typedef typename NodeAlloc::multiallocation_chain multiallocation_chain; //Try to allocate memory in a single block - multiallocation_iterator itbeg = - this->node_alloc().allocate_individual(n), itend, itold; + 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 = &*itbeg; - ++itbeg; + p = containers_detail::get_pointer(mem.front()); + mem.pop_front(); //This can throw - boost::interprocess::construct_in_place(p, beg); + constructed = 0; + boost::interprocess_container::construct_in_place(p, beg); ++constructed; //This can throw in some containers (predicate might throw) inserter(*p); @@ -320,7 +387,7 @@ struct node_alloc_holder if(constructed){ this->destroy(p); } - this->node_alloc().deallocate_many(itbeg); + this->node_alloc().deallocate_individual(boost::interprocess::move(mem)); BOOST_RETHROW } BOOST_CATCH_END @@ -334,8 +401,12 @@ struct node_alloc_holder void clear(allocator_v2) { - allocator_multialloc_chain_node_deallocator chain_holder(this->node_alloc()); - this->icont().clear_and_dispose(chain_holder.get_chain_builder()); + typename NodeAlloc::multiallocation_chain chain; + allocator_destroyer_and_chain_builder builder(this->node_alloc(), chain); + this->icont().clear_and_dispose(builder); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + if(!chain.empty()) + this->node_alloc().deallocate_individual(boost::interprocess::move(chain)); } icont_iterator erase_range(icont_iterator first, icont_iterator last, allocator_v1) @@ -419,10 +490,10 @@ struct node_alloc_holder { return static_cast(this->members_); } }; -} //namespace detail { -} //namespace interprocess { +} //namespace containers_detail { +} //namespace interprocess_container { } //namespace boost { -#include +#include -#endif // BOOST_INTERPROCESS_DETAIL_NODE_ALLOC_HPP_ +#endif // BOOST_CONTAINERS_DETAIL_NODE_ALLOC_HPP_ diff --git a/include/boost/interprocess/containers/container/detail/pair.hpp b/include/boost/interprocess/containers/container/detail/pair.hpp new file mode 100644 index 0000000..72f4ab0 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/pair.hpp @@ -0,0 +1,189 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP +#define BOOST_CONTAINERS_CONTAINERS_DETAIL_PAIR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include + +#include //std::pair + +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct pair +{ + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(pair) + + typedef T1 first_type; + typedef T2 second_type; + + T1 first; + T2 second; + + //std::pair compatibility + template + pair(const std::pair& p) + : first(p.first), second(p.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the previous constructor + pair(std::pair& x) + : first(x.first), second(x.second) + {} + + template + pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + pair() + : first(), second() + {} + + pair(const pair& x) + : first(x.first), second(x.second) + {} + + //To resolve ambiguity with the variadic constructor of 1 argument + //and the copy constructor + pair(pair& x) + : first(x.first), second(x.second) + {} + + pair(BOOST_INTERPROCESS_RV_REF(pair) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + template + pair(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(pair, D, S) p) + : first(boost::interprocess::move(p.first)), second(boost::interprocess::move(p.second)) + {} + + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + pair(U &&u, Args &&... args) + : first(boost::interprocess::forward(u)) + , second(boost::interprocess::forward(args)...) + {} + + #else + + template + pair( BOOST_CONTAINERS_PARAM(U, u) + #ifndef BOOST_HAS_RVALUE_REFS + , typename containers_detail::disable_if + < containers_detail::is_same > >::type* = 0 + #endif + ) + : first(boost::interprocess::forward(const_cast(u))) + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + pair(BOOST_CONTAINERS_PARAM(U, u) \ + ,BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : first(boost::interprocess::forward(const_cast(u))) \ + , second(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + #endif + + pair& operator=(BOOST_INTERPROCESS_RV_REF(pair) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, T1, T2) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + template + pair& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(std::pair, D, S) p) + { + first = boost::interprocess::move(p.first); + second = boost::interprocess::move(p.second); + return *this; + } + + void swap(pair& p) + { std::swap(*this, p); } +}; + +template +inline bool operator==(const pair& x, const pair& y) +{ return static_cast(x.first == y.first && x.second == y.second); } + +template +inline bool operator< (const pair& x, const pair& y) +{ return static_cast(x.first < y.first || + (!(y.first < x.first) && x.second < y.second)); } + +template +inline bool operator!=(const pair& x, const pair& y) +{ return static_cast(!(x == y)); } + +template +inline bool operator> (const pair& x, const pair& y) +{ return y < x; } + +template +inline bool operator>=(const pair& x, const pair& y) +{ return static_cast(!(x < y)); } + +template +inline bool operator<=(const pair& x, const pair& y) +{ return static_cast(!(y < x)); } + +template +inline pair make_pair(T1 x, T2 y) +{ return pair(x, y); } + +template +inline void swap(pair& x, pair& y) +{ + swap(x.first, y.first); + swap(x.second, y.second); +} + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_PAIR_HPP diff --git a/include/boost/interprocess/containers/container/detail/preprocessor.hpp b/include/boost/interprocess/containers/container/detail/preprocessor.hpp new file mode 100644 index 0000000..ecd143d --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/preprocessor.hpp @@ -0,0 +1,101 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP +#define BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif + +#include +#include +#include +#include +#include + +#define BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS 10 + +//Note: +//We define template parameters as const references to +//be able to bind temporaries. After that we will un-const them. +//This cast is ugly but it is necessary until "perfect forwarding" +//is achieved in C++0x. Meanwhile, if we want to be able to +//bind rvalues with non-const references, we have to be ugly +#ifdef BOOST_HAS_RVALUE_REFS + #define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ + //! +#else + #define BOOST_CONTAINERS_PP_PARAM_LIST(z, n, data) \ + const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ + //! +#endif + +#ifdef BOOST_HAS_RVALUE_REFS + #define BOOST_CONTAINERS_PARAM(U, u) \ + U && u \ + //! +#else + #define BOOST_CONTAINERS_PARAM(U, u) \ + const U & u \ + //! +#endif + +#ifdef BOOST_HAS_RVALUE_REFS +#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (BOOST_PP_CAT(p, n)) \ +//! +#else +#define BOOST_CONTAINERS_AUX_PARAM_INIT(z, n, data) \ + BOOST_PP_CAT(m_p, n) (const_cast(BOOST_PP_CAT(p, n))) \ +//! +#endif + +#define BOOST_CONTAINERS_AUX_PARAM_INC(z, n, data) \ + BOOST_PP_CAT(++m_p, n) \ +//! + +#ifdef BOOST_HAS_RVALUE_REFS +#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(m_p, n); \ +//! +#else +#define BOOST_CONTAINERS_AUX_PARAM_DEFINE(z, n, data) \ + BOOST_PP_CAT(P, n) & BOOST_PP_CAT(m_p, n); \ +//! +#endif + +#define BOOST_CONTAINERS_PP_PARAM_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! + +#define BOOST_CONTAINERS_PP_MEMBER_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! + +#define BOOST_CONTAINERS_PP_MEMBER_IT_FORWARD(z, n, data) \ +BOOST_PP_CAT(*m_p, n) \ +//! + +#include + +#else +#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING +#error "This file is not needed when perfect forwarding is available" +#endif +#endif //#ifndef BOOST_CONTAINERS_DETAIL_PREPROCESSOR_HPP diff --git a/include/boost/interprocess/containers/container/detail/transform_iterator.hpp b/include/boost/interprocess/containers/container/detail/transform_iterator.hpp new file mode 100644 index 0000000..8610dcc --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/transform_iterator.hpp @@ -0,0 +1,176 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost { +namespace interprocess_container { + +template +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 +struct operator_arrow_proxy +{ + 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 transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename containers_detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , 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 + operator->() const + { return operator_arrow_proxy(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 +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_TRANSFORM_ITERATORS_HPP diff --git a/include/boost/interprocess/containers/detail/tree.hpp b/include/boost/interprocess/containers/container/detail/tree.hpp similarity index 80% rename from include/boost/interprocess/containers/detail/tree.hpp rename to include/boost/interprocess/containers/container/detail/tree.hpp index 408ce3d..77e77eb 100644 --- a/include/boost/interprocess/containers/detail/tree.hpp +++ b/include/boost/interprocess/containers/container/detail/tree.hpp @@ -4,7 +4,7 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// // @@ -39,21 +39,25 @@ * purpose. It is provided "as is" without express or implied warranty. * */ -#ifndef BOOST_INTERPROCESS_TREE_HPP -#define BOOST_INTERPROCESS_TREE_HPP +#ifndef BOOST_CONTAINERS_TREE_HPP +#define BOOST_CONTAINERS_TREE_HPP -#include -#include +#include +#include #include -#include -#include +#include #include #include -#include #include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include + +#include +#include +#include +#include +#include +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include #endif #include //std::pair @@ -61,8 +65,8 @@ #include namespace boost { -namespace interprocess { -namespace detail { +namespace interprocess_container { +namespace containers_detail { template struct value_compare_impl @@ -91,10 +95,10 @@ struct value_compare_impl template struct rbtree_hook { - typedef typename bi::make_set_base_hook - < bi::void_pointer - , bi::link_mode - , bi::optimize_size + typedef typename containers_detail::bi::make_set_base_hook + < containers_detail::bi::void_pointer + , containers_detail::bi::link_mode + , containers_detail::bi::optimize_size >::type type; }; @@ -107,7 +111,7 @@ struct rbtree_type template struct rbtree_type< std::pair > { - typedef detail::pair type; + typedef pair type; }; template @@ -121,28 +125,32 @@ struct rbtree_node typedef rbtree_node node_type; - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING rbtree_node() : m_data() {} + rbtree_node(const rbtree_node &other) + : m_data(other.m_data) + {} + #define BOOST_PP_LOCAL_MACRO(n) \ template \ - rbtree_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : m_data(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)) \ + rbtree_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ {} \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #else //#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING template rbtree_node(Args &&...args) - : m_data(detail::forward_impl(args)...) + : m_data(boost::interprocess::forward(args)...) {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING rbtree_node &operator=(const rbtree_node &other) { do_assign(other.m_data); return *this; } @@ -170,7 +178,7 @@ struct rbtree_node } template - void do_assign(const detail::pair &p) + void do_assign(const pair &p) { const_cast(m_data.first) = p.first; m_data.second = p.second; @@ -182,64 +190,58 @@ struct rbtree_node public: template - - static void construct(node_type *ptr - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) - , const Convertible &value) - #else - , Convertible &&value) - #endif - { new(ptr) node_type(detail::forward_impl(value)); } + static void construct(node_type *ptr, BOOST_INTERPROCESS_FWD_REF(Convertible) convertible) + { new(ptr) node_type(boost::interprocess::forward(convertible)); } }; -}//namespace detail { -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) || !defined(BOOST_INTERPROCESS_RVALUE_PAIR) +}//namespace containers_detail { +#if !defined(BOOST_HAS_RVALUE_REFS) template struct has_own_construct_from_it - < boost::interprocess::detail::rbtree_node > + < boost::interprocess_container::containers_detail::rbtree_node > { static const bool value = true; }; #endif -namespace detail { +namespace containers_detail { template struct intrusive_rbtree_type { typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type void_pointer; - typedef typename detail::rbtree_node + typedef typename containers_detail::rbtree_node node_type; typedef node_compare node_compare_type; - typedef typename bi::make_rbtree + typedef typename containers_detail::bi::make_rbtree - ,bi::base_hook::type> - ,bi::constant_time_size - ,bi::size_type + ,containers_detail::bi::compare + ,containers_detail::bi::base_hook::type> + ,containers_detail::bi::constant_time_size + ,containers_detail::bi::size_type >::type container_type; typedef container_type type ; }; -} //namespace detail { +} //namespace containers_detail { -namespace detail { +namespace containers_detail { template class rbtree - : protected detail::node_alloc_holder - >::type > { - typedef typename detail::intrusive_rbtree_type + typedef typename containers_detail::intrusive_rbtree_type >::type Icont; - typedef detail::node_alloc_holder AllocHolder; + typedef containers_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; typedef rbtree < Key, Value, KeyOfValue , KeyCompare, A> ThisType; @@ -248,7 +250,7 @@ class rbtree typedef typename AllocHolder::Node Node; typedef typename Icont::iterator iiterator; typedef typename Icont::const_iterator iconst_iterator; - typedef detail::allocator_destroyer Destroyer; + typedef containers_detail::allocator_destroyer Destroyer; typedef typename AllocHolder::allocator_v1 allocator_v1; typedef typename AllocHolder::allocator_v2 allocator_v2; typedef typename AllocHolder::alloc_version alloc_version; @@ -293,6 +295,8 @@ class rbtree }; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(rbtree) + typedef Key key_type; typedef Value value_type; typedef A allocator_type; @@ -450,15 +454,9 @@ class rbtree (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree(detail::moved_object x) - : AllocHolder(x.get(), x.get().key_comp()) - { this->swap(x.get()); } - #else - rbtree(rbtree &&x) + rbtree(BOOST_INTERPROCESS_RV_REF(rbtree) x) : AllocHolder(x, x.key_comp()) { this->swap(x); } - #endif ~rbtree() {} //AllocHolder clears the tree @@ -488,13 +486,8 @@ class rbtree return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - rbtree& operator=(detail::moved_object mx) - { this->clear(); this->swap(mx.get()); return *this; } - #else - rbtree& operator=(rbtree &&mx) + rbtree& operator=(BOOST_INTERPROCESS_RV_REF(rbtree) mx) { this->clear(); this->swap(mx); return *this; } - #endif public: // accessors: @@ -583,14 +576,6 @@ class rbtree void swap(ThisType& x) { AllocHolder::swap(x); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object mt) - { this->swap(mt.get()); } - #else - void swap(rbtree &&mt) - { this->swap(mt); } - #endif - public: typedef typename Icont::insert_commit_data insert_commit_data; @@ -619,25 +604,14 @@ class rbtree return iterator(it); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template iterator insert_unique_commit - (detail::moved_object mv, insert_commit_data &data) + (BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv, insert_commit_data &data) { - NodePtr tmp = AllocHolder::create_node(mv); + NodePtr tmp = AllocHolder::create_node(boost::interprocess::forward(mv)); iiterator it(this->icont().insert_unique_commit(*tmp, data)); return iterator(it); } - #else - template - iterator insert_unique_commit - (MovableConvertible && mv, insert_commit_data &data) - { - NodePtr tmp = AllocHolder::create_node(detail::forward_impl(mv)); - iiterator it(this->icont().insert_unique_commit(*tmp, data)); - return iterator(it); - } - #endif std::pair insert_unique(const value_type& v) { @@ -650,21 +624,8 @@ class rbtree (this->insert_unique_commit(v, data), true); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - std::pair insert_unique(detail::moved_object mv) - { - insert_commit_data data; - std::pair ret = - this->insert_unique_check(KeyOfValue()(mv.get()), data); - if(!ret.second) - return ret; - return std::pair - (this->insert_unique_commit(mv, data), true); - } - #else - template - std::pair insert_unique(MovableConvertible &&mv) + std::pair insert_unique(BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { insert_commit_data data; std::pair ret = @@ -672,9 +633,8 @@ class rbtree if(!ret.second) return ret; return std::pair - (this->insert_unique_commit(detail::forward_impl(mv), data), true); + (this->insert_unique_commit(boost::interprocess::forward(mv), data), true); } - #endif private: iterator emplace_unique_impl(NodePtr p) @@ -705,31 +665,31 @@ class rbtree public: - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING template iterator emplace_unique(Args&&... args) - { return this->emplace_unique_impl(AllocHolder::create_node(detail::forward_impl(args)...)); } + { return this->emplace_unique_impl(AllocHolder::create_node(boost::interprocess::forward(args)...)); } template iterator emplace_hint_unique(const_iterator hint, Args&&... args) - { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(detail::forward_impl(args)...)); } + { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::interprocess::forward(args)...)); } template iterator emplace_equal(Args&&... args) { - NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(args)...)); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } template iterator emplace_hint_equal(const_iterator hint, Args&&... args) { - NodePtr p(AllocHolder::create_node(detail::forward_impl(args)...)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(args)...)); return iterator(this->icont().insert_equal(hint.get(), *p)); } - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator emplace_unique() { return this->emplace_unique_impl(AllocHolder::create_node()); } @@ -751,37 +711,37 @@ class rbtree #define BOOST_PP_LOCAL_MACRO(n) \ template \ - iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ return this->emplace_unique_impl \ - (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + (AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ } \ \ template \ - iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_hint_unique(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ return this->emplace_unique_hint_impl \ - (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + (hint, AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ } \ \ template \ - iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ return iterator(this->icont().insert_equal(this->icont().end(), *p)); \ } \ \ template \ - iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ + iterator emplace_hint_equal(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ { \ - NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ + NodePtr p(AllocHolder::create_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ return iterator(this->icont().insert_equal(hint.get(), *p)); \ } \ //! - #define BOOST_PP_LOCAL_LIMITS (1, BOOST_INTERPROCESS_MAX_CONSTRUCTOR_PARAMETERS) + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() - #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING iterator insert_unique(const_iterator hint, const value_type& v) { @@ -793,30 +753,16 @@ class rbtree return this->insert_unique_commit(v, data); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_unique(const_iterator hint, detail::moved_object mv) - { - insert_commit_data data; - std::pair 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 - iterator insert_unique - (const_iterator hint, MovableConvertible &&mv) + iterator insert_unique(const_iterator hint, BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { insert_commit_data data; std::pair ret = this->insert_unique_check(hint, KeyOfValue()(mv), data); if(!ret.second) return ret.first; - return this->insert_unique_commit(detail::forward_impl(mv), data); + return this->insert_unique_commit(boost::interprocess::forward(mv), data); } - #endif template void insert_unique(InputIterator first, InputIterator last) @@ -840,21 +786,12 @@ class rbtree return iterator(this->icont().insert_equal(this->icont().end(), *p)); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(detail::moved_object mv) + iterator insert_equal(BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(mv)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(mv))); return iterator(this->icont().insert_equal(this->icont().end(), *p)); } - #else - template - iterator insert_equal(MovableConvertible &&mv) - { - NodePtr p(AllocHolder::create_node(detail::forward_impl(mv))); - return iterator(this->icont().insert_equal(this->icont().end(), *p)); - } - #endif iterator insert_equal(const_iterator hint, const value_type& v) { @@ -862,21 +799,12 @@ class rbtree return iterator(this->icont().insert_equal(hint.get(), *p)); } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE template - iterator insert_equal(const_iterator hint, detail::moved_object mv) + iterator insert_equal(const_iterator hint, BOOST_INTERPROCESS_FWD_REF(MovableConvertible) mv) { - NodePtr p(AllocHolder::create_node(mv)); + NodePtr p(AllocHolder::create_node(boost::interprocess::forward(mv))); return iterator(this->icont().insert_equal(hint.get(), *p)); } - #else - template - iterator insert_equal(const_iterator hint, MovableConvertible &&mv) - { - NodePtr p(AllocHolder::create_node(detail::move_impl(mv))); - return iterator(this->icont().insert_equal(hint.get(), *p)); - } - #endif template void insert_equal(InputIterator first, InputIterator last) @@ -1066,46 +994,25 @@ swap(rbtree& x, x.swap(y); } -} //namespace detail { +} //namespace containers_detail { +} //namespace interprocess_container { -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -/* -template -struct is_movable > -{ - enum { value = true }; -}; -*/ +namespace interprocess { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class C, class A> +struct has_trivial_destructor_after_move + > { - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; }; +} //namespace interprocess { -} //namespace interprocess { } //namespace boost { -#include +#include -#endif //BOOST_INTERPROCESS_TREE_HPP +#endif //BOOST_CONTAINERS_TREE_HPP diff --git a/include/boost/interprocess/containers/container/detail/type_traits.hpp b/include/boost/interprocess/containers/container/detail/type_traits.hpp new file mode 100644 index 0000000..cb103d9 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/type_traits.hpp @@ -0,0 +1,166 @@ +////////////////////////////////////////////////////////////////////////////// +// (C) Copyright John Maddock 2000. +// (C) Copyright Ion Gaztanaga 2005-2008. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +// The alignment_of implementation comes from John Maddock's boost::alignment_of code +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP +#define BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +struct nat{}; + +//boost::alignment_of yields to 10K lines of preprocessed code, so we +//need an alternative +template struct alignment_of; + +template +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template +struct alignment_logic +{ + enum{ value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum{ value = alignment_logic + < sizeof(alignment_of_hack) - 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 +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct is_reference +{ + enum { value = false }; +}; + +template +struct is_reference +{ + enum { value = true }; +}; + +template +struct is_pointer +{ + enum { value = false }; +}; + +template +struct is_pointer +{ + enum { value = true }; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template +struct add_reference +{ + typedef T& type; +}; + +template<> +struct add_reference +{ + typedef nat &type; +}; + +template<> +struct add_reference +{ + typedef const nat &type; +}; + +template +struct add_const_reference +{ typedef const T &type; }; + +template +struct add_const_reference +{ typedef T& type; }; + +template +struct is_same +{ + typedef char yes_type; + struct no_type + { + char padding[8]; + }; + + template + static yes_type is_same_tester(V*, V*); + static no_type is_same_tester(...); + + static T *t; + static U *u; + + static const bool value = sizeof(yes_type) == sizeof(is_same_tester(t,u)); +}; + +} // namespace containers_detail +} //namespace interprocess_container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINERS_CONTAINER_DETAIL_TYPE_TRAITS_HPP + +#include + diff --git a/include/boost/interprocess/containers/container/detail/utilities.hpp b/include/boost/interprocess/containers/container/detail/utilities.hpp new file mode 100644 index 0000000..5dad0dc --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/utilities.hpp @@ -0,0 +1,95 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP +#define BOOST_CONTAINERS_DETAIL_UTILITIES_HPP + +#include +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +SizeType + get_next_capacity(const SizeType max_size + ,const SizeType capacity + ,const SizeType n) +{ +// if (n > max_size - capacity) +// throw std::length_error("get_next_capacity"); + + const SizeType m3 = max_size/3; + + if (capacity < m3) + return capacity + max_value(3*(capacity+1)/5, n); + + if (capacity < m3*2) + return capacity + max_value((capacity+1)/2, n); + + return max_size; +} + +template +const T &max_value(const T &a, const T &b) +{ return a > b ? a : b; } + +template +const T &min_value(const T &a, const T &b) +{ return a < b ? a : b; } + +template +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 +struct smart_ptr_type +{ + 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 +inline typename smart_ptr_type::pointer +get_pointer(const Ptr &ptr) +{ return smart_ptr_type::get(ptr); } + +//!To avoid ADL problems with swap +template +inline void do_swap(T& x, T& y) +{ + using std::swap; + swap(x, y); +} + +template +struct ct_rounded_size +{ + enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_UTILITIES_HPP diff --git a/include/boost/interprocess/containers/container/detail/value_init.hpp b/include/boost/interprocess/containers/container/detail/value_init.hpp new file mode 100644 index 0000000..4918379 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/value_init.hpp @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2009. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP +#define BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +struct value_init +{ + value_init() + : m_t() + {} + + T m_t; +}; + +} //namespace containers_detail { +} //namespace interprocess_container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_VALUE_INIT_HPP diff --git a/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp b/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp new file mode 100644 index 0000000..ba46e85 --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/variadic_templates_tools.hpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP +#define BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include //std::size_t + +namespace boost { +namespace interprocess_container { +namespace containers_detail { + +template +class tuple; + +template<> class tuple<> +{}; + +template +class tuple + : private tuple +{ + typedef tuple inherited; + + public: + tuple() { } + + // implicit copy-constructor is okay + // Construct tuple from separate arguments. + tuple(typename add_const_reference::type v, + typename add_const_reference::type... vtail) + : inherited(vtail...), m_head(v) + {} + + // Construct tuple from another tuple. + template + tuple(const tuple& other) + : m_head(other.head()), inherited(other.tail()) + {} + + template + tuple& operator=(const tuple& other) + { + m_head = other.head(); + tail() = other.tail(); + return this; + } + + typename add_reference::type head() { return m_head; } + typename add_reference::type head() const { return m_head; } + + inherited& tail() { return *this; } + const inherited& tail() const { return *this; } + + protected: + Head m_head; +}; + + +template +tuple tie_forward(Values&&... values) +{ return tuple(values...); } + +template +struct tuple_element; + +template +struct tuple_element > +{ + typedef typename tuple_element >::type type; +}; + +template +struct tuple_element<0, tuple > +{ + typedef Head type; +}; + +template +class get_impl; + +template +class get_impl > +{ + typedef typename tuple_element >::type Element; + typedef get_impl > Next; + + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return Next::get(t.tail()); } + static const_type get(const tuple& t) { return Next::get(t.tail()); } +}; + +template +class get_impl<0, tuple > +{ + public: + typedef typename add_reference::type type; + typedef typename add_const_reference::type const_type; + static type get(tuple& t) { return t.head(); } + static const_type get(const tuple& t){ return t.head(); } +}; + +template +typename get_impl >::type get(tuple& t) +{ return get_impl >::get(t); } + +template +typename get_impl >::const_type get(const tuple& t) +{ return get_impl >::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 +struct index_tuple{}; + +template > +struct build_number_seq; + +template +struct build_number_seq > + : build_number_seq > +{}; + +template +struct build_number_seq<0, index_tuple > +{ typedef index_tuple type; }; + + +}}} //namespace boost { namespace interprocess_container { namespace containers_detail { + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP diff --git a/include/boost/interprocess/detail/version_type.hpp b/include/boost/interprocess/containers/container/detail/version_type.hpp similarity index 66% rename from include/boost/interprocess/detail/version_type.hpp rename to include/boost/interprocess/containers/container/detail/version_type.hpp index ed43623..f7075dd 100644 --- a/include/boost/interprocess/detail/version_type.hpp +++ b/include/boost/interprocess/containers/container/detail/version_type.hpp @@ -4,7 +4,7 @@ // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// // @@ -13,22 +13,22 @@ ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP -#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP +#ifndef BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP +#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP -#include -#include +#include +#include namespace boost{ -namespace interprocess{ -namespace detail{ +namespace interprocess_container { +namespace containers_detail { //using namespace boost; template struct version_type - : public detail::integral_constant + : public containers_detail::integral_constant { typedef T type; @@ -38,7 +38,7 @@ struct version_type namespace impl{ template , typename T::version>::value> + bool = containers_detail::is_convertible, typename T::version>::value> struct extract_version { static const unsigned value = 1; @@ -78,12 +78,12 @@ struct version template struct version - : public detail::integral_constant::value> + : public containers_detail::integral_constant::value> { }; -} //namespace detail{ -} //namespace interprocess{ +} //namespace containers_detail { +} //namespace interprocess_container { } //namespace boost{ -#endif //#define BOOST_INTERPROCESS_DETAIL_VERSION_TYPE_HPP +#endif //#define BOOST_CONTAINERS_DETAIL_VERSION_TYPE_HPP diff --git a/include/boost/interprocess/containers/container/detail/workaround.hpp b/include/boost/interprocess/containers/container/detail/workaround.hpp new file mode 100644 index 0000000..60abf6c --- /dev/null +++ b/include/boost/interprocess/containers/container/detail/workaround.hpp @@ -0,0 +1,24 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP +#define BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP + +#include + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) +#define BOOST_CONTAINERS_PERFECT_FORWARDING + +#endif + +#include + +#endif //#ifndef BOOST_CONTAINERS_DETAIL_WORKAROUND_HPP diff --git a/include/boost/interprocess/containers/container/flat_map.hpp b/include/boost/interprocess/containers/container/flat_map.hpp new file mode 100644 index 0000000..b3b9b79 --- /dev/null +++ b/include/boost/interprocess/containers/container/flat_map.hpp @@ -0,0 +1,1390 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_FLAT_MAP_HPP +#define BOOST_CONTAINERS_FLAT_MAP_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +class flat_map; + +template +inline bool operator==(const flat_map& x, + const flat_map& y); + +template +inline bool operator<(const flat_map& x, + const flat_map& y); +/// @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 the key_type is Key and the value_type is std::pair +//! (unlike std::map which value_type is std::pair<const Key, T>). +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair >). +//! +//! 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 flat_map +{ + /// @cond + private: + //This is the tree that we should store if pair was movable + typedef containers_detail::flat_tree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + + //This is the real tree stored here. It's based on a movable pair + typedef containers_detail::flat_tree, + containers_detail::select1st >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + 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; + + template + static D &force(const S &s) + { return *const_cast(reinterpret_cast(&s)); } + + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } + + /// @endcond + + public: + BOOST_INTERPROCESS_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; + + //! Effects: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! Complexity: Constant. + explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) {} + + //! Effects: Constructs an empty flat_map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) + { m_flat_tree.insert_unique(first, last); } + + //! Effects: Copy constructs a flat_map. + //! + //! Complexity: Linear in x.size(). + flat_map(const flat_map& x) + : m_flat_tree(x.m_flat_tree) {} + + //! Effects: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_map(BOOST_INTERPROCESS_RV_REF(flat_map) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_map& operator=(const flat_map& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: Move constructs a flat_map. + //! Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_map& operator=(BOOST_INTERPROCESS_RV_REF(flat_map) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return force(m_flat_tree.key_comp()); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(force(m_flat_tree.key_comp())); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return force(m_flat_tree.get_allocator()); } + + const stored_allocator_type &get_stored_allocator() const + { return force(m_flat_tree.get_stored_allocator()); } + + stored_allocator_type &get_stored_allocator() + { return force(m_flat_tree.get_stored_allocator()); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return force_copy(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return force(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return force(m_flat_tree.cbegin()); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return force_copy(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return force(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return force(m_flat_tree.cend()); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return force(m_flat_tree.crbegin()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return force(m_flat_tree.crend()); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: 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. + T &operator[](BOOST_INTERPROCESS_RV_REF(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::interprocess::move(k), boost::interprocess::move(T()))); + 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. + 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; + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_map& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(const value_type& x) + { return force >( + m_flat_tree.insert_unique(force(x))); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force >( + m_flat_tree.insert_unique(boost::interprocess::move(force(x)))); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force > + (m_flat_tree.insert_unique(boost::interprocess::move(x))); + } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return force_copy( + m_flat_tree.insert_unique(force(position), force(x))); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force_copy( + m_flat_tree.insert_unique(force(position), boost::interprocess::move(force(x)))); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force_copy( + m_flat_tree.insert_unique(force(position), boost::interprocess::move(x))); + } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: 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. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_unique(boost::interprocess::forward(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), boost::interprocess::forward(args)...)); } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_unique()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_unique \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_unique \ + (force(hint), \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return force_copy(m_flat_tree.erase(force(position))); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: 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); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return force_copy(m_flat_tree.erase(force(first), force(last))); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return force_copy(m_flat_tree.find(x)); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return force(m_flat_tree.find(x)); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return force_copy(m_flat_tree.lower_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return force(m_flat_tree.lower_bound(x)); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return force_copy(m_flat_tree.upper_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return force(m_flat_tree.upper_bound(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return force >(m_flat_tree.equal_range(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return force >(m_flat_tree.equal_range(x)); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: 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. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: 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 + friend bool operator== (const flat_map&, + const flat_map&); + template + friend bool operator< (const flat_map&, + const flat_map&); + /// @endcond +}; + +template +inline bool operator==(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_map& x, + const flat_map& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_map& x, + const flat_map& y) + { return !(x == y); } + +template +inline bool operator>(const flat_map& x, + const flat_map& y) + { return y < x; } + +template +inline bool operator<=(const flat_map& x, + const flat_map& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_map& x, + const flat_map& y) + { return !(x < y); } + +template +inline void swap(flat_map& x, + flat_map& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. +template +class flat_multimap; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y); + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y); +/// @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 the key_type is Key and the value_type is std::pair +//! (unlike std::multimap which value_type is std::pair<const Key, T>). +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair >). +template +class flat_multimap +{ + /// @cond + private: + typedef containers_detail::flat_tree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + //This is the real tree stored here. It's based on a movable pair + typedef containers_detail::flat_tree, + containers_detail::select1st >, + Pred, + typename Alloc::template + rebind >::other> impl_tree_t; + 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; + + template + static D &force(const S &s) + { return *const_cast((reinterpret_cast(&s))); } + + template + static D force_copy(S s) + { + value_type *vp = reinterpret_cast(&*s); + return D(vp); + } + /// @endcond + + public: + BOOST_INTERPROCESS_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; + + //! Effects: Constructs an empty flat_multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit flat_multimap(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) { } + + //! Effects: Constructs an empty flat_multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_multimap(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, force(a)) + { m_flat_tree.insert_equal(first, last); } + + //! Effects: Copy constructs a flat_multimap. + //! + //! Complexity: Linear in x.size(). + flat_multimap(const flat_multimap& x) + : m_flat_tree(x.m_flat_tree) { } + + //! Effects: Move constructs a flat_multimap. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_multimap(BOOST_INTERPROCESS_RV_REF(flat_multimap) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + { } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_multimap& operator=(const flat_multimap& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + flat_multimap& operator=(BOOST_INTERPROCESS_RV_REF(flat_multimap) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return force(m_flat_tree.key_comp()); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(force(m_flat_tree.key_comp())); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return force(m_flat_tree.get_allocator()); } + + const stored_allocator_type &get_stored_allocator() const + { return force(m_flat_tree.get_stored_allocator()); } + + stored_allocator_type &get_stored_allocator() + { return force(m_flat_tree.get_stored_allocator()); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return force_copy(m_flat_tree.begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return force(m_flat_tree.begin()); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return force_copy(m_flat_tree.end()); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return force(m_flat_tree.end()); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return force(m_flat_tree.rbegin()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return force(m_flat_tree.rend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return force(m_flat_tree.rend()); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_multimap& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(x))); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return force_copy(m_flat_tree.insert_equal(boost::interprocess::move(x))); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { return force_copy(m_flat_tree.insert_equal(boost::interprocess::move(x))); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, const value_type& x) + { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { + return force_copy + (m_flat_tree.insert_equal(force(position) + , boost::interprocess::move(x))); + } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(impl_value_type) x) + { + return force_copy( + m_flat_tree.insert_equal(force(position), boost::interprocess::move(x))); + } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return force_copy(m_flat_tree.emplace_equal(boost::interprocess::forward(args)...)); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { + return force_copy(m_flat_tree.emplace_hint_equal + (force(hint), boost::interprocess::forward(args)...)); + } + + #else //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator emplace() + { return force_copy(m_flat_tree.emplace_equal()); } + + iterator emplace_hint(const_iterator hint) + { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_equal \ + (BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return force_copy(m_flat_tree.emplace_hint_equal \ + (force(hint), \ + BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _))); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return force_copy(m_flat_tree.erase(force(position))); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: 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); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: Logarithmic search time plus erasure time + //! linear to the elements with bigger keys. + iterator erase(const_iterator first, const_iterator last) + { return force_copy(m_flat_tree.erase(force(first), force(last))); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return force_copy(m_flat_tree.find(x)); } + + //! Returns: An const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return force(m_flat_tree.find(x)); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return force_copy(m_flat_tree.lower_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key + //! not less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return force(m_flat_tree.lower_bound(x)); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + {return force_copy(m_flat_tree.upper_bound(x)); } + + //! Returns: A const iterator pointing to the first element with key + //! not less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return force(m_flat_tree.upper_bound(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return force_copy >(m_flat_tree.equal_range(x)); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return force_copy >(m_flat_tree.equal_range(x)); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: 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. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: 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 + friend bool operator== (const flat_multimap& x, + const flat_multimap& y); + + template + friend bool operator< (const flat_multimap& x, + const flat_multimap& y); + /// @endcond +}; + +template +inline bool operator==(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multimap& x, + const flat_multimap& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multimap& x, + const flat_multimap& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multimap& x, + const flat_multimap& y) + { return y < x; } + +template +inline bool operator<=(const flat_multimap& x, + const flat_multimap& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multimap& x, + const flat_multimap& y) + { return !(x < y); } + +template +inline void swap(flat_multimap& x, flat_multimap& y) + { x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move< boost::interprocess_container::flat_multimap > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { +} //namespace boost { + +/// @endcond + +#include + +#endif /* BOOST_CONTAINERS_FLAT_MAP_HPP */ diff --git a/include/boost/interprocess/containers/container/flat_set.hpp b/include/boost/interprocess/containers/container/flat_set.hpp new file mode 100644 index 0000000..2c00cb7 --- /dev/null +++ b/include/boost/interprocess/containers/container/flat_set.hpp @@ -0,0 +1,1172 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINERS_FLAT_SET_HPP +#define BOOST_CONTAINERS_FLAT_SET_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators < and ==, needed for friend declaration. + +template +class flat_set; + +template +inline bool operator==(const flat_set& x, + const flat_set& y); + +template +inline bool operator<(const flat_set& x, + const flat_set& y); +/// @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 flat_set +{ + /// @cond + private: + typedef containers_detail::flat_tree, Pred, Alloc> tree_t; + tree_t m_flat_tree; // flat tree representing flat_set + /// @endcond + + public: + BOOST_INTERPROCESS_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; + + //! Effects: Constructs an empty flat_map using the specified + //! comparison object and allocator. + //! + //! Complexity: Constant. + explicit flat_set(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + {} + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + flat_set(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + { m_flat_tree.insert_unique(first, last); } + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + flat_set(const flat_set& x) + : m_flat_tree(x.m_flat_tree) {} + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + flat_set(BOOST_INTERPROCESS_RV_REF(flat_set) mx) + : m_flat_tree(boost::interprocess::move(mx.m_flat_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_set& operator=(const flat_set& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + flat_set& operator=(BOOST_INTERPROCESS_RV_REF(flat_set) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: 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(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_set& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(const value_type& x) + { return m_flat_tree.insert_unique(x); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: 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); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: 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. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_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 \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return m_flat_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: 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); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: 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); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_flat_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return m_flat_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_flat_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_flat_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_flat_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_flat_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: 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. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: 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 + friend bool operator== (const flat_set&, const flat_set&); + + template + friend bool operator< (const flat_set&, const flat_set&); + /// @endcond +}; + +template +inline bool operator==(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_set& x, + const flat_set& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_set& x, + const flat_set& y) + { return !(x == y); } + +template +inline bool operator>(const flat_set& x, + const flat_set& y) + { return y < x; } + +template +inline bool operator<=(const flat_set& x, + const flat_set& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_set& x, + const flat_set& y) + { return !(x < y); } + +template +inline void swap(flat_set& x, flat_set& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value &&has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +class flat_multiset; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y); + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y); +/// @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 flat_multiset +{ + /// @cond + private: + typedef containers_detail::flat_tree, Pred, Alloc> tree_t; + tree_t m_flat_tree; // flat tree representing flat_multiset + /// @endcond + + public: + BOOST_INTERPROCESS_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 + flat_multiset(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_flat_tree(comp, a) + { m_flat_tree.insert_equal(first, last); } + + flat_multiset(const flat_multiset& x) + : m_flat_tree(x.m_flat_tree) {} + + flat_multiset(BOOST_INTERPROCESS_RV_REF(flat_multiset) x) + : m_flat_tree(boost::interprocess::move(x.m_flat_tree)) + {} + + flat_multiset& operator=(const flat_multiset& x) + { m_flat_tree = x.m_flat_tree; return *this; } + + flat_multiset& operator=(BOOST_INTERPROCESS_RV_REF(flat_multiset) mx) + { m_flat_tree = boost::interprocess::move(mx.m_flat_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_flat_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: 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(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_flat_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_flat_tree.cbegin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_flat_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_flat_tree.cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_flat_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_flat_tree.crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_flat_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_flat_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_flat_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_flat_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_flat_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(flat_multiset& x) + { m_flat_tree.swap(x.m_flat_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const value_type& x) + { return m_flat_tree.insert_equal(x); } + + //! Effects: Inserts a new value_type move constructed from x + //! and returns the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: 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); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_flat_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + //! search time plus N*size() insertion time. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + void insert(InputIterator first, InputIterator last) + { m_flat_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic search time plus linear insertion + //! to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace(Args&&... args) + { return m_flat_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic search time (constant if x is inserted + //! right before p) plus insertion linear to the elements with bigger keys than x. + //! + //! Note: If an element it's inserted it might invalidate elements. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_flat_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_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 \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_flat_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Linear to the elements with keys bigger than position + //! + //! Note: Invalidates elements with keys + //! not less than the erased element. + iterator erase(const_iterator position) + { return m_flat_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: 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); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: size()*N where N is the distance from first to last. + //! + //! Complexity: 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); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_flat_tree.clear(); } + + //! Effects: Tries to deallocate the excess of memory created + // with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to size(). + void shrink_to_fit() + { m_flat_tree.shrink_to_fit(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_flat_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic.s + const_iterator find(const key_type& x) const + { return m_flat_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_flat_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_flat_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_flat_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_flat_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_flat_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_flat_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_flat_tree.equal_range(x); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return m_flat_tree.capacity(); } + + //! Effects: 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. + //! + //! Throws: If memory allocation allocation throws or T's copy constructor throws. + //! + //! Note: 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 + friend bool operator== (const flat_multiset&, + const flat_multiset&); + template + friend bool operator< (const flat_multiset&, + const flat_multiset&); + /// @endcond +}; + +template +inline bool operator==(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree == y.m_flat_tree; } + +template +inline bool operator<(const flat_multiset& x, + const flat_multiset& y) + { return x.m_flat_tree < y.m_flat_tree; } + +template +inline bool operator!=(const flat_multiset& x, + const flat_multiset& y) + { return !(x == y); } + +template +inline bool operator>(const flat_multiset& x, + const flat_multiset& y) + { return y < x; } + +template +inline bool operator<=(const flat_multiset& x, + const flat_multiset& y) + { return !(y < x); } + +template +inline bool operator>=(const flat_multiset& x, + const flat_multiset& y) +{ return !(x < y); } + +template +inline void swap(flat_multiset& x, flat_multiset& y) + { x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_FLAT_SET_HPP */ diff --git a/include/boost/interprocess/containers/container/list.hpp b/include/boost/interprocess/containers/container/list.hpp new file mode 100644 index 0000000..e7d0f89 --- /dev/null +++ b/include/boost/interprocess/containers/container/list.hpp @@ -0,0 +1,1372 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This 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_CONTAINERS_LIST_HPP_ +#define BOOST_CONTAINERS_LIST_HPP_ + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +namespace containers_detail { + +template +struct list_hook +{ + typedef typename containers_detail::bi::make_list_base_hook + , containers_detail::bi::link_mode >::type type; +}; + +template +struct list_node + : public list_hook::type +{ + + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + list_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + list_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + list_node(Args &&...args) + : m_data(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + T m_data; +}; + +template +struct intrusive_list_type +{ + typedef typename A::value_type value_type; + typedef typename boost::pointer_to_other + ::type void_pointer; + typedef typename containers_detail::list_node + node_type; + typedef typename containers_detail::bi::make_list + < node_type + , containers_detail::bi::base_hook::type> + , containers_detail::bi::constant_time_size + , containers_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace containers_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::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 list + : protected containers_detail::node_alloc_holder + ::type> +{ + /// @cond + typedef typename + containers_detail::intrusive_list_type::type Icont; + typedef list ThisType; + typedef containers_detail::node_alloc_holder AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef containers_detail::allocator_destroyer 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 + struct ValueCompareToNodeCompare + : Pred + { + ValueCompareToNodeCompare(Pred pred) + : Pred(pred) + {} + + bool operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.m_data, b.m_data); } + + bool operator()(const Node &a) const + { return static_cast(*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_INTERPROCESS_ENABLE_MOVE_EMULATION(list) + + //! Const iterator used to iterate through a list. + class const_iterator + /// @cond + : public std::iterator + { + + 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; + 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; + 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 reverse_iterator; + //! Const iterator used to iterate backwards through a list. + typedef std::reverse_iterator const_reverse_iterator; + + //! Effects: Constructs a list taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit list(const allocator_type &a = A()) + : AllocHolder(a) + {} + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + list(size_type n) + : AllocHolder(A()) + { this->resize(n); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + list(size_type n, const T& value, const A& a = A()) + : AllocHolder(a) + { this->insert(this->cbegin(), n, value); } + + //! Effects: Copy constructs a list. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + list(const list& x) + : AllocHolder(x) + { this->insert(this->cbegin(), x.begin(), x.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + list(BOOST_INTERPROCESS_RV_REF(list) x) + : AllocHolder(boost::interprocess::move((AllocHolder&)x)) + {} + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the list. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + list(InpIt first, InpIt last, const A &a = A()) + : AllocHolder(a) + { this->insert(this->cbegin(), first, last); } + + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~list() + {} //AllocHolder clears the list + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: 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(); } + + //! Effects: Erases all the elements of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the list. + void clear() + { AllocHolder::clear(alloc_version()); } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->icont().begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->icont().end()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return const_reverse_iterator(this->cend()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->cbegin()); } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->size(); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->icont().size(); } + + //! Effects: Returns the largest possible size of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return AllocHolder::max_size(); } + + //! Effects: Inserts a copy of t in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const T& x) + { this->insert(this->cbegin(), x); } + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of t to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(BOOST_INTERPROCESS_RV_REF(T) x) + { this->insert(this->cbegin(), boost::interprocess::move(x)); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void push_back (const T& x) + { this->insert(this->cend(), x); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void push_back (BOOST_INTERPROCESS_RV_REF(T) x) + { this->insert(this->cend(), boost::interprocess::move(x)); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->erase(this->cbegin()); } + + //! Effects: Removes the last element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_back() + { const_iterator tmp = this->cend(); this->erase(--tmp); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return *(--this->end()); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return *(--this->end()); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + } + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(ThisType& x) + { AllocHolder::swap(x); } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + ThisType& operator=(const ThisType& x) + { + if (this != &x) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + ThisType& operator=(BOOST_INTERPROCESS_RV_REF(ThisType) mx) + { + this->clear(); + this->swap(mx); + return *this; + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void insert(const_iterator p, size_type n, const T& x) + { this->priv_create_and_insert_nodes(p, n, x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + void insert(const_iterator p, InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: 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)); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(T) x) + { + NodePtr tmp = AllocHolder::create_node(boost::interprocess::move(x)); + return iterator(this->icont().insert(p.get(), *tmp)); + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_back(Args&&... args) + { + this->emplace(this->cend(), boost::interprocess::forward(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + void emplace_front(Args&&... args) + { + this->emplace(this->cbegin(), boost::interprocess::forward(args)...); + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace(const_iterator p, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(boost::interprocess::forward(args)...); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert(p.get(), *node)); + } + + #else //#ifdef BOOST_CONTAINERS_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*)containers_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 \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + this->emplace(this->cend(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { this->emplace(this->cbegin(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));} \ + \ + template \ + iterator emplace(const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ + new ((void*)containers_detail::get_pointer(d.get())) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + NodePtr node = d.get(); \ + d.release(); \ + return iterator(this->icont().insert(p.get(), *node)); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + iterator erase(const_iterator p) + { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: 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())); } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: 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. + void splice(iterator p, ThisType& x) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().splice(p.get(), x.icont()); + } + else{ + throw std::runtime_error("list::splice called with unequal allocators"); + } + } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: 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. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: 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. + void splice(const_iterator p, ThisType &x, const_iterator i) + { + 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"); + } + } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: 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. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of elements transferred. + //! + //! Note: 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. + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last) + { + 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"); + } + } + + //! Requires: 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) + //! + //! Effects: 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. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: 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. + void splice(const_iterator p, ThisType &x, const_iterator first, const_iterator last, size_type n) + { + 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"); + } + } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + + //! Effects: Removes all the elements that compare equal to value. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: 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)); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! Note: 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()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(BinaryPredicate binary_pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc())); + } + + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. 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. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(list& x) + { this->merge(x, value_less()); } + + //! Requires: 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. + //! + //! Effects: 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. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(list &x, StrictWeakOrdering comp) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().merge(x.icont(), + ValueCompareToNodeCompare(comp)); + } + else{ + throw std::runtime_error("list::merge called with unequal allocators"); + } + } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { this->sort(value_less()); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(StrictWeakOrdering comp) + { + // nothing if the list has length 0 or 1. + if (this->size() < 2) + return; + this->icont().sort(ValueCompareToNodeCompare(comp)); + } + + /// @cond + private: + + //Iterator range version + template + void priv_create_and_insert_nodes + (const_iterator pos, InpIterator beg, InpIterator end) + { + typedef typename std::iterator_traits::iterator_category ItCat; + priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); + } + + template + 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 + 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 + 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 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 cvalue_iterator; + this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); + } + + //Dispatch to detect iterator range or integer overloads + template + void priv_insert_dispatch(const_iterator p, + InputIter first, InputIter last, + containers_detail::false_) + { this->priv_create_and_insert_nodes(p, first, last); } + + template + void priv_insert_dispatch(const_iterator p, Integer n, Integer x, containers_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 + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InputIter first2, InputIter last2, containers_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 +inline bool operator==(const list& x, const list& y) +{ + if(x.size() != y.size()){ + return false; + } + typedef typename list::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 +inline bool operator<(const list& x, + const list& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline bool operator!=(const list& x, const list& y) +{ + return !(x == y); +} + +template +inline bool operator>(const list& x, const list& y) +{ + return y < x; +} + +template +inline bool operator<=(const list& x, const list& y) +{ + return !(y < x); +} + +template +inline bool operator>=(const list& x, const list& y) +{ + return !(x < y); +} + +template +inline void swap(list& x, list& y) +{ + x.swap(y); +} + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif // BOOST_CONTAINERS_LIST_HPP_ diff --git a/include/boost/interprocess/containers/container/map.hpp b/include/boost/interprocess/containers/container/map.hpp new file mode 100644 index 0000000..c0033c7 --- /dev/null +++ b/include/boost/interprocess/containers/container/map.hpp @@ -0,0 +1,1266 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This 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_CONTAINERS_MAP_HPP +#define BOOST_CONTAINERS_MAP_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators == and <, needed for friend declarations. +template +inline bool operator==(const map& x, + const map& y); + +template +inline bool operator<(const map& x, + const map& y); +/// @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 the key_type is Key and the value_type is std::pair. +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//! (e.g. allocator< std::pair > ). +template +class map +{ + /// @cond + private: + typedef containers_detail::rbtree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + BOOST_INTERPROCESS_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; + typedef std::pair nonconst_value_type; + typedef containers_detail::pair + nonconst_impl_value_type; + + /// @cond + class value_compare_impl + : public Pred, + public std::binary_function + { + friend class map; + 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; + + //! Effects: Constructs an empty map using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit map(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty map using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + map(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, true) + {} + + //! Effects: Copy constructs a map. + //! + //! Complexity: Linear in x.size(). + map(const map& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a map. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + map(BOOST_INTERPROCESS_RV_REF(map) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + map& operator=(const map& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + map& operator=(BOOST_INTERPROCESS_RV_REF(map) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: 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(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: 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)){ + containers_detail::value_init v; + value_type val(k, boost::interprocess::move(v.m_t)); + i = insert(i, boost::interprocess::move(val)); + } + return (*i).second; + } + + //! Effects: If there is no key equivalent to x in the map, inserts + //! value_type(boost::interprocess::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. + T& operator[](BOOST_INTERPROCESS_RV_REF(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::interprocess::move(k), boost::interprocess::move(T())); + i = insert(i, boost::interprocess::move(val)); + } + 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. + 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; + } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(map& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(const nonconst_value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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); } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(iterator position, const nonconst_value_type& x) + { return m_tree.insert_unique(position, x); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: 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. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_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 \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));}\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: 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); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const map&, + const map&); + template + friend bool operator< (const map&, + const map&); + /// @endcond +}; + +template +inline bool operator==(const map& x, + const map& y) + { return x.m_tree == y.m_tree; } + +template +inline bool operator<(const map& x, + const map& y) + { return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const map& x, + const map& y) + { return !(x == y); } + +template +inline bool operator>(const map& x, + const map& y) + { return y < x; } + +template +inline bool operator<=(const map& x, + const map& y) + { return !(y < x); } + +template +inline bool operator>=(const map& x, + const map& y) + { return !(x < y); } + +template +inline void swap(map& x, map& y) + { x.swap(y); } + +/// @cond + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multimap& x, + const multimap& y); + +template +inline bool operator<(const multimap& x, + const multimap& y); + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @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 the key_type is Key and the value_type is std::pair. +//! +//! Pred is the ordering function for Keys (e.g. std::less). +//! +//! Alloc is the allocator to allocate the value_types +//!(e.g. allocator< std::pair<const Key, T> >). +template +class multimap +{ + /// @cond + private: + typedef containers_detail::rbtree, + containers_detail::select1st< std::pair >, + Pred, + Alloc> tree_t; + tree_t m_tree; // red-black tree representing map + /// @endcond + + public: + BOOST_INTERPROCESS_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; + typedef std::pair nonconst_value_type; + typedef containers_detail::pair + nonconst_impl_value_type; + + /// @cond + class value_compare_impl + : public Pred, + public std::binary_function + { + friend class multimap; + 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; + + //! Effects: Constructs an empty multimap using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multimap(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty multimap using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multimap(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, false) + {} + + //! Effects: Copy constructs a multimap. + //! + //! Complexity: Linear in x.size(). + multimap(const multimap& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a multimap. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + multimap(BOOST_INTERPROCESS_RV_REF(multimap) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multimap& operator=(const multimap& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multimap& operator=(BOOST_INTERPROCESS_RV_REF(multimap) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return value_compare(m_tree.key_comp()); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: 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(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multimap& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const nonconst_value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a new value move-constructed from x and returns + //! the iterator pointing to the newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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); } + + //! Effects: Inserts a new value constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, const nonconst_value_type& x) + { return m_tree.insert_equal(position, x); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_value_type) x) + { return m_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Effects: Inserts a new value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(iterator position, BOOST_INTERPROCESS_RV_REF(nonconst_impl_value_type) x) + { return m_tree.insert_equal(position, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_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 \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by position. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator position) + { return m_tree.erase(position); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: 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); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + {return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multimap& x, + const multimap& y); + + template + friend bool operator< (const multimap& x, + const multimap& y); + /// @endcond +}; + +template +inline bool operator==(const multimap& x, + const multimap& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multimap& x, + const multimap& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multimap& x, + const multimap& y) +{ return !(x == y); } + +template +inline bool operator>(const multimap& x, + const multimap& y) +{ return y < x; } + +template +inline bool operator<=(const multimap& x, + const multimap& y) +{ return !(y < x); } + +template +inline bool operator>=(const multimap& x, + const multimap& y) +{ return !(x < y); } + +template +inline void swap(multimap& x, multimap& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_MAP_HPP */ + diff --git a/include/boost/interprocess/containers/container/set.hpp b/include/boost/interprocess/containers/container/set.hpp new file mode 100644 index 0000000..bf5234a --- /dev/null +++ b/include/boost/interprocess/containers/container/set.hpp @@ -0,0 +1,1112 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This 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_CONTAINERS_SET_HPP +#define BOOST_CONTAINERS_SET_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +#include +#endif + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +// Forward declarations of operators < and ==, needed for friend declaration. +template +inline bool operator==(const set& x, + const set& y); + +template +inline bool operator<(const set& x, + const set& y); +/// @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 set +{ + /// @cond + private: + typedef containers_detail::rbtree, Pred, Alloc> tree_t; + tree_t m_tree; // red-black tree representing set + /// @endcond + + public: + BOOST_INTERPROCESS_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; + + //! Effects: Constructs an empty set using the specified comparison object + //! and allocator. + //! + //! Complexity: Constant. + explicit set(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty set using the specified comparison object and + //! allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + set(InputIterator first, InputIterator last, const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, true) + {} + + //! Effects: Copy constructs a set. + //! + //! Complexity: Linear in x.size(). + set(const set& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a set. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + set(BOOST_INTERPROCESS_RV_REF(set) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + set& operator=(const set& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + set& operator=(BOOST_INTERPROCESS_RV_REF(set) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: 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(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(set& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x if and only if there is no element in the container + //! with key equivalent to the key of x. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(const value_type& x) + { return m_tree.insert_unique(x); } + + //! Effects: 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. + //! + //! Returns: 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. + //! + //! Complexity: Logarithmic. + std::pair insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(boost::interprocess::move(x)); } + + //! Effects: 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. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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); } + + //! Effects: Inserts an element move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_unique(p, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: 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. + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_unique(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_unique(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(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. + //! + //! Returns: An iterator pointing to the element with key equivalent to the key of x. + //! + //! Complexity: Logarithmic. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_unique(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_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 \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_unique(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_unique(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _));}\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by p. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator p) + { return m_tree.erase(p); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: 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); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const_iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.find(x) == m_tree.end() ? 0 : 1; } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const set&, const set&); + + template + friend bool operator< (const set&, const set&); + /// @endcond +}; + +template +inline bool operator==(const set& x, + const set& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const set& x, + const set& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const set& x, + const set& y) +{ return !(x == y); } + +template +inline bool operator>(const set& x, + const set& y) +{ return y < x; } + +template +inline bool operator<=(const set& x, + const set& y) +{ return !(y < x); } + +template +inline bool operator>=(const set& x, + const set& y) +{ return !(x < y); } + +template +inline void swap(set& x, set& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +// Forward declaration of operators < and ==, needed for friend declaration. + +template +inline bool operator==(const multiset& x, + const multiset& y); + +template +inline bool operator<(const multiset& x, + const multiset& y); +/// @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 multiset +{ + /// @cond + private: + typedef containers_detail::rbtree, Pred, Alloc> tree_t; + tree_t m_tree; // red-black tree representing multiset + /// @endcond + + public: + BOOST_INTERPROCESS_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; + + //! Effects: Constructs an empty multiset using the specified comparison + //! object and allocator. + //! + //! Complexity: Constant. + explicit multiset(const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(comp, a) + {} + + //! Effects: Constructs an empty multiset using the specified comparison object + //! and allocator, and inserts elements from the range [first ,last ). + //! + //! Complexity: Linear in N if the range [first ,last ) is already sorted using + //! comp and otherwise N logN, where N is last - first. + template + multiset(InputIterator first, InputIterator last, + const Pred& comp = Pred(), + const allocator_type& a = allocator_type()) + : m_tree(first, last, comp, a, false) + {} + + //! Effects: Copy constructs a multiset. + //! + //! Complexity: Linear in x.size(). + multiset(const multiset& x) + : m_tree(x.m_tree) + {} + + //! Effects: Move constructs a multiset. Constructs *this using x's resources. + //! + //! Complexity: Construct. + //! + //! Postcondition: x is emptied. + multiset(BOOST_INTERPROCESS_RV_REF(multiset) x) + : m_tree(boost::interprocess::move(x.m_tree)) + {} + + //! Effects: Makes *this a copy of x. + //! + //! Complexity: Linear in x.size(). + multiset& operator=(const multiset& x) + { m_tree = x.m_tree; return *this; } + + //! Effects: this->swap(x.get()). + //! + //! Complexity: Constant. + multiset& operator=(BOOST_INTERPROCESS_RV_REF(multiset) x) + { m_tree = boost::interprocess::move(x.m_tree); return *this; } + + //! Effects: Returns the comparison object out + //! of which a was constructed. + //! + //! Complexity: Constant. + key_compare key_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns an object of value_compare constructed out + //! of the comparison object. + //! + //! Complexity: Constant. + value_compare value_comp() const + { return m_tree.key_comp(); } + + //! Effects: Returns a copy of the Allocator that + //! was passed to the object's constructor. + //! + //! Complexity: 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(); } + + //! Effects: Returns an iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return m_tree.begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return m_tree.begin(); } + + //! Effects: Returns an iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return m_tree.end(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return m_tree.end(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return m_tree.rbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return m_tree.rbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return m_tree.rend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return m_tree.rend(); } + + //! Effects: Returns a const_iterator to the first element contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return m_tree.cbegin(); } + + //! Effects: Returns a const_iterator to the end of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return m_tree.cend(); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin() const + { return m_tree.crbegin(); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return m_tree.crend(); } + + //! Effects: Returns true if the container contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return m_tree.empty(); } + + //! Effects: Returns the number of the elements contained in the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return m_tree.size(); } + + //! Effects: Returns the largest possible size of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return m_tree.max_size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(multiset& x) + { m_tree.swap(x.m_tree); } + + //! Effects: Inserts x and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + iterator insert(const value_type& x) + { return m_tree.insert_equal(x); } + + //! Effects: Inserts a copy of x in the container. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_equal(boost::interprocess::move(x)); } + + //! Effects: Inserts a copy of x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: 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); } + + //! Effects: Inserts a value move constructed from x in the container. + //! p is a hint pointing to where the insert should start to search. + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return m_tree.insert_equal(p, boost::interprocess::move(x)); } + + //! Requires: i, j are not iterators into *this. + //! + //! Effects: inserts each element from the range [i,j) . + //! + //! Complexity: N log(size()+N) (N is the distance from i to j) + template + void insert(InputIterator first, InputIterator last) + { m_tree.insert_equal(first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... and returns the iterator pointing to the + //! newly inserted element. + //! + //! Complexity: Logarithmic. + template + iterator emplace(Args&&... args) + { return m_tree.emplace_equal(boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... + //! + //! Returns: An iterator pointing to the element with key equivalent + //! to the key of x. + //! + //! Complexity: Logarithmic in general, but amortized constant if t + //! is inserted right before p. + template + iterator emplace_hint(const_iterator hint, Args&&... args) + { return m_tree.emplace_hint_equal(hint, boost::interprocess::forward(args)...); } + + #else //#ifdef BOOST_CONTAINERS_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 \ + iterator emplace(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_equal(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); } \ + \ + template \ + iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { return m_tree.emplace_hint_equal(hint, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); }\ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element pointed to by p. + //! + //! Returns: Returns an iterator pointing to the element immediately + //! following q prior to the element being erased. If no such element exists, + //! returns end(). + //! + //! Complexity: Amortized constant time + iterator erase(const_iterator p) + { return m_tree.erase(p); } + + //! Effects: Erases all elements in the container with key equivalent to x. + //! + //! Returns: Returns the number of erased elements. + //! + //! Complexity: log(size()) + count(k) + size_type erase(const key_type& x) + { return m_tree.erase(x); } + + //! Effects: Erases all the elements in the range [first, last). + //! + //! Returns: Returns last. + //! + //! Complexity: 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); } + + //! Effects: erase(a.begin(),a.end()). + //! + //! Postcondition: size() == 0. + //! + //! Complexity: linear in size(). + void clear() + { m_tree.clear(); } + + //! Returns: An iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + iterator find(const key_type& x) + { return m_tree.find(x); } + + //! Returns: A const iterator pointing to an element with the key + //! equivalent to x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic. + const_iterator find(const key_type& x) const + { return m_tree.find(x); } + + //! Returns: The number of elements with key equivalent to x. + //! + //! Complexity: log(size())+count(k) + size_type count(const key_type& x) const + { return m_tree.count(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator lower_bound(const key_type& x) + { return m_tree.lower_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than k, or a.end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator lower_bound(const key_type& x) const + { return m_tree.lower_bound(x); } + + //! Returns: An iterator pointing to the first element with key not less + //! than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + iterator upper_bound(const key_type& x) + { return m_tree.upper_bound(x); } + + //! Returns: A const iterator pointing to the first element with key not + //! less than x, or end() if such an element is not found. + //! + //! Complexity: Logarithmic + const_iterator upper_bound(const key_type& x) const + { return m_tree.upper_bound(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) + { return m_tree.equal_range(x); } + + //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). + //! + //! Complexity: Logarithmic + std::pair + equal_range(const key_type& x) const + { return m_tree.equal_range(x); } + + /// @cond + template + friend bool operator== (const multiset&, + const multiset&); + template + friend bool operator< (const multiset&, + const multiset&); + /// @endcond +}; + +template +inline bool operator==(const multiset& x, + const multiset& y) +{ return x.m_tree == y.m_tree; } + +template +inline bool operator<(const multiset& x, + const multiset& y) +{ return x.m_tree < y.m_tree; } + +template +inline bool operator!=(const multiset& x, + const multiset& y) +{ return !(x == y); } + +template +inline bool operator>(const multiset& x, + const multiset& y) +{ return y < x; } + +template +inline bool operator<=(const multiset& x, + const multiset& y) +{ return !(y < x); } + +template +inline bool operator>=(const multiset& x, + const multiset& y) +{ return !(x < y); } + +template +inline void swap(multiset& x, multiset& y) +{ x.swap(y); } + +/// @cond + +} //namespace interprocess_container { + +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value && has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} + +#include + +#endif /* BOOST_CONTAINERS_SET_HPP */ + diff --git a/include/boost/interprocess/containers/container/slist.hpp b/include/boost/interprocess/containers/container/slist.hpp new file mode 100644 index 0000000..6e60ae1 --- /dev/null +++ b/include/boost/interprocess/containers/container/slist.hpp @@ -0,0 +1,1524 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/container 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_CONTAINERS_SLIST_HPP +#define BOOST_CONTAINERS_SLIST_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING +//Preprocessor library to emulate perfect forwarding +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace containers_detail { + +template +struct slist_hook +{ + typedef typename containers_detail::bi::make_slist_base_hook + , containers_detail::bi::link_mode >::type type; +}; + +template +struct slist_node + : public slist_hook::type +{ + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + slist_node() + : m_data() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + slist_node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : m_data(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + slist_node(Args &&...args) + : m_data(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + T m_data; +}; + +template +struct intrusive_slist_type +{ + typedef typename A::value_type value_type; + typedef typename boost::pointer_to_other + ::type void_pointer; + typedef typename containers_detail::slist_node + node_type; + + typedef typename containers_detail::bi::make_slist + ::type> + ,containers_detail::bi::constant_time_size + ,containers_detail::bi::size_type + >::type container_type; + typedef container_type type ; +}; + +} //namespace containers_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::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 slist + : protected containers_detail::node_alloc_holder + ::type> +{ + /// @cond + typedef typename + containers_detail::intrusive_slist_type::type Icont; + typedef containers_detail::node_alloc_holder AllocHolder; + typedef typename AllocHolder::NodePtr NodePtr; + typedef slist ThisType; + typedef typename AllocHolder::NodeAlloc NodeAlloc; + typedef typename AllocHolder::ValAlloc ValAlloc; + typedef typename AllocHolder::Node Node; + typedef containers_detail::allocator_destroyer 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 + struct ValueCompareToNodeCompare + : Pred + { + ValueCompareToNodeCompare(Pred pred) + : Pred(pred) + {} + + bool operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.m_data, b.m_data); } + + bool operator()(const Node &a) const + { return static_cast(*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_INTERPROCESS_ENABLE_MOVE_EMULATION(slist) + + //! Const iterator used to iterate through a list. + class const_iterator + /// @cond + : public std::iterator + { + + 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; + 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; + 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: + //! Effects: Constructs a list taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit slist(const allocator_type& a = allocator_type()) + : AllocHolder(a) + {} + + explicit slist(size_type n) + : AllocHolder(allocator_type()) + { this->resize(n); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: 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); } + + //! Effects: Constructs a list that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the list. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + slist(InpIt first, InpIt last, + const allocator_type& a = allocator_type()) + : AllocHolder(a) + { this->insert_after(this->before_begin(), first, last); } + + //! Effects: Copy constructs a list. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocator_type's default constructor or copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + slist(const slist& x) + : AllocHolder(x) + { this->insert_after(this->before_begin(), x.begin(), x.end()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + slist(BOOST_INTERPROCESS_RV_REF(slist) x) + : AllocHolder(boost::interprocess::move((AllocHolder&)x)) + {} + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + slist& operator= (const slist& x) + { + if (&x != this){ + this->assign(x.begin(), x.end()); + } + return *this; + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + slist& operator= (BOOST_INTERPROCESS_RV_REF(slist) mx) + { + if (&mx != this){ + this->clear(); + this->swap(mx); + } + return *this; + } + + //! Effects: Destroys the list. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~slist() + {} //AllocHolder clears the slist + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: 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: + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const T& val) + { this->priv_fill_assign(n, val); } + + //! Effects: Assigns the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InpIt first, InpIt last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Returns an iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->icont().begin()); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->cbegin(); } + + //! Effects: Returns an iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->icont().end()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a non-dereferenceable iterator that, + //! when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator before_begin() + { return iterator(end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator before_begin() const + { return this->cbefore_begin(); } + + //! Effects: Returns a const_iterator to the first element contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->non_const_icont().begin()); } + + //! Effects: Returns a const_iterator to the end of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->non_const_icont().end()); } + + //! Effects: Returns a non-dereferenceable const_iterator + //! that, when incremented, yields begin(). This iterator may be used + //! as the argument toinsert_after, erase_after, etc. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbefore_begin() const + { return const_iterator(end()); } + + //! Effects: Returns the number of the elements contained in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->icont().size(); } + + //! Effects: Returns the largest possible size of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return AllocHolder::max_size(); } + + //! Effects: Returns true if the list contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->size(); } + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements on *this and x. + void swap(slist& x) + { AllocHolder::swap(x); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->begin(); } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->begin(); } + + //! Effects: Inserts a copy of t in the beginning of the list. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const value_type& x) + { this->icont().push_front(*this->create_node(x)); } + + //! Effects: Constructs a new element in the beginning of the list + //! and moves the resources of t to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(BOOST_INTERPROCESS_RV_REF(T) x) + { this->icont().push_front(*this->create_node(boost::interprocess::move(x))); } + + //! Effects: Removes the first element from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Amortized constant time. + void pop_front() + { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } + + //! Returns: 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. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + iterator previous(iterator p) + { return iterator(this->icont().previous(p.get())); } + + //! Returns: 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. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before i. + const_iterator previous(const_iterator p) + { return const_iterator(this->icont().previous(p.get())); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts a copy of the value after the p pointed + //! by prev_p. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: 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))); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts a move constructed copy object from the value after the + //! p pointed by prev_pos. + //! + //! Returns: An iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + iterator insert_after(const_iterator prev_pos, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return iterator(this->icont().insert_after(prev_pos.get(), *this->create_node(boost::interprocess::move(x)))); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x after prev_pos. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: 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); } + + //! Requires: prev_pos must be a valid iterator of *this. + //! + //! Effects: Inserts the range pointed by [first, last) + //! after the p prev_pos. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to the number of elements inserted. + //! + //! Note: Does not affect the validity of iterators and references of + //! previous values. + template + void insert_after(const_iterator prev_pos, InIter first, InIter last) + { + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator p, const value_type& x) + { return this->insert_after(previous(p), x); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Linear to the elements before p. + iterator insert(const_iterator p, BOOST_INTERPROCESS_RV_REF(value_type) x) + { return this->insert_after(previous(p), boost::interprocess::move(x)); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts n copies of x before p. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: 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); } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before p. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws. + //! + //! Complexity: Linear to std::distance [first, last) plus + //! linear to the elements before p. + template + void insert(const_iterator p, InIter first, InIter last) + { return this->insert_after(previous(p), first, last); } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the front of the list + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_front(Args&&... args) + { this->emplace_after(this->cbefore_begin(), boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Linear to the elements before p + template + iterator emplace(const_iterator p, Args&&... args) + { return this->emplace_after(this->previous(p), boost::interprocess::forward(args)...); } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... after prev + //! + //! Throws: If memory allocation throws or + //! T's in-place constructor throws. + //! + //! Complexity: Constant + template + iterator emplace_after(const_iterator prev, Args&&... args) + { + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); + new ((void*)containers_detail::get_pointer(d.get())) Node(boost::interprocess::forward(args)...); + NodePtr node = d.get(); + d.release(); + return iterator(this->icont().insert_after(prev.get(), *node)); + } + + #else //#ifdef BOOST_CONTAINERS_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*)containers_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 \ + void emplace_front(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + this->emplace \ + (this->cbegin(), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + iterator emplace \ + (const_iterator p, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + return this->emplace_after \ + (this->previous(p), BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + } \ + \ + template \ + iterator emplace_after \ + (const_iterator prev, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); \ + new ((void*)containers_detail::get_pointer(d.get())) \ + Node(BOOST_PP_ENUM(n, BOOST_CONTAINERS_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_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Erases the element after the element pointed by prev_pos + //! of the list. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: 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()))); + } + + //! Effects: Erases the range (before_first, last) from + //! the list. + //! + //! Returns: the first element remaining beyond the removed elements, + //! or end() if no such element exists. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of erased elements. + //! + //! Note: 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()))); + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Erases the element at p p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements before p. + iterator erase(const_iterator p) + { return iterator(this->erase_after(previous(p))); } + + //! Requires: first and last must be valid iterator to elements in *this. + //! + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: 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)); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + } + } + + //! Effects: Erases all the elements of the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the list. + void clear() + { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, after the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the elements in x. + //! + //! Note: 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. + void splice_after(const_iterator prev_pos, slist& x) + { + 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"); + } + } + + //! Requires: prev_pos must be a valid iterator of this. + //! i must point to an element contained in list x. + //! + //! Effects: 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. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: 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. + void splice_after(const_iterator prev_pos, slist& x, const_iterator prev) + { + 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"); + } + } + + //! Requires: 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. + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear to the number of transferred elements. + //! + //! Note: 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. + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last) + { + 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"); + } + } + + //! Requires: 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) + //! + //! Effects: Transfers the range [before_first + 1, before_last + 1) + //! from list x to this list, after the element pointed by prev_pos. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Constant. + //! + //! Note: 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. + void splice_after(const_iterator prev_pos, slist& x, + const_iterator before_first, const_iterator before_last, + size_type n) + { + 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"); + } + } + + //! Requires: p must point to an element contained + //! by the list. x != *this + //! + //! Effects: Transfers all the elements of list x to this list, before the + //! the element pointed by p. No destructors or copy constructors are called. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and linear in x.size(). + //! + //! Note: 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. + void splice(const_iterator p, ThisType& x) + { this->splice_after(this->previous(p), x); } + + //! Requires: p must point to an element contained + //! by this list. i must point to an element contained in list x. + //! + //! Effects: 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. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). + //! + //! Note: 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. + void splice(const_iterator p, slist& x, const_iterator i) + { this->splice_after(previous(p), x, i); } + + //! Requires: p must point to an element contained + //! by this list. first and last must point to elements contained in list x. + //! + //! Effects: 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. + //! + //! Throws: std::runtime_error if this' allocator and x's allocator + //! are not equal. + //! + //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), + //! and in distance(first, last). + //! + //! Note: 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. + void splice(const_iterator p, slist& x, const_iterator first, const_iterator last) + { this->splice_after(previous(p), x, previous(first), previous(last)); } + + //! Effects: Reverses the order of elements in the list. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time. + //! + //! Note: Iterators and references are not invalidated + void reverse() + { this->icont().reverse(); } + + //! Effects: Removes all the elements that compare equal to value. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time. It performs exactly size() comparisons for equality. + //! + //! Note: 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)); } + + //! Effects: Removes all the elements for which a specified + //! predicate is satisfied. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time. It performs exactly size() calls to the predicate. + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void remove_if(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that are equal from the list. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear time (size()-1 comparisons calls to pred()). + //! + //! Note: 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()); } + + //! Effects: Removes adjacent duplicate elements or adjacent + //! elements that satisfy some binary predicate from the list. + //! + //! Throws: If pred throws. + //! + //! Complexity: Linear time (size()-1 comparisons equality comparisons). + //! + //! Note: The relative order of elements that are not removed is unchanged, + //! and iterators to elements that are not removed remain valid. + template + void unique(Pred pred) + { + typedef ValueCompareToNodeCompare Predicate; + this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc())); + } + + //! Requires: The lists x and *this must be distinct. + //! + //! Effects: This function removes all of x's elements and inserts them + //! in order into *this according to std::less. 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. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + void merge(slist & x) + { this->merge(x, value_less()); } + + //! Requires: 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. + //! + //! Effects: 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. + //! + //! Throws: Nothing. + //! + //! Complexity: This function is linear time: it performs at most + //! size() + x.size() - 1 comparisons. + //! + //! Note: Iterators and references to *this are not invalidated. + template + void merge(slist& x, StrictWeakOrdering comp) + { + if((NodeAlloc&)*this == (NodeAlloc&)x){ + this->icont().merge(x.icont(), + ValueCompareToNodeCompare(comp)); + } + else{ + throw std::runtime_error("list::merge called with unequal allocators"); + } + } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + void sort() + { this->sort(value_less()); } + + //! Effects: This function sorts the list *this according to std::less. + //! The sort is stable, that is, the relative order of equivalent elements is preserved. + //! + //! Throws: Nothing. + //! + //! Notes: Iterators and references are not invalidated. + //! + //! Complexity: The number of comparisons is approximately N log N, where N + //! is the list's size. + template + void sort(StrictWeakOrdering comp) + { + // nothing if the slist has length 0 or 1. + if (this->size() < 2) + return; + this->icont().sort(ValueCompareToNodeCompare(comp)); + } + + /// @cond + private: + + //Iterator range version + template + void priv_create_and_insert_nodes + (const_iterator prev, InpIterator beg, InpIterator end) + { + typedef typename std::iterator_traits::iterator_category ItCat; + priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); + } + + template + 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 + 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 + 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 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 cvalue_iterator; + this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); + } + + //Dispatch to detect iterator range or integer overloads + template + void priv_insert_dispatch(const_iterator prev, + InputIter first, InputIter last, + containers_detail::false_) + { this->priv_create_and_insert_nodes(prev, first, last); } + + template + void priv_insert_dispatch(const_iterator prev, Integer n, Integer x, containers_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 + void priv_assign_dispatch(Int n, Int val, containers_detail::true_) + { this->priv_fill_assign((size_type) n, (T)val); } + + template + void priv_assign_dispatch(InpIt first, InpIt last, containers_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 + void priv_insert_after_range_dispatch(const_iterator prev_pos, Int n, Int x, containers_detail::true_) + { this->priv_create_and_insert_nodes(prev_pos, n, x); } + + template + void priv_insert_after_range_dispatch(const_iterator prev_pos, InIter first, InIter last, containers_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 +inline bool +operator==(const slist& x, const slist& y) +{ + if(x.size() != y.size()){ + return false; + } + typedef typename slist::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 +inline bool +operator<(const slist& sL1, const slist& sL2) +{ + return std::lexicographical_compare + (sL1.begin(), sL1.end(), sL2.begin(), sL2.end()); +} + +template +inline bool +operator!=(const slist& sL1, const slist& sL2) + { return !(sL1 == sL2); } + +template +inline bool +operator>(const slist& sL1, const slist& sL2) + { return sL2 < sL1; } + +template +inline bool +operator<=(const slist& sL1, const slist& sL2) + { return !(sL2 < sL1); } + +template +inline bool +operator>=(const slist& sL1, const slist& sL2) + { return !(sL1 < sL2); } + +template +inline void swap(slist& x, slist& y) + { x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +} //namespace interprocess { + +namespace interprocess_container { + +/// @endcond + +}} //namespace boost{ namespace interprocess_container { + +// 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 insert_iterator > +{ + protected: + typedef boost::interprocess_container::slist Container; + Container* container; + typename Container::iterator iter; + public: + typedef Container container_type; + typedef output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + insert_iterator(Container& x, + typename Container::iterator i, + bool is_previous = false) + : container(&x), iter(is_previous ? i : x.previous(i)){ } + + insert_iterator& + operator=(const typename Container::value_type& value) + { + iter = container->insert_after(iter, value); + return *this; + } + insert_iterator& operator*(){ return *this; } + insert_iterator& operator++(){ return *this; } + insert_iterator& operator++(int){ return *this; } +}; + +} //namespace std; + +///@endcond + +#include + +#endif /* BOOST_CONTAINERS_SLIST_HPP */ diff --git a/include/boost/interprocess/containers/container/stable_vector.hpp b/include/boost/interprocess/containers/container/stable_vector.hpp new file mode 100644 index 0000000..3182dcd --- /dev/null +++ b/include/boost/interprocess/containers/container/stable_vector.hpp @@ -0,0 +1,1351 @@ +/* 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STABLE_VECTOR_USE_CONTAINERS_VECTOR + +#if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR) +#include +#else +#include +#endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR + +//#define STABLE_VECTOR_ENABLE_INVARIANT_CHECKING + +#if defined(STABLE_VECTOR_ENABLE_INVARIANT_CHECKING) +#include +#endif + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace stable_vector_detail{ + +template +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 +struct smart_ptr_type +{ + typedef T value_type; + typedef value_type *pointer; + static pointer get (pointer ptr) + { return ptr;} +}; + +template +inline typename smart_ptr_type::pointer get_pointer(const Ptr &ptr) +{ return smart_ptr_type::get(ptr); } + +template +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 constant_iterator + : public std::iterator + +{ + typedef constant_iterator 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 +struct node_type_base +{/* + node_type_base(VoidPtr p) + : up(p) + {}*/ + node_type_base() + {} + void set_pointer(VoidPtr p) + { up = p; } + + VoidPtr up; +}; + +template +struct node_type + : public node_type_base +{ + #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + node_type() + {} + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + node_type(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + : value(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)) \ + {} \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #else //#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + template + node_type(Args &&...args) + : value(boost::interprocess::forward(args)...) + {} + #endif//#ifndef BOOST_CONTAINERS_PERFECT_FORWARDING + + void set_pointer(VoidPointer p) + { node_type_base::set_pointer(p); } + + T value; +}; + +template +class iterator + : public std::iterator< std::random_access_iterator_tag + , const typename std::iterator_traits::value_type + , typename std::iterator_traits::difference_type + , Pointer + , Value &> +{ + + typedef typename boost::pointer_to_other + ::type void_ptr; + typedef node_type node_type_t; + typedef typename boost::pointer_to_other + ::type node_type_ptr_t; + typedef typename boost::pointer_to_other + ::type void_ptr_ptr; + + friend class iterator::type>; + + public: + typedef std::random_access_iterator_tag iterator_category; + typedef Value value_type; + typedef typename std::iterator_traits + ::difference_type difference_type; + typedef Pointer pointer; + typedef Value & reference; + + iterator() + {} + + explicit iterator(node_type_ptr_t pn) + : pn(pn) + {} + + iterator(const iterator::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(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(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 + static typename iterator::node_type_t* get(const iterator& it) + { + return stable_vector_detail::get_pointer(it.pn); + } +}; +*/ + +template +struct select_multiallocation_chain +{ + typedef typename Allocator::multiallocation_chain type; +}; + +template +struct select_multiallocation_chain +{ + typedef typename Allocator::template + rebind::other::pointer void_ptr; + typedef containers_detail::basic_multiallocation_cached_slist multialloc_cached; + typedef containers_detail::basic_multiallocation_cached_counted_slist + multialloc_cached_counted; + typedef boost::interprocess_container::containers_detail::transform_multiallocation_chain + 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) + +/// @endcond + +template > +class stable_vector +{ + typedef typename Allocator::template + rebind::other::pointer void_ptr; + typedef typename Allocator::template + rebind::other::pointer void_ptr_ptr; + typedef stable_vector_detail::node_type + node_type_t; + typedef typename Allocator::template + rebind::other::pointer node_type_ptr_t; + typedef stable_vector_detail::node_type_base + node_type_base_t; + typedef typename Allocator::template + rebind::other::pointer node_type_base_ptr_t; + typedef + #if defined (STABLE_VECTOR_USE_CONTAINERS_VECTOR) + ::boost::interprocess_container:: + #else + ::std:: + #endif //STABLE_VECTOR_USE_CONTAINERS_VECTOR + vector::other + > impl_type; + typedef typename impl_type::iterator impl_iterator; + typedef typename impl_type::const_iterator const_impl_iterator; + + typedef ::boost::interprocess_container::containers_detail:: + integral_constant allocator_v1; + typedef ::boost::interprocess_container::containers_detail:: + integral_constant allocator_v2; + typedef ::boost::interprocess_container::containers_detail::integral_constant + ::value> alloc_version; + typedef typename Allocator:: + template rebind::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; + + 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 + iterator; + typedef stable_vector_detail::iterator + 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 reverse_iterator; + typedef std::reverse_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: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(stable_vector) + + // 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 cod(*this); + this->insert(this->cbegin(), n, t); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + template + stable_vector(InputIterator first,InputIterator last,const Allocator& al=Allocator()) + : internal_data(al),impl(al) + { + stable_vector_detail::clear_on_destroy 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 cod(*this); + this->insert(this->cbegin(), x.begin(), x.end()); + STABLE_VECTOR_CHECK_INVARIANT; + cod.release(); + } + + stable_vector(BOOST_INTERPROCESS_RV_REF(stable_vector) x) + : internal_data(x.get_al()),impl(x.get_al()) + { this->swap(x); } + + ~stable_vector() + { + this->clear(); + clear_pool(); + } + + stable_vector& operator=(const stable_vector &x) + { + STABLE_VECTOR_CHECK_INVARIANT; + if (this != &x) { + this->assign(x.begin(), x.end()); + } + return *this; + } + + stable_vector& operator=(BOOST_INTERPROCESS_RV_REF(stable_vector) x) + { + if (&x != this){ + this->swap(x); + x.clear(); + } + return *this; + } + + template + void assign(InputIterator first,InputIterator last) + { + assign_dispatch(first, last, boost::is_integral()); + } + + void assign(size_type n,const T& t) + { + typedef stable_vector_detail::constant_iterator 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) + { + 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 resize(size_type n) + { + typedef default_construct_iterator default_iterator; + STABLE_VECTOR_CHECK_INVARIANT; + if(n > size()) + this->insert(this->cend(), default_iterator(n - this->size()), default_iterator()); + 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 + void clear_pool(AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::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 + void clear_pool(AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::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::interprocess::move(holder)); + p1 = p2 = 0; + this->internal_data.pool_size = 0; + } + } + + void clear_pool() + { + this->clear_pool(alloc_version()); + } + + template + void add_to_pool(size_type n, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::value>::type * = 0) + { + size_type remaining = n; + while(remaining--){ + this->put_in_pool(this->allocate_one()); + } + } + + template + void add_to_pool(size_type n, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::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::interprocess::is_movable::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 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 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 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 push_back(BOOST_INTERPROCESS_RV_REF(T) t) + { this->insert(end(), boost::interprocess::move(t)); } + + void pop_back() + { this->erase(this->end()-1); } + + iterator insert(const_iterator position, const T& t) + { + typedef stable_vector_detail::constant_iterator cvalue_iterator; + return this->insert_iter(position, cvalue_iterator(t, 1), cvalue_iterator(), std::forward_iterator_tag()); + } + + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x) + { + typedef repeat_iterator repeat_it; + typedef boost::interprocess::move_iterator repeat_move_it; + //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->begin() + pos_n); + } + + void insert(const_iterator position, size_type n, const T& t) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->insert_not_iter(position, n, t); + } + + template + void insert(const_iterator position,InputIterator first, InputIterator last) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->insert_iter(position,first,last, + boost::mpl::not_ >()); + } + + #ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef(boost::interprocess::forward(args)...); + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef(boost::interprocess::forward(args)...); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #else + + void emplace_back() + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef; + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + } + + iterator emplace(const_iterator position) + { + typedef emplace_functor EmplaceFunctor; + typedef emplace_iterator EmplaceIterator; + EmplaceFunctor ef; + size_type pos_n = position - this->cbegin(); + this->insert(position, EmplaceIterator(ef), EmplaceIterator()); + return iterator(this->begin() + pos_n); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); \ + } \ + \ + template \ + iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + typedef BOOST_PP_CAT(BOOST_PP_CAT(emplace_functor, n), arg) \ + EmplaceFunctor; \ + typedef emplace_iterator EmplaceIterator; \ + EmplaceFunctor ef(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + size_type pos_n = pos - this->cbegin(); \ + this->insert(pos, EmplaceIterator(ef), EmplaceIterator()); \ + return iterator(this->begin() + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + iterator erase(const_iterator position) + { + 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()); } + + void swap(stable_vector & x) + { + STABLE_VECTOR_CHECK_INVARIANT; + this->swap_impl(*this,x); + } + + void clear() + { this->erase(this->cbegin(),this->cend()); } + + /// @cond + private: + + void insert_iter_prolog(size_type n, difference_type d) + { + 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); + } + } + + template + 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 + void assign_dispatch(Integer n, Integer t, boost::mpl::true_) + { + typedef stable_vector_detail::constant_iterator 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 + iterator priv_erase(const_iterator first, const_iterator last, AllocatorVersion, + typename boost::interprocess_container::containers_detail::enable_if_c + + ::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(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(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(cp); + return node_ptr_cast(p); + } + + template + void_ptr new_node(void_ptr up, Iter it) + { + node_type_ptr_t p = this->allocate_one(); + try{ + boost::interprocess_container::construct_in_place(&*p, it); + p->set_pointer(up); + } + 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 cvalue_iterator; + this->insert_iter(position, cvalue_iterator(t, n), cvalue_iterator(), std::forward_iterator_tag()); + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last, boost::mpl::true_) + { + typedef typename std::iterator_traits::iterator_category category; + this->insert_iter(position, first, last, category()); + } + + template + void insert_iter(const_iterator position,InputIterator first,InputIterator last,std::input_iterator_tag) + { + for(; first!=last; ++first){ + this->insert(position, *first); + } + } + + template + 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){ + this->insert_iter_prolog(n, 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 + 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); + ++first; + ++i; + } + } + catch(...){ + impl.erase(it + i, it + n); + this->align_nodes(it + i, get_last_align()); + throw; + } + } + + template + 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 + boost::interprocess_container::construct_in_place(&*p, first); + p->set_pointer(void_ptr((void*)(&*(it + i)))); + ++first; + *(it + i) = p; + ++i; + } + } + catch(...){ + get_al().deallocate_one(p); + get_al().deallocate_many(boost::interprocess::move(mem)); + impl.erase(it+i, it+n); + this->align_nodes(it+i,get_last_align()); + throw; + } + } + + template + 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 + boost::interprocess_container::construct_in_place(&*p, first); + p->set_pointer(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 + 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() + { + end_node.set_pointer(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; + /// @endcond +}; + +template +bool operator==(const stable_vector& x,const stable_vector& y) +{ + return x.size()==y.size()&&std::equal(x.begin(),x.end(),y.begin()); +} + +template +bool operator< (const stable_vector& x,const stable_vector& y) +{ + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); +} + +template +bool operator!=(const stable_vector& x,const stable_vector& y) +{ + return !(x==y); +} + +template +bool operator> (const stable_vector& x,const stable_vector& y) +{ + return y +bool operator>=(const stable_vector& x,const stable_vector& y) +{ + return !(x +bool operator<=(const stable_vector& x,const stable_vector& y) +{ + return !(x>y); +} + +// specialized algorithms: + +template +void swap(stable_vector& x,stable_vector& y) +{ + x.swap(y); +} + +/// @cond + +#undef STABLE_VECTOR_CHECK_INVARIANT + +/// @endcond + +}} + +#endif diff --git a/include/boost/interprocess/containers/container/string.hpp b/include/boost/interprocess/containers/container/string.hpp new file mode 100644 index 0000000..cb061ad --- /dev/null +++ b/include/boost/interprocess/containers/container/string.hpp @@ -0,0 +1,2320 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This 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_CONTAINERS_STRING_HPP +#define BOOST_CONTAINERS_STRING_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond +namespace containers_detail { +// ------------------------------------------------------------ +// 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 basic_string_base +{ + basic_string_base(); + basic_string_base(basic_string_base&); + basic_string_base & operator=(basic_string_base&); + + public: + BOOST_INTERPROCESS_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); + } + + basic_string_base(BOOST_INTERPROCESS_RV_REF(basic_string_base) b) + : members_(b.members_) + { + init(); + this->swap(b); + } + + ~basic_string_base() + { + this->deallocate_block(); + if(!this->is_short()){ + static_cast(static_cast(&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::value>::type +// long_alignment_type; + typedef void *long_alignment_type; + BOOST_STATIC_ASSERT((containers_detail::alignment_of::value % + containers_detail::alignment_of::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; + static const size_type ShortDataOffset = + containers_detail::ct_rounded_size::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(&s); } + + long_t &long_repr() const + { return *static_cast(const_cast(static_cast(&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(this->members_.m_repr.s.h.is_short != 0); } + + void is_short(bool yes) + { + if(yes && !this->is_short()){ + static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); + } + else{ + new(static_cast(&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 containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; + + std::pair + 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 + 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(0), 0); + received_size = preferred_size; + return std::make_pair(this->alloc().allocate(received_size), false); + } + + std::pair + 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*)containers_detail::get_pointer(p)) value_type(value); } + + void destroy(pointer p, size_type n) + { + for(; n--; ++p) + containers_detail::get_pointer(p)->~value_type(); + } + + void destroy(pointer p) + { containers_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(sz); + } + + void swap(basic_string_base& other) + { + 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){ + containers_detail::do_swap(this_al, other_al); + } + } +}; + +} //namespace containers_detail { + +/// @endcond + +//! 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 basic_string + : private containers_detail::basic_string_base +{ + /// @cond + private: + typedef containers_detail::basic_string_base 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 + struct Eq_traits + : public std::binary_function + { + bool operator()(const typename Tr::char_type& x, + const typename Tr::char_type& y) const + { return Tr::eq(x, y); } + }; + + template + struct Not_within_traits + : public std::unary_function + { + typedef const typename Tr::char_type* Pointer; + const Pointer m_first; + const Pointer m_last; + + Not_within_traits(Pointer f, Pointer l) + : m_first(f), m_last(l) {} + + bool operator()(const typename Tr::char_type& x) const + { + return std::find_if(m_first, m_last, + std::bind1st(Eq_traits(), x)) == m_last; + } + }; + /// @endcond + + public: + BOOST_INTERPROCESS_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 reverse_iterator; + //! Const iterator used to iterate backwards through a string + typedef std::reverse_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 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(); } + + //! Effects: Constructs a basic_string taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + explicit basic_string(const allocator_type& a = allocator_type()) + : base_t(a, InternalBufferChars) + { this->priv_terminate_string(); } + + //! Effects: Copy constructs a basic_string. + //! + //! Postcondition: x == *this. + //! + //! Throws: 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()); } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + basic_string(BOOST_INTERPROCESS_RV_REF(basic_string) s) + : base_t(boost::interprocess::move((base_t&)s)) + {} + + //! Effects: 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 + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: 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); } + + //! Effects: 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)); } + + //! Effects: 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()); + } + + //! Effects: Constructs a basic_string taking the allocator as parameter, + //! and a range of iterators. + template + basic_string(InputIterator f, InputIterator l, + const allocator_type& a = allocator_type()) + : base_t(a) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_initialize_dispatch(f, l, Result()); + } + + //! Effects: Destroys the basic_string. All used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + ~basic_string() + {} + + //! Effects: Copy constructs a string. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + basic_string& operator=(const basic_string& s) + { + if (&s != this) + this->assign(s.begin(), s.end()); + return *this; + } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + basic_string& operator=(BOOST_INTERPROCESS_RV_REF(basic_string) ms) + { + basic_string &s = ms; + if (&s != this){ + this->swap(s); + } + return *this; + } + + //! Effects: Assignment from a null-terminated c-string. + basic_string& operator=(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + //! Effects: Assignment from character. + basic_string& operator=(CharT c) + { return this->assign(static_cast(1), c); } + + //! Effects: Returns an iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return this->priv_addr(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return this->priv_addr(); } + + //! Effects: Returns an iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return this->priv_addr() + this->priv_size(); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->priv_addr() + this->priv_size(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(this->priv_addr() + this->priv_size()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin() const + { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(this->priv_addr()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return const_reverse_iterator(this->priv_addr()); } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + allocator_type get_allocator() const + { return this->alloc(); } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->priv_size(); } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type length() const + { return this->size(); } + + //! Effects: Returns the largest possible size of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return base_t::max_size(); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type n) + { resize(n, this->priv_null()); } + + //! Effects: 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. + //! + //! Throws: 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 = containers_detail::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); + } + } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return this->priv_capacity(); } + + //! Effects: Erases all the elements of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: 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); + } + } + + //! Effects: Returns true if the vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->priv_size(); } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return *(this->priv_addr() + n); } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const + { return *(this->priv_addr() + n); } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) { + if (n >= size()) + this->throw_out_of_range(); + return *(this->priv_addr() + n); + } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const { + if (n >= size()) + this->throw_out_of_range(); + return *(this->priv_addr() + n); + } + + //! Effects: Appends string s to *this. + basic_string& operator+=(const basic_string& s) + { return this->append(s); } + + //! Effects: Appends c-string s to *this. + basic_string& operator+=(const CharT* s) + { return this->append(s); } + + //! Effects: Appends character c to *this. + basic_string& operator+=(CharT c) + { this->push_back(c); return *this; } + + //! Effects: Appends string s to *this. + basic_string& append(const basic_string& s) + { return this->append(s.begin(), s.end()); } + + //! Effects: 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 + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: 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); } + + //! Effects: Appends the c-string s to *this. + basic_string& append(const CharT* s) + { return this->append(s, s + Traits::length(s)); } + + //! Effects: 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()); } + + //! Effects: Appends the range [first, last) *this. + template + basic_string& append(InputIter first, InputIter last) + { this->insert(this->end(), first, last); return *this; } + + //! Effects: 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); + } + } + + //! Effects: 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);; + } + + //! Effects: Assigns the value s to *this. + basic_string& assign(const basic_string& s) + { return this->operator=(s); } + + //! Effects: Moves the resources from ms *this. + basic_string& assign(BOOST_INTERPROCESS_RV_REF(basic_string) ms) + { return this->operator=(ms);} + + //! Effects: 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 + containers_detail::min_value(n, s.size() - pos)); + } + + //! Effects: 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); } + + //! Effects: Assigns the c-string s to *this. + basic_string& assign(const CharT* s) + { return this->assign(s, s + Traits::length(s)); } + + //! Effects: 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()); } + + //! Effects: Assigns the range [first, last) to *this. + template + basic_string& assign(InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + return this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: 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(n) <= size()) { + Traits::copy(containers_detail::get_pointer(this->priv_addr()), f, n); + this->erase(this->priv_addr() + n, this->priv_addr() + this->priv_size()); + } + else { + Traits::copy(containers_detail::get_pointer(this->priv_addr()), f, this->priv_size()); + this->append(f + this->priv_size(), l); + } + return *this; + } + + //! Effects: 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; + } + + //! Effects: 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 = containers_detail::min_value(n, s.size() - beg); + if (this->size() > this->max_size() - len) + this->throw_length_error(); + const CharT *beg_ptr = containers_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; + } + + //! Effects: 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; + } + + //! Effects: 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; + } + + //! Effects: 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; + } + + //! Effects: 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; + } + + //! Effects: 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()); + } + + //! Effects: Inserts the range [first, last) before position. + template + void insert(iterator p, InputIter first, InputIter last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(p, first, last, Result()); + } + + //! Effects: 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 + containers_detail::min_value(n, size() - pos)); + return *this; + } + + //! Effects: Erases the character pointed by position. + iterator erase(iterator position) + { + // The move includes the terminating null. + Traits::move(containers_detail::get_pointer(position), + containers_detail::get_pointer(position + 1), + this->priv_size() - (position - this->priv_addr())); + this->priv_size(this->priv_size()-1); + return position; + } + + //! Effects: 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(containers_detail::get_pointer(first), + containers_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; + } + + //! Effects: 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 = containers_detail::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()); + } + + //! Effects: 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 = containers_detail::min_value(n1, size() - pos1); + const size_type len2 = containers_detail::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); + } + + //! Effects: 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 = containers_detail::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); + } + + //! Effects: 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 = containers_detail::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)); + } + + //! Effects: 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 = containers_detail::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); + } + + //! Effects: 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()); } + + //! Effects: 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); } + + //! Effects: 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)); } + + //! Effects: 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(last - first); + if (len >= n) { + Traits::assign(containers_detail::get_pointer(first), n, c); + erase(first + n, last); + } + else { + Traits::assign(containers_detail::get_pointer(first), len, c); + insert(last, n - len, c); + } + return *this; + } + + //! Effects: Replaces a substring of *this with the range [f, l) + template + basic_string& replace(iterator first, iterator last, + InputIter f, InputIter l) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + return this->priv_replace_dispatch(first, last, f, l, Result()); + } + + //! Effects: 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 = containers_detail::min_value(n, size() - pos); + Traits::copy(s, containers_detail::get_pointer(this->priv_addr() + pos), len); + return len; + } + + //! Effects: Swaps the contents of two strings. + void swap(basic_string& x) + { base_t::swap(x); } + + //! Returns: 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 containers_detail::get_pointer(this->priv_addr()); } + + //! Returns: 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 containers_detail::get_pointer(this->priv_addr()); } + + //! Effects: 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()); } + + //! Effects: 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)); } + + //! Effects: 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(containers_detail::get_pointer(this->priv_addr() + pos), + containers_detail::get_pointer(finish), + s, s + n, Eq_traits()); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: 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(), c)); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: 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()); } + + //! Effects: 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)); } + + //! Effects: 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 containers_detail::min_value(len, pos); + else { + const const_iterator last = begin() + containers_detail::min_value(len - n, pos) + n; + const const_iterator result = find_end(begin(), last, + s, s + n, + Eq_traits()); + return result != last ? result - begin() : npos; + } + } + + //! Effects: 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() + containers_detail::min_value(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::bind2nd(Eq_traits(), c)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: 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()); } + + //! Effects: 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)); } + + //! Effects: 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()); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: 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); } + + //! Effects: 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()); } + + //! Effects: 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)); } + + //! Effects: 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() + containers_detail::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()); + return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; + } + } + + //! Effects: 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); } + + //! Effects: 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()); } + + //! Effects: 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)); } + + //! Effects: 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(s, s + n)); + return result != finish ? result - this->priv_addr() : npos; + } + } + + //! Effects: 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(), c))); + return result != finish ? result - begin() : npos; + } + } + + //! Effects: 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()); } + + //! Effects: 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)); } + + //! Effects: 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() + containers_detail::min_value(len - 1, pos) + 1; + const const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + Not_within_traits(s, s + n)); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: 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() + containers_detail::min_value(len - 1, pos) + 1; + const_reverse_iterator rresult = + std::find_if(const_reverse_iterator(last), rend(), + std::not1(std::bind2nd(Eq_traits(), c))); + return rresult != rend() ? (rresult.base() - 1) - begin() : npos; + } + } + + //! Effects: 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 + containers_detail::min_value(n, size() - pos), this->alloc()); + } + + //! Effects: 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()); } + + //! Effects: 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 + containers_detail::min_value(n1, size() - pos1), + s.priv_addr(), s.priv_addr() + s.priv_size()); + } + + //! Effects: 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 + containers_detail::min_value(n1, size() - pos1), + s.priv_addr() + pos2, + s.priv_addr() + pos2 + containers_detail::min_value(n2, size() - pos2)); + } + + //! Effects: 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)); } + + + //! Effects: 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 + containers_detail::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(containers_detail::get_pointer(f1), + containers_detail::get_pointer(f2), + containers_detail::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 + 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 + void priv_range_initialize(ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + this->allocate_initial_block(containers_detail::max_value(n+1, InternalBufferChars)); + priv_uninitialized_copy(f, l, this->priv_addr()); + this->priv_size(n); + this->priv_terminate_string(); + } + + template + void priv_range_initialize(InputIter f, InputIter l) + { + typedef typename std::iterator_traits::iterator_category Category; + this->priv_range_initialize(f, l, Category()); + } + + template + void priv_initialize_dispatch(Integer n, Integer x, containers_detail::true_) + { + this->allocate_initial_block(containers_detail::max_value(n+1, InternalBufferChars)); + priv_uninitialized_fill_n(this->priv_addr(), n, x); + this->priv_size(n); + this->priv_terminate_string(); + } + + template + void priv_initialize_dispatch(InputIter f, InputIter l, containers_detail::false_) + { this->priv_range_initialize(f, l); } + + template 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 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 + basic_string& priv_assign_dispatch(Integer n, Integer x, containers_detail::true_) + { return this->assign((size_type) n, (CharT) x); } + + template + basic_string& priv_assign_dispatch(InputIter f, InputIter l, + containers_detail::false_) + { + size_type cur = 0; + CharT *ptr = containers_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 + void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) + { + for ( ; first != last; ++first, ++p) { + p = this->insert(p, *first); + } + } + + template + void priv_insert(iterator position, ForwardIter first, + ForwardIter last, std::forward_iterator_tag) + { + if (first != last) { + size_type n = std::distance(first, last); + size_type remaining = this->capacity() - this->priv_size(); + const size_type old_size = this->size(); + pointer old_start = this->priv_addr(); + bool enough_capacity = false; + std::pair 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(containers_detail::get_pointer(position + n), + containers_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 + value_type *oldbuf = containers_detail::get_pointer(old_start); + value_type *newbuf = containers_detail::get_pointer(new_start); + value_type *pos = containers_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 + void priv_insert_dispatch(iterator p, Integer n, Integer x, + containers_detail::true_) + { insert(p, (size_type) n, (CharT) x); } + + template + void priv_insert_dispatch(iterator p, InputIter first, InputIter last, + containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + priv_insert(p, first, last, Category()); + } + + template + void priv_copy(InputIterator first, InputIterator last, iterator result) + { + for ( ; first != last; ++first, ++result) + Traits::assign(*result, *first); + } + + void priv_copy(const CharT* first, const CharT* last, CharT* result) + { Traits::copy(result, first, last - first); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + Integer n, Integer x, + containers_detail::true_) + { return this->replace(first, last, (size_type) n, (CharT) x); } + + template + basic_string& priv_replace_dispatch(iterator first, iterator last, + InputIter f, InputIter l, + containers_detail::false_) + { + typedef typename std::iterator_traits::iterator_category Category; + return this->priv_replace(first, last, f, l, Category()); + } + + + template + basic_string& priv_replace(iterator first, iterator last, + InputIter f, InputIter l, std::input_iterator_tag) + { + for ( ; first != last && f != l; ++first, ++f) + Traits::assign(*first, *f); + + if (f == l) + this->erase(first, last); + else + this->insert(last, f, l); + return *this; + } + + template + basic_string& priv_replace(iterator first, iterator last, + ForwardIter f, ForwardIter l, + std::forward_iterator_tag) + { + difference_type n = std::distance(f, l); + const difference_type len = last - first; + if (len >= n) { + this->priv_copy(f, l, first); + this->erase(first + n, last); + } + else { + ForwardIter m = f; + std::advance(m, len); + this->priv_copy(f, m, first); + this->insert(last, m, l); + } + return *this; + } + /// @endcond +}; + +/// @cond + +template +const typename basic_string::size_type +basic_string::npos + = (typename basic_string::size_type) -1; + +/// @endcond + +// ------------------------------------------------------------ +// Non-member functions. + +// Operator+ + +template +inline basic_string +operator+(const basic_string& x, + const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + y.size(), x.alloc()); + result.append(x); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) + operator+( + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const basic_string& y) +{ + mx += y; + return boost::interprocess::move(mx); +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) + operator+(const basic_string& x, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return my.replace(size_type(0), size_type(0), x); +} + +template +inline basic_string +operator+(const CharT* s, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, n + y.size()); + result.append(s, s + n); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(const CharT* s, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return boost::interprocess::move(my.get().replace(size_type(0), size_type(0), s)); +} + +template +inline basic_string +operator+(CharT c, const basic_string& y) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, 1 + y.size()); + result.push_back(c); + result.append(y); + return result; +} + +template inline +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(CharT c, + BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) my) +{ + typedef typename basic_string::size_type size_type; + return my.replace(size_type(0), size_type(0), &c, &c + 1); +} + +template +inline basic_string +operator+(const basic_string& x, const CharT* s) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + const std::size_t n = Traits::length(s); + str_t result(reserve, x.size() + n, x.alloc()); + result.append(x); + result.append(s, s + n); + return result; +} + +template +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+(BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const CharT* s) +{ + mx += s; + return boost::interprocess::move(mx); +} + +template +inline basic_string +operator+(const basic_string& x, const CharT c) +{ + typedef basic_string str_t; + typedef typename str_t::reserve_t reserve_t; + reserve_t reserve; + str_t result(reserve, x.size() + 1, x.alloc()); + result.append(x); + result.push_back(c); + return result; +} + +template +BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) +operator+( BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(basic_string, CharT, Traits, A) mx + , const CharT c) +{ + mx += c; + return boost::interprocess::move(mx); +} + +// Operator== and operator!= + +template +inline bool +operator==(const basic_string& x, + const basic_string& y) +{ + return x.size() == y.size() && + Traits::compare(x.data(), y.data(), x.size()) == 0; +} + +template +inline bool +operator==(const CharT* s, const basic_string& y) +{ + std::size_t n = Traits::length(s); + return n == y.size() && Traits::compare(s, y.data(), n) == 0; +} + +template +inline bool +operator==(const basic_string& x, const CharT* s) +{ + std::size_t n = Traits::length(s); + return x.size() == n && Traits::compare(x.data(), s, n) == 0; +} + +template +inline bool +operator!=(const basic_string& x, + const basic_string& y) + { return !(x == y); } + +template +inline bool +operator!=(const CharT* s, const basic_string& y) + { return !(s == y); } + +template +inline bool +operator!=(const basic_string& x, const CharT* s) + { return !(x == s); } + + +// Operator< (and also >, <=, and >=). + +template +inline bool +operator<(const basic_string& x, const basic_string& y) +{ + return x.compare(y) < 0; +// return basic_string +// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const CharT* s, const basic_string& y) +{ + return y.compare(s) > 0; +// std::size_t n = Traits::length(s); +// return basic_string +// ::s_compare(s, s + n, y.begin(), y.end()) < 0; +} + +template +inline bool +operator<(const basic_string& x, + const CharT* s) +{ + return x.compare(s) < 0; +// std::size_t n = Traits::length(s); +// return basic_string +// ::s_compare(x.begin(), x.end(), s, s + n) < 0; +} + +template +inline bool +operator>(const basic_string& x, + const basic_string& y) { + return y < x; +} + +template +inline bool +operator>(const CharT* s, const basic_string& y) { + return y < s; +} + +template +inline bool +operator>(const basic_string& x, const CharT* s) +{ + return s < x; +} + +template +inline bool +operator<=(const basic_string& x, + const basic_string& y) +{ + return !(y < x); +} + +template +inline bool +operator<=(const CharT* s, const basic_string& y) + { return !(y < s); } + +template +inline bool +operator<=(const basic_string& x, const CharT* s) + { return !(s < x); } + +template +inline bool +operator>=(const basic_string& x, + const basic_string& y) + { return !(x < y); } + +template +inline bool +operator>=(const CharT* s, const basic_string& y) + { return !(s < y); } + +template +inline bool +operator>=(const basic_string& x, const CharT* s) + { return !(x < s); } + +// Swap. +template +inline void swap(basic_string& x, basic_string& y) +{ x.swap(y); } + +/// @cond +// I/O. +namespace containers_detail { + +template +inline bool +string_fill(std::basic_ostream& os, + std::basic_streambuf* buf, + std::size_t n) +{ + CharT f = os.fill(); + std::size_t i; + bool ok = true; + + for (i = 0; i < n; i++) + ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); + return ok; +} + +} //namespace containers_detail { +/// @endcond + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const basic_string& s) +{ + typename std::basic_ostream::sentry sentry(os); + bool ok = false; + + if (sentry) { + ok = true; + std::size_t n = s.size(); + std::size_t pad_len = 0; + const bool left = (os.flags() & std::ios::left) != 0; + const std::size_t w = os.width(0); + std::basic_streambuf* buf = os.rdbuf(); + + if (w != 0 && n < w) + pad_len = w - n; + + if (!left) + ok = containers_detail::string_fill(os, buf, pad_len); + + ok = ok && + buf->sputn(s.data(), std::streamsize(n)) == std::streamsize(n); + + if (left) + ok = ok && containers_detail::string_fill(os, buf, pad_len); + } + + if (!ok) + os.setstate(std::ios_base::failbit); + + return os; +} + + +template +std::basic_istream& +operator>>(std::basic_istream& is, basic_string& s) +{ + typename std::basic_istream::sentry sentry(is); + + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + const std::ctype& ctype = std::use_facet >(is.getloc()); + + s.clear(); + std::size_t n = is.width(0); + if (n == 0) + n = static_cast(-1); + else + s.reserve(n); + + while (n-- > 0) { + typename Traits::int_type c1 = buf->sbumpc(); + + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + CharT c = Traits::to_char_type(c1); + + if (ctype.is(std::ctype::space, c)) { + if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) + is.setstate(std::ios_base::failbit); + break; + } + else + s.push_back(c); + } + } + + // If we have read no characters, then set failbit. + if (s.size() == 0) + is.setstate(std::ios_base::failbit); + } + else + is.setstate(std::ios_base::failbit); + + return is; +} + +template +std::basic_istream& +getline(std::istream& is, basic_string& s,CharT delim) +{ + std::size_t nread = 0; + typename std::basic_istream::sentry sentry(is, true); + if (sentry) { + std::basic_streambuf* buf = is.rdbuf(); + s.clear(); + + int c1; + while (nread < s.max_size()) { + int c1 = buf->sbumpc(); + if (Traits::eq_int_type(c1, Traits::eof())) { + is.setstate(std::ios_base::eofbit); + break; + } + else { + ++nread; + CharT c = Traits::to_char_type(c1); + if (!Traits::eq(c, delim)) + s.push_back(c); + else + break; // Character is extracted but not appended. + } + } + } + if (nread == 0 || nread >= s.max_size()) + is.setstate(std::ios_base::failbit); + + return is; +} + +template +inline std::basic_istream& +getline(std::basic_istream& is, basic_string& s) +{ + return getline(is, s, '\n'); +} + +template +inline std::size_t hash_value(basic_string, A> const& v) +{ + return hash_range(v.begin(), v.end()); +} + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +}} + +/// @endcond + +#include + +#endif // BOOST_CONTAINERS_STRING_HPP diff --git a/include/boost/interprocess/containers/container/vector.hpp b/include/boost/interprocess/containers/container/vector.hpp new file mode 100644 index 0000000..4c38e25 --- /dev/null +++ b/include/boost/interprocess/containers/container/vector.hpp @@ -0,0 +1,1933 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +// +// This 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_CONTAINERS_CONTAINERS_VECTOR_HPP +#define BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED +namespace boost { +namespace interprocess { +#else +namespace boost { +namespace interprocess_container { +#endif + +/// @cond + +namespace containers_detail { + +//! Const vector_iterator used to iterate through a vector. +template +class vector_const_iterator + : public std::iterator::value_type + ,typename std::iterator_traits::difference_type + ,typename boost::pointer_to_other + ::value_type + >::type + ,const typename std::iterator_traits::value_type &> +{ + public: + typedef const typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename boost::pointer_to_other::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 containers_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 vector_iterator + : public vector_const_iterator +{ + public: + explicit vector_iterator(Pointer ptr) + : vector_const_iterator(ptr) + {} + + public: + typedef typename std::iterator_traits::value_type value_type; + typedef typename vector_const_iterator::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 containers_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& right) const + { return static_cast&>(*this) - right; } +}; + +template +struct vector_value_traits +{ + typedef T value_type; + typedef A allocator_type; + static const bool trivial_dctr = boost::has_trivial_destructor::value; + static const bool trivial_dctr_after_move = + boost::interprocess::has_trivial_destructor_after_move::value || trivial_dctr; + static const bool trivial_copy = has_trivial_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value; + static const bool trivial_assign = has_trivial_assign::value; + static const bool nothrow_assign = has_nothrow_assign::value; + + //This is the anti-exception array destructor + //to deallocate values already constructed + typedef typename containers_detail::if_c + + ,containers_detail::scoped_destructor_n + >::type OldArrayDestructor; + //This is the anti-exception array destructor + //to destroy objects created with copy construction + typedef typename containers_detail::if_c + + ,containers_detail::scoped_destructor_n + >::type UCopiedArrayDestructor; + //This is the anti-exception array deallocator + typedef typename containers_detail::if_c + + ,containers_detail::scoped_array_deallocator + >::type UCopiedArrayDeallocator; +}; + +//!This struct deallocates and allocated memory +template +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_traits; + + //Constructor, does not throw + vector_alloc_holder(const A &a) + : members_(a) + {} + + //Constructor, does not throw + vector_alloc_holder(const vector_alloc_holder &h) + : members_(h.alloc()) + {} + + //Destructor + ~vector_alloc_holder() + { + this->prot_destroy_all(); + this->prot_deallocate(); + } + + typedef containers_detail::integral_constant allocator_v1; + typedef containers_detail::integral_constant allocator_v2; + typedef containers_detail::integral_constant::value> alloc_version; + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, const pointer &reuse = 0) + { + return allocation_command(command, limit_size, preferred_size, + received_size, reuse, alloc_version()); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v1) + { + (void)limit_size; + (void)reuse; + if(!(command & allocate_new)) + return std::pair(pointer(0), 0); + received_size = preferred_size; + return std::make_pair(this->alloc().allocate(received_size), false); + } + + std::pair + allocation_command(allocation_type command, + size_type limit_size, + size_type preferred_size, + size_type &received_size, + const pointer &reuse, + allocator_v2) + { + return 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) + containers_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(containers_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 containers_detail { +/// @endcond + +//! \class ::boost::interprocess::vector boost/interprocess/containers/container/vector.hpp +//! 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_container::vector is similar to std::vector but it's compatible +//! with shared memory and memory mapped files. +template +class vector : private containers_detail::vector_alloc_holder +{ + /// @cond + typedef vector self_t; + typedef containers_detail::vector_alloc_holder 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 containers_detail::vector_iterator iterator; + //! The random access const_iterator + typedef containers_detail::vector_const_iterator const_iterator; + + //! Iterator used to iterate backwards through a vector. + typedef std::reverse_iterator + reverse_iterator; + //! Const iterator used to iterate backwards through a vector. + typedef std::reverse_iterator + const_reverse_iterator; + //! The stored allocator type + typedef allocator_type stored_allocator_type; + + /// @cond + private: + typedef containers_detail::advanced_insert_aux_int advanced_insert_aux_int_t; + typedef containers_detail::vector_value_traits 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 cvalue_iterator; + typedef repeat_iterator repeat_it; + typedef boost::interprocess::move_iterator repeat_move_it; + /// @endcond + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(vector) + + //! Effects: Constructs a vector taking the allocator as parameter. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + explicit vector(const A& a = A()) + : base_t(a) + {} + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n default contructed values. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n) + : base_t(allocator_type()) + { this->resize(n); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's default or copy constructor throws. + //! + //! Complexity: 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); } + + //! Effects: Copy constructs a vector. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + vector(const vector& x) + : base_t((base_t&)x) + { *this = x; } + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + vector(BOOST_INTERPROCESS_RV_REF(vector) mx) + : base_t(boost::interprocess::move(mx)) + { this->swap(mx); } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the vector. + //! + //! Throws: If allocator_type's default constructor or copy constructor + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + vector(InIt first, InIt last, const allocator_type& a = allocator_type()) + : base_t(a) + { this->assign(first, last); } + + //! Effects: Destroys the vector. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + ~vector() + {} //vector_alloc_holder clears the data + + //! Effects: Returns an iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator begin() + { return iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator begin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns an iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + iterator end() + { return iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator end() const + { return this->cend(); } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rbegin() + { return reverse_iterator(this->end()); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rbegin()const + { return this->crbegin(); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reverse_iterator rend() + { return reverse_iterator(this->begin()); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator rend() const + { return this->crend(); } + + //! Effects: Returns a const_iterator to the first element contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cbegin() const + { return const_iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the end of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_iterator cend() const + { return const_iterator(this->members_.m_start + this->members_.m_size); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crbegin()const + { return const_reverse_iterator(this->end());} + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reverse_iterator crend() const + { return const_reverse_iterator(this->begin()); } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference front() + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference front() const + { return *this->members_.m_start; } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference back() + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference back() const + { return this->members_.m_start[this->members_.m_size - 1]; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + pointer data() + { return this->members_.m_start; } + + //! Returns: A pointer such that [data(),data() + size()) is a valid range. + //! For a non-empty vector, data() == &front(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_pointer data() const + { return this->members_.m_start; } + + //! Effects: Returns the number of the elements contained in the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type size() const + { return this->members_.m_size; } + + //! Effects: Returns the largest possible size of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type max_size() const + { return this->alloc().max_size(); } + + //! Effects: Number of elements for which memory has been allocated. + //! capacity() is always greater than or equal to size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + size_type capacity() const + { return this->members_.m_capacity; } + + //! Effects: Returns true if the vector contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + bool empty() const + { return !this->members_.m_size; } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + reference operator[](size_type n) + { return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + const_reference operator[](size_type n) const + { return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + reference at(size_type n) + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Requires: size() < n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + const_reference at(size_type n) const + { this->priv_check_range(n); return this->members_.m_start[n]; } + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: 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(); } + + //! Effects: 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. + //! + //! Throws: 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 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_CONTAINERS_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(containers_detail::get_pointer(this->members_.m_start)); + containers_detail::advanced_insert_aux_proxy, T*> + proxy(boost::interprocess::make_move_iterator(dummy_it), boost::interprocess::make_move_iterator(dummy_it)); + //Backwards (and possibly forward) expansion + if(ret.second){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(this->members_.m_start) + , 0 + , proxy); + } + //New buffer + else{ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(this->members_.m_start) + , 0 + , proxy); + } + } + } + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + vector& operator=(const vector& x) + { + if (&x != this){ + this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); + } + return *this; + } + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + vector& operator=(BOOST_INTERPROCESS_RV_REF(vector) x) + { + if (&x != this){ + this->swap(x); + x.clear(); + } + return *this; + } + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void assign(size_type n, const value_type& val) + { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InpIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_assign_dispatch(first, last, Result()); + } + + //! Effects: Inserts a copy of x at the end of the vector. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: 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*)(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size))value_type(x); + ++this->members_.m_size; + } + else{ + this->insert(this->cend(), x); + } + } + + //! Effects: Constructs a new element in the end of the vector + //! and moves the resources of mx to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(BOOST_INTERPROCESS_RV_REF(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*)containers_detail::get_pointer(this->members_.m_start + this->members_.m_size))value_type(boost::interprocess::move(x)); + ++this->members_.m_size; + } + else{ + this->insert(this->cend(), boost::interprocess::move(x)); + } + } + + #if defined(BOOST_CONTAINERS_PERFECT_FORWARDING) || defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the vector. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time. + template + void emplace_back(Args &&...args) + { + T* back_pos = containers_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::interprocess::forward(args)...); + ++this->members_.m_size; + } + else{ + containers_detail::advanced_insert_aux_emplace proxy + (boost::interprocess::forward(args)...); + priv_range_insert(back_pos, 1, proxy); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before position + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator position, Args && ...args) + { + //Just call more general insert(pos, size, value) and return iterator + size_type pos_n = position - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy + (boost::interprocess::forward(args)...); + priv_range_insert(position.get_ptr(), 1, proxy); + return iterator(this->members_.m_start + pos_n); + } + + #else + + void emplace_back() + { + T* back_pos = containers_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{ + containers_detail::advanced_insert_aux_emplace proxy; + priv_range_insert(back_pos, 1, proxy); + } + } + + iterator emplace(const_iterator position) + { + size_type pos_n = position - cbegin(); + containers_detail::advanced_insert_aux_emplace proxy; + priv_range_insert(containers_detail::get_pointer(position.get_ptr()), 1, proxy); + return iterator(this->members_.m_start + pos_n); + } + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + T* back_pos = containers_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_CONTAINERS_PP_PARAM_FORWARD, _)); \ + ++this->members_.m_size; \ + } \ + else{ \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(back_pos, 1, proxy); \ + } \ + } \ + \ + template \ + iterator emplace(const_iterator pos, BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_LIST, _)) \ + { \ + size_type pos_n = pos - cbegin(); \ + containers_detail::BOOST_PP_CAT(BOOST_PP_CAT(advanced_insert_aux_emplace, n), arg) \ + \ + proxy(BOOST_PP_ENUM(n, BOOST_CONTAINERS_PP_PARAM_FORWARD, _)); \ + priv_range_insert(containers_detail::get_pointer(pos.get_ptr()), 1, proxy); \ + return iterator(this->members_.m_start + pos_n); \ + } \ + //! + #define BOOST_PP_LOCAL_LIMITS (1, BOOST_CONTAINERS_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + + #endif //#ifdef BOOST_CONTAINERS_PERFECT_FORWARDING + + //! Effects: Swaps the contents of *this and x. + //! If this->allocator_type() != x.allocator_type() + //! allocators are also swapped. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + void swap(vector& x) + { + allocator_type &this_al = this->alloc(), &other_al = x.alloc(); + //Just swap internals + containers_detail::do_swap(this->members_.m_start, x.members_.m_start); + containers_detail::do_swap(this->members_.m_size, x.members_.m_size); + containers_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); + + if (this_al != other_al){ + containers_detail::do_swap(this_al, other_al); + } + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before position. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: 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); + } + + //! Requires: position must be a valid iterator of *this. + //! + //! Effects: Insert a new element before position with mx's resources. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If position is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator position, BOOST_INTERPROCESS_RV_REF(T) x) + { + //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); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InpIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to std::distance [first, last). + template + void insert(const_iterator pos, InIt first, InIt last) + { + //Dispatch depending on integer/iterator + const bool aux_boolean = containers_detail::is_convertible::value; + typedef containers_detail::bool_ Result; + this->priv_insert_dispatch(pos, first, last, Result()); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + void insert(const_iterator p, size_type n, const T& x) + { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } + + //! Effects: Removes the last element from the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() + { + //Destroy last element + --this->members_.m_size; + this->destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + } + + //! Effects: Erases the element at position pos. + //! + //! Throws: Nothing. + //! + //! Complexity: 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 = containers_detail::get_pointer(position.get_ptr()); + T *beg = containers_detail::get_pointer(this->members_.m_start); + boost::interprocess::move(pos + 1, beg + this->members_.m_size, pos); + --this->members_.m_size; + //Destroy last element + base_t::destroy(containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size); + return iterator(position.get_ptr()); + } + + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: 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 = containers_detail::get_pointer(this->members_.m_start) + this->members_.m_size; + T* ptr = containers_detail::get_pointer(boost::interprocess::move + (containers_detail::get_pointer(last.get_ptr()) + ,end_pos + ,containers_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()); + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default constructed. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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); + containers_detail::default_construct_aux_proxy proxy(n); + priv_range_insert(this->cend().get_ptr(), n, proxy); + } + } + + //! Effects: Erases all the elements of the vector. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the vector. + void clear() + { this->prot_destroy_all(); } + + /// @cond + + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the vector is unchanged + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: 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(*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_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_shrink; + #endif + } + } + } + } + + template + 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); + containers_detail::advanced_insert_aux_proxy 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 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_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->priv_range_insert_expand_forward + (containers_detail::get_pointer(pos), n, interf); + } + //Backwards (and possibly forward) expansion + else if(ret.second){ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_range_insert_expand_backwards + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_detail::get_pointer(pos) + , n + , interf); + } + //New buffer + else{ + #ifdef BOOST_CONTAINERS_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_range_insert_new_allocation + ( containers_detail::get_pointer(ret.first) + , real_cap + , containers_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 = containers_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::interprocess::uninitialized_move(old_finish - n, old_finish, old_finish); + this->members_.m_size += n; + //Copy previous to last objects to the initialized end + boost::interprocess::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::interprocess::uninitialized_move + ( pos, old_finish, containers_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::interprocess::uninitialized_move + (containers_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::interprocess::uninitialized_move + ( pos, containers_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(containers_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 = containers_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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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::interprocess::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 + void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) + { + for(;first != last; ++first){ + this->insert(pos, boost::interprocess::move(value_type(*first))); + } + } + + template + void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) + { + //Overwrite all elements we can from [first, last) + iterator cur = begin(); + for ( ; first != last && cur != end(); ++cur, ++first){ + *cur = *first; + } + + if (first == last){ + //There are no more elements in the sequence, erase remaining + this->erase(cur, cend()); + } + else{ + //There are more elements in the range, insert the remaining ones + this->insert(this->cend(), first, last); + } + } + + template + void priv_assign_aux(FwdIt first, FwdIt last, std::forward_iterator_tag) + { + size_type n = std::distance(first, last); + //Check if we have enough memory or try to expand current memory + size_type remaining = this->members_.m_capacity - this->members_.m_size; + bool same_buffer_start; + std::pair 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 = containers_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::interprocess::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, containers_detail::get_pointer(ret.first)); + boost::interprocess::uninitialized_copy_or_move(first, last, containers_detail::get_pointer(ret.first)); + scoped_alloc.release(); + //Destroy and deallocate old buffer + if(this->members_.m_start != 0){ + this->destroy_n(containers_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 = containers_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 - containers_detail::get_pointer(ret.first); + size_type first_count = containers_detail::min_value(n, old_offset); + + FwdIt mid = first; + std::advance(mid, first_count); + // iG std::uninitialized_copy(first, mid, containers_detail::get_pointer(ret.first)); + boost::interprocess::uninitialized_copy_or_move(first, mid, containers_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 = containers_detail::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 + void priv_assign_dispatch(Integer n, Integer val, containers_detail::true_) + { this->assign((size_type) n, (T) val); } + + template + void priv_assign_dispatch(InIt first, InIt last, containers_detail::false_) + { + //Dispatch depending on integer/iterator + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_assign_aux(first, last, ItCat()); + } + + template + void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, containers_detail::true_) + { this->insert(pos, (size_type)n, (T)val); } + + template + void priv_insert_dispatch(const_iterator pos, InIt first, + InIt last, containers_detail::false_) + { + //Dispatch depending on integer/iterator + typedef typename std::iterator_traits::iterator_category ItCat; + this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); + } + + void priv_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_CONTAINERS_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 +inline bool +operator==(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator!=(const vector& x, const vector& y) +{ + //Check first size and each element if needed + return x.size() != y.size() || !std::equal(x.begin(), x.end(), y.begin()); +} + +template +inline bool +operator<(const vector& x, const vector& y) +{ + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); +} + +template +inline void swap(vector& x, vector& y) +{ x.swap(y); } + +}} + +/// @cond + +namespace boost { +namespace interprocess { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + static const bool value = has_trivial_destructor::value; +}; + +}} + +/// @endcond + +#include + +#endif // #ifndef BOOST_CONTAINERS_CONTAINERS_VECTOR_HPP + diff --git a/include/boost/interprocess/containers/deque.hpp b/include/boost/interprocess/containers/deque.hpp index e820596..249fda6 100644 --- a/include/boost/interprocess/containers/deque.hpp +++ b/include/boost/interprocess/containers/deque.hpp @@ -1,1538 +1,32 @@ -/* - * - * 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 +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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 +#ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond -template -class deque; - -template -struct deque_value_traits -{ - typedef T value_type; - typedef A allocator_type; - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::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 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 - ::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::other allocator_type; - typedef allocator_type stored_allocator_type; - - protected: - - typedef deque_value_traits traits_t; - typedef typename Alloc::template - rebind::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 - { - public: - static std::size_t s_buffer_size() { return deque_base::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; - friend class deque_base; - - protected: - val_alloc_ptr m_cur; - val_alloc_ptr m_first; - val_alloc_ptr m_last; - index_pointer m_node; - - public: - const_iterator(val_alloc_ptr x, index_pointer y) - : m_cur(x), m_first(*y), - m_last(*y + s_buffer_size()), m_node(y) {} - - const_iterator() : m_cur(0), m_first(0), m_last(0), m_node(0) {} - - const_iterator(const const_iterator& x) - : m_cur(x.m_cur), m_first(x.m_first), - m_last(x.m_last), m_node(x.m_node) {} - - reference operator*() const - { return *this->m_cur; } - - pointer operator->() const - { return this->m_cur; } - - difference_type operator-(const self_t& x) const - { - 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; - friend class deque_base; - - private: - explicit iterator(const const_iterator& x) : const_iterator(x){} - - public: - //Constructors - iterator(val_alloc_ptr x, index_pointer y) : const_iterator(x, y){} - iterator() : const_iterator(){} - //iterator(const const_iterator &cit) : const_iterator(cit){} - iterator(const iterator& x) : const_iterator(x){} - - //Pointer like operators - reference operator*() const { return *this->m_cur; } - pointer operator->() const { return this->m_cur; } - - reference operator[](difference_type n) const { return *(*this + n); } - - //Increment / Decrement - iterator& operator++() - { this->const_iterator::operator++(); return *this; } - - iterator operator++(int) - { iterator tmp = *this; ++*this; return tmp; } - - iterator& operator--() - { this->const_iterator::operator--(); return *this; } - - iterator operator--(int) - { iterator tmp = *this; --*this; return tmp; } - - // Arithmetic - iterator& operator+=(difference_type off) - { this->const_iterator::operator+=(off); return *this; } - - iterator operator+(difference_type off) const - { return iterator(this->const_iterator::operator+(off)); } - - friend iterator operator+(difference_type off, const iterator& right) - { return iterator(off+static_cast(right)); } - - iterator& operator-=(difference_type off) - { this->const_iterator::operator-=(off); return *this; } - - iterator operator-(difference_type off) const - { return iterator(this->const_iterator::operator-(off)); } - - difference_type operator-(const const_iterator& right) const - { return static_cast(*this) - right; } - }; - - deque_base(const allocator_type& a, std::size_t num_elements) - : 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 deque : protected deque_base -{ - /// @cond - typedef deque_base Base; - - public: // Basic types - typedef typename Alloc::value_type val_alloc_val; - typedef typename Alloc::pointer val_alloc_ptr; - typedef typename Alloc::const_pointer val_alloc_cptr; - typedef typename Alloc::reference val_alloc_ref; - typedef typename Alloc::const_reference val_alloc_cref; - typedef typename Alloc::template - rebind::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_reverse_iterator; - typedef std::reverse_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 advanced_insert_aux_int_t; - typedef repeat_iterator r_iterator; - typedef detail::move_iterator move_it; - - /// @endcond - - allocator_type get_allocator() const { return Base::alloc(); } - - public: // Basic accessors - 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - deque(detail::moved_object 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 - 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::value; - typedef detail::bool_ 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - deque& operator= (detail::moved_object mx) - { - deque &x = mx.get(); - #else - deque& operator= (deque &&x) - { - #endif - this->clear(); - this->swap(x); - return *this; - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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 - void assign(InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back(detail::moved_object 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(detail::move_impl(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object 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(detail::move_impl(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object m) - { - value_type &mx = m.get(); - #else - iterator insert(const_iterator position, value_type &&mx) - { - #endif - if (position == cbegin()) { - this->push_front(detail::move_impl(mx)); - return begin(); - } - else if (position == cend()) { - this->push_back(detail::move_impl(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 - void insert(const_iterator pos, InpIt first, InpIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - void emplace_back(Args&&... args) - { - if(this->priv_push_back_simple_available()){ - new(this->priv_push_back_simple_pos())value_type(detail::forward_impl(args)...); - this->priv_push_back_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(this->cend(), 1, proxy); - } - } - - template - void emplace_front(Args&&... args) - { - if(this->priv_push_front_simple_available()){ - new(this->priv_push_front_simple_pos())value_type(detail::forward_impl(args)...); - this->priv_push_front_simple_commit(); - } - else{ - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(args)...); - this->priv_insert_aux_impl(this->cbegin(), 1, proxy); - } - } - - template - iterator emplace(const_iterator p, Args&&... args) - { - if(p == this->cbegin()){ - this->emplace_front(detail::forward_impl(args)...); - return this->begin(); - } - else if(p == this->cend()){ - this->emplace_back(detail::forward_impl(args)...); - return (this->end()-1); - } - else{ - size_type n = p - this->cbegin(); - detail::advanced_insert_aux_emplace proxy(detail::forward_impl(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 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 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 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 \ - 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) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_insert_aux_impl(cend(), 1, proxy); \ - } \ - } \ - \ - template \ - 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) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_insert_aux_impl(cbegin(), 1, proxy); \ - } \ - } \ - \ - template \ - 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) \ - \ - 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 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)) { - std::copy_backward( detail::make_move_iterator(begin()) - , detail::make_move_iterator(iterator(pos)) - , iterator(next)); - pop_front(); - } - else { - std::copy( detail::make_move_iterator(iterator(next)) - , detail::make_move_iterator(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(this->size() - n) - elems_before) { - std::copy_backward( detail::make_move_iterator(begin()) - , detail::make_move_iterator(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 { - std::copy( detail::make_move_iterator(iterator(last)) - , detail::make_move_iterator(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(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(detail::get_pointer(this->members_.m_start.m_cur) - 1); } - - void priv_push_front_simple_commit() - { --this->members_.m_start.m_cur; } - - template - void priv_insert_aux(const_iterator pos, InpIt first, InpIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, move_impl(value_type(*first))); - } - } - - template - 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 - void priv_initialize_dispatch(Integer n, Integer x, detail::true_) - { - this->priv_initialize_map(n); - this->priv_fill_initialize(x); - } - - template - void priv_initialize_dispatch(InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_range_initialize(first, last, ItCat()); - } - - void priv_destroy_range(iterator p, iterator p2) - { - for(;p != p2; ++p) - 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 - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_assign_aux(InpIt first, InpIt last, std::input_iterator_tag) - { - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first) - *cur = *first; - if (first == last) - this->erase(cur, cend()); - else - this->insert(cend(), first, last); - } - - template - 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 - 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 - void priv_insert_dispatch(const_iterator pos,InpIt first, InpIt last, detail::false_) - { - typedef typename std::iterator_traits::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 c_it; - this->priv_insert_aux(pos, c_it(x, n), c_it()); - } - - //Just forward all operations to priv_insert_aux_impl - template - void priv_insert_aux(const_iterator p, FwdIt first, FwdIt last) - { - detail::advanced_insert_aux_proxy 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(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); - std::uninitialized_copy(detail::make_move_iterator(this->members_.m_start), detail::make_move_iterator(start_n), new_start); - this->members_.m_start = new_start; - std::copy(detail::make_move_iterator(start_n), detail::make_move_iterator(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; - std::uninitialized_copy(detail::make_move_iterator(old_start), detail::make_move_iterator(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); - std::uninitialized_copy(detail::make_move_iterator(finish_n), detail::make_move_iterator(this->members_.m_finish), this->members_.m_finish); - this->members_.m_finish = new_finish; - std::copy_backward(detail::make_move_iterator(pos), detail::make_move_iterator(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; - std::uninitialized_copy(detail::make_move_iterator(pos), detail::make_move_iterator(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 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 - void priv_range_initialize(InpIt first, InpIt last, std::input_iterator_tag) - { - this->priv_initialize_map(0); - BOOST_TRY { - for ( ; first != last; ++first) - this->push_back(*first); - } - BOOST_CATCH(...){ - this->clear(); - BOOST_RETHROW - } - BOOST_CATCH_END - } - - template - void priv_range_initialize(FwdIt first, FwdIt last, std::forward_iterator_tag) - { - size_type n = 0; - n = std::distance(first, last); - this->priv_initialize_map(n); - - index_pointer cur_node; - BOOST_TRY { - for (cur_node = this->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()); - std::uninitialized_copy(first, mid, *cur_node); - first = mid; - } - std::uninitialized_copy(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) - std::copy(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); - else - std::copy_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); - std::copy(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 -inline bool operator==(const deque& x, - const deque& y) -{ - return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool operator<(const deque& x, - const deque& y) -{ - return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); -} - -template -inline bool operator!=(const deque& x, - const deque& y) - { return !(x == y); } - -template -inline bool operator>(const deque& x, - const deque& y) - { return y < x; } - -template -inline bool operator<=(const deque& x, - const deque& y) - { return !(y < x); } - -template -inline bool operator>=(const deque& x, - const deque& y) - { return !(x < y); } - - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(deque& x, deque& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, deque& y) -{ x.get().swap(y); } - -template -inline void swap(deque &x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(deque&&x, deque&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::deque; } //namespace interprocess { } //namespace boost { #include -#endif // #ifndef BOOST_INTERPROCESS_DEQUE_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_DEQUE_HPP diff --git a/include/boost/interprocess/containers/flat_map.hpp b/include/boost/interprocess/containers/flat_map.hpp index 3649906..4129bbb 100644 --- a/include/boost/interprocess/containers/flat_map.hpp +++ b/include/boost/interprocess/containers/flat_map.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -8,1434 +8,25 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_MAP_HPP -#define BOOST_INTERPROCESS_FLAT_MAP_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { -namespace boost { namespace interprocess { +using boost::interprocess_container::flat_map; +using boost::interprocess_container::flat_multimap; -/// @cond -// Forward declarations of operators == and <, needed for friend declarations. -template -class flat_map; - -template -inline bool operator==(const flat_map& x, - const flat_map& y); - -template -inline bool operator<(const flat_map& x, - const flat_map& y); -/// @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 the key_type is Key and the value_type is std::pair -//! (unlike std::map which value_type is std::pair<const Key, T>). -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -//! -//! 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 flat_map -{ - /// @cond - private: - //This is the tree that we should store if pair was movable - typedef detail::flat_tree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - //This is the real tree stored here. It's based on a movable pair - typedef detail::flat_tree, - detail::select1st< detail::pair >, - Pred, - typename Alloc::template - rebind >::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_INTERPROCESS_RVALUE_REFERENCE - typedef detail::moved_object impl_moved_value_type; - #endif - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &force(const S &s) - { return *const_cast(reinterpret_cast(&s)); } - - template - static D force_copy(S s) - { - value_type *vp = reinterpret_cast(&*s); - return D(vp); - } - - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::value_compare value_compare; - typedef T mapped_type; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_map using the specified - //! comparison object and allocator. - //! - //! Complexity: Constant. - explicit flat_map(const Pred& comp = Pred(), const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) {} - - //! Effects: Constructs an empty flat_map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_map(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) - { m_flat_tree.insert_unique(first, last); } - - //! Effects: Copy constructs a flat_map. - //! - //! Complexity: Linear in x.size(). - flat_map(const flat_map& x) - : m_flat_tree(x.m_flat_tree) {} - - //! Effects: Move constructs a flat_map. - //! Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_map(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} - - #else - flat_map(flat_map && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_map& operator=(const flat_map& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: Move constructs a flat_map. - //! Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_map& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_map& operator=(flat_map && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return force(m_flat_tree.key_comp()); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(force(m_flat_tree.key_comp())); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return force(m_flat_tree.get_allocator()); } - - const stored_allocator_type &get_stored_allocator() const - { return force(m_flat_tree.get_stored_allocator()); } - - stored_allocator_type &get_stored_allocator() - { return force(m_flat_tree.get_stored_allocator()); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return force_copy(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return force(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return force(m_flat_tree.cbegin()); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return force_copy(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return force(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return force(m_flat_tree.cend()); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return force(m_flat_tree.crbegin()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return force(m_flat_tree.crend()); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - T &operator[](detail::moved_object 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, detail::move_impl(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(detail::forward_impl(k), detail::move_impl(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; - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - std::pair insert(const value_type& x) - { return force >( - m_flat_tree.insert_unique(force(x))); } - - //! Effects: 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. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return force >( - m_flat_tree.insert_unique(force(x))); } - #else - std::pair insert(value_type &&x) - { return force >( - m_flat_tree.insert_unique(detail::move_impl(force(x)))); } - #endif - - //! Effects: 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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return force_copy( - m_flat_tree.insert_unique(force(position), force(x))); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return force_copy( - m_flat_tree.insert_unique(force(position), force(x))); } - #else - iterator insert(const_iterator position, value_type &&x) - { return force_copy( - m_flat_tree.insert_unique(force(position), detail::move_impl(force(x)))); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: 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. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return force_copy(m_flat_tree.emplace_unique(detail::forward_impl(args)...)); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return force_copy(m_flat_tree.emplace_hint_unique(force(hint), detail::forward_impl(args)...)); } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return force_copy(m_flat_tree.emplace_unique()); } - - iterator emplace_hint(const_iterator hint) - { return force_copy(m_flat_tree.emplace_hint_unique(force(hint))); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_unique \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_hint_unique \ - (force(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 - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return force_copy(m_flat_tree.erase(force(position))); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: 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); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return force_copy(m_flat_tree.erase(force(first), force(last))); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return force_copy(m_flat_tree.find(x)); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return force(m_flat_tree.find(x)); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return force_copy(m_flat_tree.lower_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return force(m_flat_tree.lower_bound(x)); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return force_copy(m_flat_tree.upper_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return force(m_flat_tree.upper_bound(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return force >(m_flat_tree.equal_range(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const - { return force >(m_flat_tree.equal_range(x)); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: 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. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: 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 - friend bool operator== (const flat_map&, - const flat_map&); - template - friend bool operator< (const flat_map&, - const flat_map&); - /// @endcond -}; - -template -inline bool operator==(const flat_map& x, - const flat_map& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_map& x, - const flat_map& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_map& x, - const flat_map& y) - { return !(x == y); } - -template -inline bool operator>(const flat_map& x, - const flat_map& y) - { return y < x; } - -template -inline bool operator<=(const flat_map& x, - const flat_map& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_map& x, - const flat_map& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_map& x, - flat_map& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, - flat_map& y) - { x.get().swap(y); } - -template -inline void swap(flat_map& x, - detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_map&&x, - flat_map&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. -template -class flat_multimap; - -template -inline bool operator==(const flat_multimap& x, - const flat_multimap& y); - -template -inline bool operator<(const flat_multimap& x, - const flat_multimap& y); -/// @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 the key_type is Key and the value_type is std::pair -//! (unlike std::multimap which value_type is std::pair<const Key, T>). -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -template -class flat_multimap -{ - /// @cond - private: - typedef detail::flat_tree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - //This is the real tree stored here. It's based on a movable pair - typedef detail::flat_tree, - detail::select1st< detail::pair >, - Pred, - typename Alloc::template - rebind >::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_INTERPROCESS_RVALUE_REFERENCE - typedef detail::moved_object impl_moved_value_type; - #endif - - //#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - static D &force(const S &s) - { return *const_cast((reinterpret_cast(&s))); } - - template - static D force_copy(S s) - { - value_type *vp = reinterpret_cast(&*s); - return D(vp); - } - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::value_compare value_compare; - typedef T mapped_type; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_multimap using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit flat_multimap(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) { } - - //! Effects: Constructs an empty flat_multimap using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_multimap(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, force(a)) - { m_flat_tree.insert_equal(first, last); } - - //! Effects: Copy constructs a flat_multimap. - //! - //! Complexity: Linear in x.size(). - flat_multimap(const flat_multimap& x) - : m_flat_tree(x.m_flat_tree) { } - - //! Effects: Move constructs a flat_multimap. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multimap(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) { } - #else - flat_multimap(flat_multimap && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) { } - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_multimap& operator=(const flat_multimap& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multimap& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_multimap& operator=(flat_multimap && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return force(m_flat_tree.key_comp()); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(force(m_flat_tree.key_comp())); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return force(m_flat_tree.get_allocator()); } - - const stored_allocator_type &get_stored_allocator() const - { return force(m_flat_tree.get_stored_allocator()); } - - stored_allocator_type &get_stored_allocator() - { return force(m_flat_tree.get_stored_allocator()); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return force_copy(m_flat_tree.begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return force(m_flat_tree.begin()); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return force_copy(m_flat_tree.end()); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return force(m_flat_tree.end()); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return force(m_flat_tree.rbegin()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return force(m_flat_tree.rend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return force(m_flat_tree.rend()); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const value_type& x) - { return force_copy(m_flat_tree.insert_equal(force(x))); } - - //! Effects: Inserts a new value move-constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return force_copy(m_flat_tree.insert_equal(force(x))); } - #else - iterator insert(value_type &&x) - { return force_copy(m_flat_tree.insert_equal(detail::move_impl(x))); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const_iterator position, const value_type& x) - { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } - - //! Effects: Inserts a value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object x) - { return force_copy(m_flat_tree.insert_equal(force(position), force(x))); } - #else - iterator insert(const_iterator position, value_type &&x) - { return force_copy(m_flat_tree.insert_equal(force(position), detail::move_impl(x))); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return force_copy(m_flat_tree.emplace_equal(detail::forward_impl(args)...)); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { - return force_copy(m_flat_tree.emplace_hint_equal - (force(hint), detail::forward_impl(args)...)); - } - - #else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - iterator emplace() - { return force_copy(m_flat_tree.emplace_equal()); } - - iterator emplace_hint(const_iterator hint) - { return force_copy(m_flat_tree.emplace_hint_equal(force(hint))); } - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - iterator emplace(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_equal \ - (BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _))); \ - } \ - \ - template \ - iterator emplace_hint(const_iterator hint, BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - { \ - return force_copy(m_flat_tree.emplace_hint_equal \ - (force(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 - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return force_copy(m_flat_tree.erase(force(position))); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: 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); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: Logarithmic search time plus erasure time - //! linear to the elements with bigger keys. - iterator erase(const_iterator first, const_iterator last) - { return force_copy(m_flat_tree.erase(force(first), force(last))); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return force_copy(m_flat_tree.find(x)); } - - //! Returns: An const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return force(m_flat_tree.find(x)); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - {return force_copy(m_flat_tree.lower_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key - //! not less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return force(m_flat_tree.lower_bound(x)); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - {return force_copy(m_flat_tree.upper_bound(x)); } - - //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return force(m_flat_tree.upper_bound(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return force_copy >(m_flat_tree.equal_range(x)); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return force_copy >(m_flat_tree.equal_range(x)); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: 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. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: 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 - friend bool operator== (const flat_multimap& x, - const flat_multimap& y); - - template - friend bool operator< (const flat_multimap& x, - const flat_multimap& y); - /// @endcond -}; - -template -inline bool operator==(const flat_multimap& x, - const flat_multimap& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_multimap& x, - const flat_multimap& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_multimap& x, - const flat_multimap& y) - { return !(x == y); } - -template -inline bool operator>(const flat_multimap& x, - const flat_multimap& y) - { return y < x; } - -template -inline bool operator<=(const flat_multimap& x, - const flat_multimap& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_multimap& x, - const flat_multimap& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_multimap& x, - flat_multimap& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, - flat_multimap& y) - { x.get().swap(y); } - - -template -inline void swap(flat_multimap& x, - detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_multimap&&x, - flat_multimap&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_FLAT_MAP_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_MAP_HPP diff --git a/include/boost/interprocess/containers/flat_set.hpp b/include/boost/interprocess/containers/flat_set.hpp index 1e3c9bf..0c38930 100644 --- a/include/boost/interprocess/containers/flat_set.hpp +++ b/include/boost/interprocess/containers/flat_set.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // @@ -8,1237 +8,25 @@ // ////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_INTERPROCESS_FLAT_SET_HPP -#define BOOST_INTERPROCESS_FLAT_SET_HPP +#ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { +using boost::interprocess_container::flat_set; +using boost::interprocess_container::flat_multiset; -namespace boost { namespace interprocess { - -/// @cond -// Forward declarations of operators < and ==, needed for friend declaration. - -template -class flat_set; - -template -inline bool operator==(const flat_set& x, - const flat_set& y); - -template -inline bool operator<(const flat_set& x, - const flat_set& y); -/// @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 flat_set -{ - /// @cond - private: - typedef detail::flat_tree, Pred, Alloc> tree_t; - tree_t m_flat_tree; // flat tree representing flat_set - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::value_compare value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty flat_map using the specified - //! comparison object and allocator. - //! - //! Complexity: Constant. - explicit flat_set(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - {} - - //! Effects: Constructs an empty map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - flat_set(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_unique(first, last); } - - //! Effects: Copy constructs a map. - //! - //! Complexity: Linear in x.size(). - flat_set(const flat_set& x) - : m_flat_tree(x.m_flat_tree) {} - - //! Effects: Move constructs a map. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_set(detail::moved_object > mx) - : m_flat_tree(detail::move_impl(mx.get().m_flat_tree)) {} - #else - flat_set(flat_set && mx) - : m_flat_tree(detail::move_impl(mx.m_flat_tree)) {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - flat_set& operator=(const flat_set& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_set& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - - #else - flat_set& operator=(flat_set &&mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: 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(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_flat_tree.cbegin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_flat_tree.cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_flat_tree.crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_flat_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - std::pair insert(const value_type& x) - { return m_flat_tree.insert_unique(x); } - - //! Effects: 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. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_flat_tree.insert_unique(x); } - #else - std::pair insert(value_type && x) - { return m_flat_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: 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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: 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); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object 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, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: 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. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return m_flat_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_flat_tree.emplace_hint_unique(hint, detail::forward_impl(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 \ - 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 \ - 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 - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return m_flat_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: 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); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: 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); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_flat_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return m_flat_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.find(x) == m_flat_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_flat_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_flat_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_flat_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_flat_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_flat_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_flat_tree.equal_range(x); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: 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. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: 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 - friend bool operator== (const flat_set&, const flat_set&); - - template - friend bool operator< (const flat_set&, const flat_set&); - /// @endcond -}; - -template -inline bool operator==(const flat_set& x, - const flat_set& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_set& x, - const flat_set& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_set& x, - const flat_set& y) - { return !(x == y); } - -template -inline bool operator>(const flat_set& x, - const flat_set& y) - { return y < x; } - -template -inline bool operator<=(const flat_set& x, - const flat_set& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_set& x, - const flat_set& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_set& x, flat_set& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, flat_set& y) - { x.get().swap(y); } - -template -inline void swap(flat_set& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_set&&x, flat_set&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -class flat_multiset; - -template -inline bool operator==(const flat_multiset& x, - const flat_multiset& y); - -template -inline bool operator<(const flat_multiset& x, - const flat_multiset& y); -/// @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 flat_multiset -{ - /// @cond - private: - typedef detail::flat_tree, Pred, Alloc> tree_t; - tree_t m_flat_tree; // flat tree representing flat_multiset - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef typename tree_t::key_compare key_compare; - typedef typename tree_t::value_compare value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - 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 - flat_multiset(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_flat_tree(comp, a) - { m_flat_tree.insert_equal(first, last); } - - flat_multiset(const flat_multiset& x) - : m_flat_tree(x.m_flat_tree) {} - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multiset(detail::moved_object > x) - : m_flat_tree(detail::move_impl(x.get().m_flat_tree)) {} - #else - flat_multiset(flat_multiset && x) - : m_flat_tree(detail::move_impl(x.m_flat_tree)) {} - #endif - - flat_multiset& operator=(const flat_multiset& x) - { m_flat_tree = x.m_flat_tree; return *this; } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - flat_multiset& operator=(detail::moved_object > mx) - { m_flat_tree = detail::move_impl(mx.get().m_flat_tree); return *this; } - #else - flat_multiset& operator=(flat_multiset && mx) - { m_flat_tree = detail::move_impl(mx.m_flat_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_flat_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: 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(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_flat_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_flat_tree.cbegin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_flat_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_flat_tree.cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_flat_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_flat_tree.crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_flat_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_flat_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_flat_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_flat_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_flat_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - iterator insert(const value_type& x) - { return m_flat_tree.insert_equal(x); } - - //! Effects: Inserts a new value_type move constructed from x - //! and returns the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return m_flat_tree.insert_equal(x); } - #else - iterator insert(value_type && x) - { return m_flat_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: 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); } - - //! Effects: Inserts a new value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object 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, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - //! search time plus N*size() insertion time. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - void insert(InputIterator first, InputIterator last) - { m_flat_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic search time plus linear insertion - //! to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace(Args&&... args) - { return m_flat_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic search time (constant if x is inserted - //! right before p) plus insertion linear to the elements with bigger keys than x. - //! - //! Note: If an element it's inserted it might invalidate elements. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_flat_tree.emplace_hint_equal(hint, detail::forward_impl(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 \ - 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 \ - 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 - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Linear to the elements with keys bigger than position - //! - //! Note: Invalidates elements with keys - //! not less than the erased element. - iterator erase(const_iterator position) - { return m_flat_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: 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); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: size()*N where N is the distance from first to last. - //! - //! Complexity: 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); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_flat_tree.clear(); } - - //! Effects: Tries to deallocate the excess of memory created - // with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to size(). - void shrink_to_fit() - { m_flat_tree.shrink_to_fit(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_flat_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic.s - const_iterator find(const key_type& x) const - { return m_flat_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_flat_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_flat_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_flat_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_flat_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_flat_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_flat_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_flat_tree.equal_range(x); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return m_flat_tree.capacity(); } - - //! Effects: 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. - //! - //! Throws: If memory allocation allocation throws or T's copy constructor throws. - //! - //! Note: 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 - friend bool operator== (const flat_multiset&, - const flat_multiset&); - template - friend bool operator< (const flat_multiset&, - const flat_multiset&); - /// @endcond -}; - -template -inline bool operator==(const flat_multiset& x, - const flat_multiset& y) - { return x.m_flat_tree == y.m_flat_tree; } - -template -inline bool operator<(const flat_multiset& x, - const flat_multiset& y) - { return x.m_flat_tree < y.m_flat_tree; } - -template -inline bool operator!=(const flat_multiset& x, - const flat_multiset& y) - { return !(x == y); } - -template -inline bool operator>(const flat_multiset& x, - const flat_multiset& y) - { return y < x; } - -template -inline bool operator<=(const flat_multiset& x, - const flat_multiset& y) - { return !(y < x); } - -template -inline bool operator>=(const flat_multiset& x, - const flat_multiset& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(flat_multiset& x, flat_multiset& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, flat_multiset& y) - { x.get().swap(y); } - -template -inline void swap(flat_multiset& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(flat_multiset&&x, flat_multiset&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_FLAT_SET_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_FLAT_SET_HPP diff --git a/include/boost/interprocess/containers/list.hpp b/include/boost/interprocess/containers/list.hpp index 9f17f5f..1eaf3f6 100644 --- a/include/boost/interprocess/containers/list.hpp +++ b/include/boost/interprocess/containers/list.hpp @@ -1,1469 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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_ +#ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_LIST_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -//Preprocessor library to emulate perfect forwarding -#include -#endif - -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond -namespace detail { - -template -struct list_hook -{ - typedef typename bi::make_list_base_hook - , bi::link_mode >::type type; -}; - -template -struct list_node - : public list_hook::type -{ - - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - list_node() - : m_data() - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - 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 - list_node(Args &&...args) - : m_data(detail::forward_impl(args)...) - {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - T m_data; -}; - -template -struct intrusive_list_type -{ - typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other - ::type void_pointer; - typedef typename detail::list_node - node_type; - typedef typename bi::make_list - < node_type - , bi::base_hook::type> - , bi::constant_time_size - , bi::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::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 list - : protected detail::node_alloc_holder - ::type> -{ - /// @cond - typedef typename - detail::intrusive_list_type::type Icont; - typedef list ThisType; - typedef detail::node_alloc_holder 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 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 - struct ValueCompareToNodeCompare - : Pred - { - ValueCompareToNodeCompare(Pred pred) - : Pred(pred) - {} - - bool operator()(const Node &a, const Node &b) const - { return static_cast(*this)(a.m_data, b.m_data); } - - bool operator()(const Node &a) const - { return static_cast(*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: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - 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; - 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; - 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 reverse_iterator; - //! Const iterator used to iterate backwards through a list. - typedef std::reverse_iterator const_reverse_iterator; - - //! Effects: Constructs a list taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit list(const allocator_type &a = A()) - : AllocHolder(a) - {} - -// list(size_type n) -// : AllocHolder(detail::move_impl(allocator_type())) -// { this->resize(n); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - list(size_type n, const T& value = T(), const A& a = A()) - : AllocHolder(a) - { this->insert(this->cbegin(), n, value); } - - //! Effects: Copy constructs a list. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - list(const list& x) - : AllocHolder(x) - { this->insert(this->cbegin(), x.begin(), x.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - list(detail::moved_object x) - : AllocHolder(detail::move_impl((AllocHolder&)x.get())) - {} - #else - list(list &&x) - : AllocHolder(detail::move_impl((AllocHolder&)x)) - {} - #endif - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the list. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - list(InpIt first, InpIt last, const A &a = A()) - : AllocHolder(a) - { this->insert(this->cbegin(), first, last); } - - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~list() - {} //AllocHolder clears the list - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: 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(); } - - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { AllocHolder::clear(alloc_version()); } - - //! Effects: Returns an iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->icont().begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->cbegin(); } - - //! Effects: Returns an iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->icont().end()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return this->crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(begin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return this->crend(); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->non_const_icont().begin()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->non_const_icont().end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return const_reverse_iterator(this->cend()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return const_reverse_iterator(this->cbegin()); } - - //! Effects: Returns true if the list contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } - - //! Effects: Returns the number of the elements contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->icont().size(); } - - //! Effects: Returns the largest possible size of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return AllocHolder::max_size(); } - - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const T& x) - { this->insert(this->cbegin(), x); } - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object x) - { this->insert(this->cbegin(), x); } - #else - void push_front(T &&x) - { this->insert(this->cbegin(), detail::move_impl(x)); } - #endif - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void push_back (const T& x) - { this->insert(this->cend(), x); } - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back (detail::moved_object x) - { this->insert(this->cend(), x); } - #else - void push_back (T &&x) - { this->insert(this->cend(), detail::move_impl(x)); } - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->erase(this->cbegin()); } - - //! Effects: Removes the last element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_back() - { const_iterator tmp = this->cend(); this->erase(--tmp); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return *(--this->end()); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const - { return *(--this->end()); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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); - } - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(ThisType& x) - #else - void swap(ThisType &&x) - #endif - { AllocHolder::swap(x); } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - ThisType& operator=(const ThisType& x) - { - if (this != &x) { - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - ThisType& operator=(detail::moved_object mx) - { - this->clear(); - this->swap(mx.get()); - return *this; - } - #else - ThisType& operator=(ThisType &&mx) - { - this->clear(); - this->swap(mx); - return *this; - } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->priv_create_and_insert_nodes(p, n, x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator p, InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: 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)); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object 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(detail::move_impl(x)); - return iterator(this->icont().insert(p.get(), *tmp)); - } - #endif - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_back(Args&&... args) - { - this->emplace(this->cend(), detail::forward_impl(args)...); - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - void emplace_front(Args&&... args) - { - this->emplace(this->cbegin(), detail::forward_impl(args)...); - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - iterator emplace(const_iterator p, Args&&... args) - { - typename AllocHolder::Deallocator d(AllocHolder::create_node_and_deallocator()); - new ((void*)detail::get_pointer(d.get())) Node(detail::forward_impl(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 \ - 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 \ - 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 \ - 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 - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - iterator erase(const_iterator p) - { return iterator(this->icont().erase_and_dispose(p.get(), Destroyer(this->node_alloc()))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: 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())); } - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(iterator p, detail::moved_object 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"); - } - } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: 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. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object 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"); - } - } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: 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. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the number of elements transferred. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object 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"); - } - } - - //! Requires: 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) - //! - //! Effects: 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. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object 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"); - } - } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } - - //! Effects: Removes all the elements that compare equal to value. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time. It performs exactly size() comparisons for equality. - //! - //! Note: 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)); } - - //! Effects: Removes all the elements for which a specified - //! predicate is satisfied. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time. It performs exactly size() calls to the predicate. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void remove_if(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that are equal from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time (size()-1 comparisons calls to pred()). - //! - //! Note: 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()); } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that satisfy some binary predicate from the list. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time (size()-1 comparisons equality comparisons). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void unique(BinaryPredicate binary_pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().unique_and_dispose(Predicate(binary_pred), Destroyer(this->node_alloc())); - } - - //! Requires: The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this according to std::less. 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. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void merge(detail::moved_object > x) - { this->merge(x.get()); } - void merge(list& x) - #else - void merge(list&& x) - #endif - { this->merge(x, value_less()); } - - //! Requires: 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. - //! - //! Effects: 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. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - template - void merge(detail::moved_object > x, StrictWeakOrdering comp) - { this->merge(x.get(), comp); } - template - void merge(list& x, StrictWeakOrdering comp) - #else - template - void merge(list&& x, StrictWeakOrdering comp) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().merge(x.icont(), - ValueCompareToNodeCompare(comp)); - } - else{ - throw std::runtime_error("list::merge called with unequal allocators"); - } - } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - void sort() - { this->sort(value_less()); } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - template - void sort(StrictWeakOrdering comp) - { - // nothing if the list has length 0 or 1. - if (this->size() < 2) - return; - this->icont().sort(ValueCompareToNodeCompare(comp)); - } - - /// @cond - private: - - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator pos, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(pos, beg, end, alloc_version(), ItCat()); - } - - template - 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 - 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 - 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 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 cvalue_iterator; - this->priv_create_and_insert_nodes(pos, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator p, - InputIter first, InputIter last, - detail::false_) - { this->priv_create_and_insert_nodes(p, first, last); } - - template - 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 - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->priv_fill_assign((size_type) n, (T) val); } - - template - 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 -inline bool operator==(const list& x, const list& y) -{ - if(x.size() != y.size()){ - return false; - } - typedef typename list::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 -inline bool operator<(const list& x, - const list& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); -} - -template -inline bool operator!=(const list& x, const list& y) -{ - return !(x == y); -} - -template -inline bool operator>(const list& x, const list& y) -{ - return y < x; -} - -template -inline bool operator<=(const list& x, const list& y) -{ - return !(y < x); -} - -template -inline bool operator>=(const list& x, const list& y) -{ - return !(x < y); -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(list& x, list& y) -{ - x.swap(y); -} - -template -inline void swap(detail::moved_object >& x, list y) -{ - x.get().swap(y); -} - -template -inline void swap(list& x, detail::moved_object > y) -{ - x.swap(y.get()); -} -#else -template -inline void swap(list &&x, list &&y) -{ - x.swap(y); -} - -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/* -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -*/ -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::list; } //namespace interprocess { } //namespace boost { #include -#endif // BOOST_INTERPROCESS_LIST_HPP_ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_LIST_HPP + diff --git a/include/boost/interprocess/containers/map.hpp b/include/boost/interprocess/containers/map.hpp index 2d7f1a3..a5f0d41 100644 --- a/include/boost/interprocess/containers/map.hpp +++ b/include/boost/interprocess/containers/map.hpp @@ -1,1313 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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 +#ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP +#define BOOST_INTERPROCESS_CONTAINERS_MAP_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { -namespace boost { namespace interprocess { +using boost::interprocess_container::map; +using boost::interprocess_container::multimap; -/// @cond -// Forward declarations of operators == and <, needed for friend declarations. -template -inline bool operator==(const map& x, - const map& y); - -template -inline bool operator<(const map& x, - const map& y); -/// @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 the key_type is Key and the value_type is std::pair. -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//! (e.g. boost::interprocess:allocator< std::pair). -template -class map -{ - /// @cond - private: - typedef detail::rbtree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - tree_t m_tree; // red-black tree representing map - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef T mapped_type; - typedef Pred key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - /// @cond - class value_compare_impl - : public Pred, - public std::binary_function - { - friend class map; - 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; - - //! Effects: Constructs an empty map using the specified comparison object - //! and allocator. - //! - //! Complexity: Constant. - explicit map(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty map using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - map(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) - {} - - //! Effects: Copy constructs a map. - //! - //! Complexity: Linear in x.size(). - map(const map& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a map. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - map(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - map(map &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - map& operator=(const map& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - map& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - map& operator=(map &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(m_tree.key_comp()); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: 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(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: 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)){ - value_type val(k, detail::move_impl(T())); - i = insert(i, detail::move_impl(val)); - } - return (*i).second; - } - - //! Effects: If there is no key equivalent to x in the map, inserts - //! value_type(detail::move_impl(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - T& operator[](detail::moved_object 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, detail::move_impl(T())); - i = insert(i, detail::move_impl(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(detail::move_impl(k), detail::move_impl(T())); - i = insert(i, detail::move_impl(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; - } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(map& x) - #else - void swap(map &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic. - std::pair insert(const value_type& x) - { return m_tree.insert_unique(x); } - - //! Effects: 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. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic. - std::pair insert(const std::pair& x) - { return m_tree.insert_unique(x); } - - //! Effects: 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. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object > x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(std::pair &&x) - { return m_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: 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. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(value_type &&x) - { return m_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: 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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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); } - - //! Effects: 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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object > x) - { return m_tree.insert_unique(position, x); } - #else - iterator insert(iterator position, std::pair &&x) - { return m_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - iterator insert(iterator position, const std::pair& x) - { return m_tree.insert_unique(position, x); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object x) - { return m_tree.insert_unique(position, x); } - #else - iterator insert(iterator position, value_type &&x) - { return m_tree.insert_unique(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: 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. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_unique(hint, detail::forward_impl(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 \ - 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 \ - 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 - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator position) - { return m_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: 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); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const map&, - const map&); - template - friend bool operator< (const map&, - const map&); - /// @endcond -}; - -template -inline bool operator==(const map& x, - const map& y) - { return x.m_tree == y.m_tree; } - -template -inline bool operator<(const map& x, - const map& y) - { return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const map& x, - const map& y) - { return !(x == y); } - -template -inline bool operator>(const map& x, - const map& y) - { return y < x; } - -template -inline bool operator<=(const map& x, - const map& y) - { return !(y < x); } - -template -inline bool operator>=(const map& x, - const map& y) - { return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(map& x, map& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, map& y) - { x.get().swap(y); } - -template -inline void swap(map& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(map&&x, map&&y) - { x.swap(y); } -#endif - - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -inline bool operator==(const multimap& x, - const multimap& y); - -template -inline bool operator<(const multimap& x, - const multimap& y); - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::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 the key_type is Key and the value_type is std::pair. -//! -//! Pred is the ordering function for Keys (e.g. std::less). -//! -//! Alloc is the allocator to allocate the value_types -//!(e.g. boost::interprocess:allocator< std::pair<const Key, T>). -template -class multimap -{ - /// @cond - private: - typedef detail::rbtree, - detail::select1st< std::pair >, - Pred, - Alloc> tree_t; - tree_t m_tree; // red-black tree representing map - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef T mapped_type; - typedef Pred key_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - /// @cond - class value_compare_impl - : public Pred, - public std::binary_function - { - friend class multimap; - 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; - - //! Effects: Constructs an empty multimap using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit multimap(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty multimap using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - multimap(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) - {} - - //! Effects: Copy constructs a multimap. - //! - //! Complexity: Linear in x.size(). - multimap(const multimap& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a multimap. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multimap(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - multimap(multimap && x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - multimap& - operator=(const multimap& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multimap& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - multimap& operator=(multimap && x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return value_compare(m_tree.key_comp()); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: 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(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(multimap& x) - #else - void swap(multimap &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const value_type& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a new value constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const std::pair& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a new value move-constructed from x and returns - //! the iterator pointing to the newly inserted element. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object > x) - { return m_tree.insert_equal(x); } - #else - iterator insert(std::pair && x) - { return m_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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); } - - //! Effects: Inserts a new value constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - iterator insert(iterator position, const std::pair& x) - { return m_tree.insert_equal(position, x); } - - //! Effects: Inserts a new value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(iterator position, detail::moved_object > x) - { return m_tree.insert_equal(position, x); } - #else - iterator insert(iterator position, std::pair && x) - { return m_tree.insert_equal(position, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_equal(hint, detail::forward_impl(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 \ - 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 \ - 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 - - //! Effects: Erases the element pointed to by position. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator position) - { return m_tree.erase(position); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: 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); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - {return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const multimap& x, - const multimap& y); - - template - friend bool operator< (const multimap& x, - const multimap& y); - /// @endcond -}; - -template -inline bool operator==(const multimap& x, - const multimap& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const multimap& x, - const multimap& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const multimap& x, - const multimap& y) -{ return !(x == y); } - -template -inline bool operator>(const multimap& x, - const multimap& y) -{ return y < x; } - -template -inline bool operator<=(const multimap& x, - const multimap& y) -{ return !(y < x); } - -template -inline bool operator>=(const multimap& x, - const multimap& y) -{ return !(x < y); } - - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(multimap& x, multimap& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, multimap& y) -{ x.get().swap(y); } - -template -inline void swap(multimap& x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(multimap&&x, multimap&&y) -{ x.swap(y); } -#endif - -/// @cond -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_MAP_HPP */ - +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_MAP_HPP diff --git a/include/boost/interprocess/containers/pair.hpp b/include/boost/interprocess/containers/pair.hpp new file mode 100644 index 0000000..0510d1a --- /dev/null +++ b/include/boost/interprocess/containers/pair.hpp @@ -0,0 +1,32 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::interprocess_container::containers_detail::pair; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_PAIR_HPP + diff --git a/include/boost/interprocess/containers/set.hpp b/include/boost/interprocess/containers/set.hpp index 0908116..53d36c0 100644 --- a/include/boost/interprocess/containers/set.hpp +++ b/include/boost/interprocess/containers/set.hpp @@ -1,1186 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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 +#ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SET_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include -#include +#include -#include -#include -#include +namespace boost { +namespace interprocess { -#include -#include -#include -#include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include -#endif +using boost::interprocess_container::set; +using boost::interprocess_container::multiset; -namespace boost { namespace interprocess { - -/// @cond -// Forward declarations of operators < and ==, needed for friend declaration. -template -inline bool operator==(const set& x, - const set& y); - -template -inline bool operator<(const set& x, - const set& y); -/// @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 set -{ - /// @cond - private: - typedef detail::rbtree, Pred, Alloc> tree_t; - tree_t m_tree; // red-black tree representing set - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef Pred key_compare; - typedef Pred value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty set using the specified comparison object - //! and allocator. - //! - //! Complexity: Constant. - explicit set(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty set using the specified comparison object and - //! allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - set(InputIterator first, InputIterator last, const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, true) - {} - - //! Effects: Copy constructs a set. - //! - //! Complexity: Linear in x.size(). - set(const set& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a set. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - set(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - set(set &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - set& operator=(const set& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - set& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - set& operator=(set &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: 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(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_tree.cbegin(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_tree.cend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_tree.crbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(set& x) - #else - void swap(set &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x if and only if there is no element in the container - //! with key equivalent to the key of x. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic. - std::pair insert(const value_type& x) - { return m_tree.insert_unique(x); } - - //! Effects: 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. - //! - //! Returns: 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. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - std::pair insert(detail::moved_object x) - { return m_tree.insert_unique(x); } - #else - std::pair insert(value_type &&x) - { return m_tree.insert_unique(detail::move_impl(x)); } - #endif - - //! Effects: 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. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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); } - - //! Effects: Inserts an element move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return m_tree.insert_unique(p, x); } - #else - iterator insert(const_iterator p, value_type &&x) - { return m_tree.insert_unique(p, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: 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. - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_unique(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(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. - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Logarithmic. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_unique(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(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. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_unique(hint, detail::forward_impl(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 \ - 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 \ - 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 - - //! Effects: Erases the element pointed to by p. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator p) - { return m_tree.erase(p); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: 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); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const_iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.find(x) == m_tree.end() ? 0 : 1; } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const set&, const set&); - - template - friend bool operator< (const set&, const set&); - /// @endcond -}; - -template -inline bool operator==(const set& x, - const set& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const set& x, - const set& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const set& x, - const set& y) -{ return !(x == y); } - -template -inline bool operator>(const set& x, - const set& y) -{ return y < x; } - -template -inline bool operator<=(const set& x, - const set& y) -{ return !(y < x); } - -template -inline bool operator>=(const set& x, - const set& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(set& x, set& y) -{ x.swap(y); } - -template -inline void swap(set& x, detail::moved_object >& y) -{ x.swap(y.get()); } - -template -inline void swap(detail::moved_object >& y, set& x) -{ y.swap(x.get()); } - -#else -template -inline void swap(set&&x, set&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; - -// Forward declaration of operators < and ==, needed for friend declaration. - -template -inline bool operator==(const multiset& x, - const multiset& y); - -template -inline bool operator<(const multiset& x, - const multiset& y); -/// @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 multiset -{ - /// @cond - private: - typedef detail::rbtree, Pred, Alloc> tree_t; - tree_t m_tree; // red-black tree representing multiset - /// @endcond - - public: - // typedefs: - typedef typename tree_t::key_type key_type; - typedef typename tree_t::value_type value_type; - typedef typename tree_t::pointer pointer; - typedef typename tree_t::const_pointer const_pointer; - typedef typename tree_t::reference reference; - typedef typename tree_t::const_reference const_reference; - typedef Pred key_compare; - typedef Pred value_compare; - typedef typename tree_t::iterator iterator; - typedef typename tree_t::const_iterator const_iterator; - typedef typename tree_t::reverse_iterator reverse_iterator; - typedef typename tree_t::const_reverse_iterator const_reverse_iterator; - typedef typename tree_t::size_type size_type; - typedef typename tree_t::difference_type difference_type; - typedef typename tree_t::allocator_type allocator_type; - typedef typename tree_t::stored_allocator_type stored_allocator_type; - - //! Effects: Constructs an empty multiset using the specified comparison - //! object and allocator. - //! - //! Complexity: Constant. - explicit multiset(const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(comp, a) - {} - - //! Effects: Constructs an empty multiset using the specified comparison object - //! and allocator, and inserts elements from the range [first ,last ). - //! - //! Complexity: Linear in N if the range [first ,last ) is already sorted using - //! comp and otherwise N logN, where N is last - first. - template - multiset(InputIterator first, InputIterator last, - const Pred& comp = Pred(), - const allocator_type& a = allocator_type()) - : m_tree(first, last, comp, a, false) - {} - - //! Effects: Copy constructs a multiset. - //! - //! Complexity: Linear in x.size(). - multiset(const multiset& x) - : m_tree(x.m_tree) - {} - - //! Effects: Move constructs a multiset. Constructs *this using x's resources. - //! - //! Complexity: Construct. - //! - //! Postcondition: x is emptied. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multiset(detail::moved_object > x) - : m_tree(detail::move_impl(x.get().m_tree)) - {} - #else - multiset(multiset &&x) - : m_tree(detail::move_impl(x.m_tree)) - {} - #endif - - //! Effects: Makes *this a copy of x. - //! - //! Complexity: Linear in x.size(). - multiset& operator=(const multiset& x) - { m_tree = x.m_tree; return *this; } - - //! Effects: this->swap(x.get()). - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - multiset& operator=(detail::moved_object > x) - { m_tree = detail::move_impl(x.get().m_tree); return *this; } - #else - multiset& operator=(multiset &&x) - { m_tree = detail::move_impl(x.m_tree); return *this; } - #endif - - //! Effects: Returns the comparison object out - //! of which a was constructed. - //! - //! Complexity: Constant. - key_compare key_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns an object of value_compare constructed out - //! of the comparison object. - //! - //! Complexity: Constant. - value_compare value_comp() const - { return m_tree.key_comp(); } - - //! Effects: Returns a copy of the Allocator that - //! was passed to the object's constructor. - //! - //! Complexity: 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(); } - - //! Effects: Returns an iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return m_tree.begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return m_tree.begin(); } - - //! Effects: Returns an iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return m_tree.end(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return m_tree.end(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return m_tree.rbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return m_tree.rbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return m_tree.rend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return m_tree.rend(); } - - //! Effects: Returns a const_iterator to the first element contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return m_tree.cbegin(); } - - //! Effects: Returns a const_iterator to the end of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return m_tree.cend(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin() const - { return m_tree.crbegin(); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return m_tree.crend(); } - - //! Effects: Returns true if the container contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return m_tree.empty(); } - - //! Effects: Returns the number of the elements contained in the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return m_tree.size(); } - - //! Effects: Returns the largest possible size of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return m_tree.max_size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(multiset& x) - #else - void swap(multiset &&x) - #endif - { m_tree.swap(x.m_tree); } - - //! Effects: Inserts x and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - iterator insert(const value_type& x) - { return m_tree.insert_equal(x); } - - //! Effects: Inserts a copy of x in the container. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(detail::moved_object x) - { return m_tree.insert_equal(x); } - #else - iterator insert(value_type && x) - { return m_tree.insert_equal(detail::move_impl(x)); } - #endif - - //! Effects: Inserts a copy of x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: 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); } - - //! Effects: Inserts a value move constructed from x in the container. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return m_tree.insert_equal(p, x); } - #else - iterator insert(const_iterator p, value_type && x) - { return m_tree.insert_equal(p, detail::move_impl(x)); } - #endif - - //! Requires: i, j are not iterators into *this. - //! - //! Effects: inserts each element from the range [i,j) . - //! - //! Complexity: N log(size()+N) (N is the distance from i to j) - template - void insert(InputIterator first, InputIterator last) - { m_tree.insert_equal(first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... and returns the iterator pointing to the - //! newly inserted element. - //! - //! Complexity: Logarithmic. - template - iterator emplace(Args&&... args) - { return m_tree.emplace_equal(detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - template - iterator emplace_hint(const_iterator hint, Args&&... args) - { return m_tree.emplace_hint_equal(hint, detail::forward_impl(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 \ - 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 \ - 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 - - //! Effects: Erases the element pointed to by p. - //! - //! Returns: Returns an iterator pointing to the element immediately - //! following q prior to the element being erased. If no such element exists, - //! returns end(). - //! - //! Complexity: Amortized constant time - iterator erase(const_iterator p) - { return m_tree.erase(p); } - - //! Effects: Erases all elements in the container with key equivalent to x. - //! - //! Returns: Returns the number of erased elements. - //! - //! Complexity: log(size()) + count(k) - size_type erase(const key_type& x) - { return m_tree.erase(x); } - - //! Effects: Erases all the elements in the range [first, last). - //! - //! Returns: Returns last. - //! - //! Complexity: 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); } - - //! Effects: erase(a.begin(),a.end()). - //! - //! Postcondition: size() == 0. - //! - //! Complexity: linear in size(). - void clear() - { m_tree.clear(); } - - //! Returns: An iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - iterator find(const key_type& x) - { return m_tree.find(x); } - - //! Returns: A const iterator pointing to an element with the key - //! equivalent to x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic. - const_iterator find(const key_type& x) const - { return m_tree.find(x); } - - //! Returns: The number of elements with key equivalent to x. - //! - //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const - { return m_tree.count(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator lower_bound(const key_type& x) - { return m_tree.lower_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator lower_bound(const key_type& x) const - { return m_tree.lower_bound(x); } - - //! Returns: An iterator pointing to the first element with key not less - //! than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - iterator upper_bound(const key_type& x) - { return m_tree.upper_bound(x); } - - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. - //! - //! Complexity: Logarithmic - const_iterator upper_bound(const key_type& x) const - { return m_tree.upper_bound(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) - { return m_tree.equal_range(x); } - - //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). - //! - //! Complexity: Logarithmic - std::pair - equal_range(const key_type& x) const - { return m_tree.equal_range(x); } - - /// @cond - template - friend bool operator== (const multiset&, - const multiset&); - template - friend bool operator< (const multiset&, - const multiset&); - /// @endcond -}; - -template -inline bool operator==(const multiset& x, - const multiset& y) -{ return x.m_tree == y.m_tree; } - -template -inline bool operator<(const multiset& x, - const multiset& y) -{ return x.m_tree < y.m_tree; } - -template -inline bool operator!=(const multiset& x, - const multiset& y) -{ return !(x == y); } - -template -inline bool operator>(const multiset& x, - const multiset& y) -{ return y < x; } - -template -inline bool operator<=(const multiset& x, - const multiset& y) -{ return !(y < x); } - -template -inline bool operator>=(const multiset& x, - const multiset& y) -{ return !(x < y); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(multiset& x, multiset& y) -{ x.swap(y); } - -template -inline void swap(multiset& x, detail::moved_object >& y) -{ x.swap(y.get()); } - -template -inline void swap(detail::moved_object >& y, multiset& x) -{ y.swap(x.get()); } -#else -template -inline void swap(multiset&&x, multiset&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = - has_trivial_destructor::value && - has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess { +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_SET_HPP */ - +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SET_HPP diff --git a/include/boost/interprocess/containers/slist.hpp b/include/boost/interprocess/containers/slist.hpp index 4b0728d..7a3cafd 100644 --- a/include/boost/interprocess/containers/slist.hpp +++ b/include/boost/interprocess/containers/slist.hpp @@ -1,1642 +1,31 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2004-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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 +#ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP +#define BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +namespace boost { +namespace interprocess { +using boost::interprocess_container::slist; -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -//Preprocessor library to emulate perfect forwarding -#include -#endif - -#include -#include -#include -#include -#include - -namespace boost{ namespace interprocess{ - -/// @cond - -namespace detail { - -template -struct slist_hook -{ - typedef typename bi::make_slist_base_hook - , bi::link_mode >::type type; -}; - -template -struct slist_node - : public slist_hook::type -{ - #ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - slist_node() - : m_data() - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - 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 - slist_node(Args &&...args) - : m_data(detail::forward_impl(args)...) - {} - #endif//#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING - - T m_data; -}; - -template -struct intrusive_slist_type -{ - typedef typename A::value_type value_type; - typedef typename detail::pointer_to_other - ::type void_pointer; - typedef typename detail::slist_node - node_type; - - typedef typename bi::make_slist - ::type> - ,bi::constant_time_size - ,bi::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::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 slist - : protected detail::node_alloc_holder - ::type> -{ - /// @cond - typedef typename - detail::intrusive_slist_type::type Icont; - typedef detail::node_alloc_holder AllocHolder; - typedef typename AllocHolder::NodePtr NodePtr; - typedef slist ThisType; - typedef typename AllocHolder::NodeAlloc NodeAlloc; - typedef typename AllocHolder::ValAlloc ValAlloc; - typedef typename AllocHolder::Node Node; - typedef detail::allocator_destroyer 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 - struct ValueCompareToNodeCompare - : Pred - { - ValueCompareToNodeCompare(Pred pred) - : Pred(pred) - {} - - bool operator()(const Node &a, const Node &b) const - { return static_cast(*this)(a.m_data, b.m_data); } - - bool operator()(const Node &a) const - { return static_cast(*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: - //! Const iterator used to iterate through a list. - class const_iterator - /// @cond - : public std::iterator - { - - 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; - 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; - 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: - //! Effects: Constructs a list taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit slist(const allocator_type& a = allocator_type()) - : AllocHolder(a) - {} - -// explicit slist(size_type n) -// : AllocHolder(detail::move_impl(allocator_type())) -// { this->resize(n); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - explicit slist(size_type n, const value_type& x = value_type(), - const allocator_type& a = allocator_type()) - : AllocHolder(a) - { this->priv_create_and_insert_nodes(this->before_begin(), n, x); } - - //! Effects: Constructs a list that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the list. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - slist(InpIt first, InpIt last, - const allocator_type& a = allocator_type()) - : AllocHolder(a) - { this->insert_after(this->before_begin(), first, last); } - - //! Effects: Copy constructs a list. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocator_type's default constructor or copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - slist(const slist& x) - : AllocHolder(x) - { this->insert_after(this->before_begin(), x.begin(), x.end()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - slist(detail::moved_object x) - : AllocHolder(detail::move_impl((AllocHolder&)x.get())) - {} - #else - slist(slist &&x) - : AllocHolder(detail::move_impl((AllocHolder&)x)) - {} - #endif - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - slist& operator= (const slist& x) - { - if (&x != this){ - this->assign(x.begin(), x.end()); - } - return *this; - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - slist& operator= (detail::moved_object 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 - - //! Effects: Destroys the list. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~slist() - {} //AllocHolder clears the slist - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: 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: - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const T& val) - { this->priv_fill_assign(n, val); } - - //! Effects: Assigns the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InpIt first, InpIt last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Returns an iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->icont().begin()); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->cbegin(); } - - //! Effects: Returns an iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->icont().end()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a non-dereferenceable iterator that, - //! when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator before_begin() - { return iterator(end()); } - - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator before_begin() const - { return this->cbefore_begin(); } - - //! Effects: Returns a const_iterator to the first element contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->non_const_icont().begin()); } - - //! Effects: Returns a const_iterator to the end of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->non_const_icont().end()); } - - //! Effects: Returns a non-dereferenceable const_iterator - //! that, when incremented, yields begin(). This iterator may be used - //! as the argument toinsert_after, erase_after, etc. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbefore_begin() const - { return const_iterator(end()); } - - //! Effects: Returns the number of the elements contained in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->icont().size(); } - - //! Effects: Returns the largest possible size of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return AllocHolder::max_size(); } - - //! Effects: Returns true if the list contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->size(); } - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements on *this and x. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(slist& x) - #else - void swap(slist &&x) - #endif - { AllocHolder::swap(x); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->begin(); } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->begin(); } - - //! Effects: Inserts a copy of t in the beginning of the list. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const value_type& x) - { this->icont().push_front(*this->create_node(x)); } - - //! Effects: Constructs a new element in the beginning of the list - //! and moves the resources of t to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_front(detail::moved_object x) - { this->icont().push_front(*this->create_node(x)); } - #else - void push_front(T && x) - { this->icont().push_front(*this->create_node(detail::move_impl(x))); } - #endif - - //! Effects: Removes the first element from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Amortized constant time. - void pop_front() - { this->icont().pop_front_and_dispose(Destroyer(this->node_alloc())); } - - //! Returns: 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. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - iterator previous(iterator p) - { return iterator(this->icont().previous(p.get())); } - - //! Returns: 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. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before i. - const_iterator previous(const_iterator p) - { return const_iterator(this->icont().previous(p.get())); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts a copy of the value after the p pointed - //! by prev_p. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: 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))); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts a move constructed copy object from the value after the - //! p pointed by prev_pos. - //! - //! Returns: An iterator to the inserted element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert_after(const_iterator prev_pos, detail::moved_object 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(detail::move_impl(x)))); } - #endif - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x after prev_pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - //! - //! Note: 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); } - - //! Requires: prev_pos must be a valid iterator of *this. - //! - //! Effects: Inserts the range pointed by [first, last) - //! after the p prev_pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to the number of elements inserted. - //! - //! Note: Does not affect the validity of iterators and references of - //! previous values. - template - void insert_after(const_iterator prev_pos, InIter first, InIter last) - { - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_after_range_dispatch(prev_pos, first, last, Result()); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: Linear to the elements before p. - iterator insert(const_iterator p, const value_type& x) - { return this->insert_after(previous(p), x); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Linear to the elements before p. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator p, detail::moved_object x) - { return this->insert_after(previous(p), x); } - #else - iterator insert(const_iterator p, value_type && x) - { return this->insert_after(previous(p), detail::move_impl(x)); } - #endif - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts n copies of x before p. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: 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); } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before p. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws. - //! - //! Complexity: Linear to std::distance [first, last) plus - //! linear to the elements before p. - template - void insert(const_iterator p, InIter first, InIter last) - { return this->insert_after(previous(p), first, last); } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the front of the list - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - template - void emplace_front(Args&&... args) - { this->emplace_after(this->cbefore_begin(), detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Linear to the elements before p - template - iterator emplace(const_iterator p, Args&&... args) - { return this->emplace_after(this->previous(p), detail::forward_impl(args)...); } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... after prev - //! - //! Throws: If memory allocation throws or - //! T's in-place constructor throws. - //! - //! Complexity: Constant - template - 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(detail::forward_impl(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 \ - 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 \ - 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 \ - 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 - - //! Effects: Erases the element after the element pointed by prev_pos - //! of the list. - //! - //! Returns: the first element remaining beyond the removed elements, - //! or end() if no such element exists. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: 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()))); - } - - //! Effects: Erases the range (before_first, last) from - //! the list. - //! - //! Returns: the first element remaining beyond the removed elements, - //! or end() if no such element exists. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of erased elements. - //! - //! Note: 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()))); - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Erases the element at p p. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements before p. - iterator erase(const_iterator p) - { return iterator(this->erase_after(previous(p))); } - - //! Requires: first and last must be valid iterator to elements in *this. - //! - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: 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)); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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); - } - } - - //! Effects: Erases all the elements of the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the list. - void clear() - { this->icont().clear_and_dispose(Destroyer(this->node_alloc())); } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, after the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the elements in x. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object 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"); - } - } - - //! Requires: prev_pos must be a valid iterator of this. - //! i must point to an element contained in list x. - //! - //! Effects: 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. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object 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"); - } - } - - //! Requires: 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. - //! - //! Effects: Transfers the range [before_first + 1, before_last + 1) - //! from list x to this list, after the element pointed by prev_pos. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear to the number of transferred elements. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object 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"); - } - } - - //! Requires: 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) - //! - //! Effects: Transfers the range [before_first + 1, before_last + 1) - //! from list x to this list, after the element pointed by prev_pos. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Constant. - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice_after(const_iterator prev_pos, detail::moved_object 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"); - } - } - - //! Requires: p must point to an element contained - //! by the list. x != *this - //! - //! Effects: Transfers all the elements of list x to this list, before the - //! the element pointed by p. No destructors or copy constructors are called. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and linear in x.size(). - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object 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); } - - //! Requires: p must point to an element contained - //! by this list. i must point to an element contained in list x. - //! - //! Effects: 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. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), and in distance(x.begin(), i). - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object 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); } - - //! Requires: p must point to an element contained - //! by this list. first and last must point to elements contained in list x. - //! - //! Effects: 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. - //! - //! Throws: std::runtime_error if this' allocator and x's allocator - //! are not equal. - //! - //! Complexity: Linear in distance(begin(), p), in distance(x.begin(), first), - //! and in distance(first, last). - //! - //! Note: 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void splice(const_iterator p, detail::moved_object 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)); } - - //! Effects: Reverses the order of elements in the list. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time. - //! - //! Note: Iterators and references are not invalidated - void reverse() - { this->icont().reverse(); } - - //! Effects: Removes all the elements that compare equal to value. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time. It performs exactly size() comparisons for equality. - //! - //! Note: 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)); } - - //! Effects: Removes all the elements for which a specified - //! predicate is satisfied. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time. It performs exactly size() calls to the predicate. - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void remove_if(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().remove_and_dispose_if(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that are equal from the list. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear time (size()-1 comparisons calls to pred()). - //! - //! Note: 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()); } - - //! Effects: Removes adjacent duplicate elements or adjacent - //! elements that satisfy some binary predicate from the list. - //! - //! Throws: If pred throws. - //! - //! Complexity: Linear time (size()-1 comparisons equality comparisons). - //! - //! Note: The relative order of elements that are not removed is unchanged, - //! and iterators to elements that are not removed remain valid. - template - void unique(Pred pred) - { - typedef ValueCompareToNodeCompare Predicate; - this->icont().unique_and_dispose(Predicate(pred), Destroyer(this->node_alloc())); - } - - //! Requires: The lists x and *this must be distinct. - //! - //! Effects: This function removes all of x's elements and inserts them - //! in order into *this according to std::less. 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. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void merge(detail::moved_object > x) - { this->merge(x.get()); } - void merge(slist& x) - #else - void merge(slist&& x) - #endif - { this->merge(x, value_less()); } - - //! Requires: 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. - //! - //! Effects: 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. - //! - //! Throws: Nothing. - //! - //! Complexity: This function is linear time: it performs at most - //! size() + x.size() - 1 comparisons. - //! - //! Note: Iterators and references to *this are not invalidated. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - template - void merge(detail::moved_object > x, StrictWeakOrdering comp) - { this->merge(x.get(), comp); } - template - void merge(slist& x, StrictWeakOrdering comp) - #else - template - void merge(slist&& x, StrictWeakOrdering comp) - #endif - { - if((NodeAlloc&)*this == (NodeAlloc&)x){ - this->icont().merge(x.icont(), - ValueCompareToNodeCompare(comp)); - } - else{ - throw std::runtime_error("list::merge called with unequal allocators"); - } - } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - void sort() - { this->sort(value_less()); } - - //! Effects: This function sorts the list *this according to std::less. - //! The sort is stable, that is, the relative order of equivalent elements is preserved. - //! - //! Throws: Nothing. - //! - //! Notes: Iterators and references are not invalidated. - //! - //! Complexity: The number of comparisons is approximately N log N, where N - //! is the list's size. - template - void sort(StrictWeakOrdering comp) - { - // nothing if the slist has length 0 or 1. - if (this->size() < 2) - return; - this->icont().sort(ValueCompareToNodeCompare(comp)); - } - - /// @cond - private: - - //Iterator range version - template - void priv_create_and_insert_nodes - (const_iterator prev, InpIterator beg, InpIterator end) - { - typedef typename std::iterator_traits::iterator_category ItCat; - priv_create_and_insert_nodes(prev, beg, end, alloc_version(), ItCat()); - } - - template - 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 - 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 - 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 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 cvalue_iterator; - this->priv_create_and_insert_nodes(prev, cvalue_iterator(x, n), cvalue_iterator()); - } - - //Dispatch to detect iterator range or integer overloads - template - void priv_insert_dispatch(const_iterator prev, - InputIter first, InputIter last, - detail::false_) - { this->priv_create_and_insert_nodes(prev, first, last); } - - template - 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 - void priv_assign_dispatch(Int n, Int val, detail::true_) - { this->priv_fill_assign((size_type) n, (T)val); } - - template - 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 - 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 - 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 -inline bool -operator==(const slist& x, const slist& y) -{ - if(x.size() != y.size()){ - return false; - } - typedef typename slist::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 -inline bool -operator<(const slist& sL1, const slist& sL2) -{ - return std::lexicographical_compare - (sL1.begin(), sL1.end(), sL2.begin(), sL2.end()); -} - -template -inline bool -operator!=(const slist& sL1, const slist& sL2) - { return !(sL1 == sL2); } - -template -inline bool -operator>(const slist& sL1, const slist& sL2) - { return sL2 < sL1; } - -template -inline bool -operator<=(const slist& sL1, const slist& sL2) - { return !(sL2 < sL1); } - -template -inline bool -operator>=(const slist& sL1, const slist& sL2) - { return !(sL1 < sL2); } - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(slist& x, slist& y) - { x.swap(y); } - -template -inline void swap(detail::moved_object > x, slist& y) - { x.get().swap(y); } - -template -inline void swap(slist& x, detail::moved_object > y) - { x.swap(y.get()); } -#else -template -inline void swap(slist&&x, slist&&y) - { x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -/* -template -struct is_movable > -{ - enum { value = true }; -}; -*/ -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::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 insert_iterator > -{ - protected: - typedef boost::interprocess::slist Container; - Container* container; - typename Container::iterator iter; - public: - typedef Container container_type; - typedef output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - insert_iterator(Container& x, - typename Container::iterator i, - bool is_previous = false) - : container(&x), iter(is_previous ? i : x.previous(i)){ } - - insert_iterator& - operator=(const typename Container::value_type& value) - { - iter = container->insert_after(iter, value); - return *this; - } - insert_iterator& operator*(){ return *this; } - insert_iterator& operator++(){ return *this; } - insert_iterator& operator++(int){ return *this; } -}; - -} //namespace std; - -///@endcond +} //namespace interprocess { +} //namespace boost { #include -#endif /* BOOST_INTERPROCESS_SLIST_HPP */ +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_SLIST_HPP diff --git a/include/boost/interprocess/containers/stable_vector.hpp b/include/boost/interprocess/containers/stable_vector.hpp new file mode 100644 index 0000000..d6c47a1 --- /dev/null +++ b/include/boost/interprocess/containers/stable_vector.hpp @@ -0,0 +1,31 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { + namespace interprocess { + + using boost::interprocess_container::stable_vector; + + } //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STABLE_VECTOR_HPP diff --git a/include/boost/interprocess/containers/string.hpp b/include/boost/interprocess/containers/string.hpp index 4410423..ceacbce 100644 --- a/include/boost/interprocess/containers/string.hpp +++ b/include/boost/interprocess/containers/string.hpp @@ -1,2491 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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 +#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP +#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -namespace detail { -/// @cond -// ------------------------------------------------------------ -// Class basic_string_base. +using boost::interprocess_container::basic_string; +using boost::interprocess_container::string; -// 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 basic_string_base -{ - basic_string_base(); - public: - 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_INTERPROCESS_RVALUE_REFERENCE) - basic_string_base(detail::moved_object > b) - : members_(b.get().members_) - { - init(); - this->swap(b.get()); - } - #else - basic_string_base(basic_string_base && b) - : members_(b.members_) - { - init(); - this->swap(b); - } - #endif - - ~basic_string_base() - { - this->deallocate_block(); - if(!this->is_short()){ - static_cast(static_cast(&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::value>::type -// long_alignment_type; - typedef void *long_alignment_type; - BOOST_STATIC_ASSERT((detail::alignment_of::value % - detail::alignment_of::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; - static const size_type ShortDataOffset = - detail::ct_rounded_size::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(&s); } - - long_t &long_repr() const - { return *static_cast(const_cast(static_cast(&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(this->members_.m_repr.s.h.is_short != 0); } - - void is_short(bool yes) - { - if(yes && !this->is_short()){ - static_cast(static_cast(&this->members_.m_repr.r))->~long_t(); - } - else{ - new(static_cast(&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 allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant::value> alloc_version; - - std::pair - 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 - 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(0), 0); - received_size = preferred_size; - return std::make_pair(this->alloc().allocate(received_size), false); - } - - std::pair - 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(sz); - } - - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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 basic_string - : private detail::basic_string_base -{ - /// @cond - private: - typedef detail::basic_string_base 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 - struct Eq_traits - : public std::binary_function - { - bool operator()(const typename Tr::char_type& x, - const typename Tr::char_type& y) const - { return Tr::eq(x, y); } - }; - - template - struct Not_within_traits - : public std::unary_function - { - typedef const typename Tr::char_type* Pointer; - const Pointer m_first; - const Pointer m_last; - - Not_within_traits(Pointer f, Pointer l) - : m_first(f), m_last(l) {} - - bool operator()(const typename Tr::char_type& x) const - { - return std::find_if(m_first, m_last, - std::bind1st(Eq_traits(), x)) == m_last; - } - }; - /// @endcond - - public: - //! 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 reverse_iterator; - //! Const iterator used to iterate backwards through a string - typedef std::reverse_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 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(); } - - //! Effects: Constructs a basic_string taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - explicit basic_string(const allocator_type& a = allocator_type()) - : base_t(a, InternalBufferChars) - { this->priv_terminate_string(); } - - //! Effects: Copy constructs a basic_string. - //! - //! Postcondition: x == *this. - //! - //! Throws: 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()); } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string(detail::moved_object s) - : base_t(detail::move_impl((base_t&)s.get())) - {} - #else - basic_string(basic_string && s) - : base_t(detail::move_impl((base_t&)s)) - {} - #endif - - //! Effects: 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)); - } - - //! Effects: 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); } - - //! Effects: 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)); } - - //! Effects: 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()); - } - - //! Effects: Constructs a basic_string taking the allocator as parameter, - //! and a range of iterators. - template - basic_string(InputIterator f, InputIterator l, - const allocator_type& a = allocator_type()) - : base_t(a) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_initialize_dispatch(f, l, Result()); - } - - //! Effects: Destroys the basic_string. All used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - ~basic_string() - {} - - //! Effects: Copy constructs a string. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - basic_string& operator=(const basic_string& s) - { - if (&s != this) - this->assign(s.begin(), s.end()); - return *this; - } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& operator=(detail::moved_object 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 - - //! Effects: Assignment from a null-terminated c-string. - basic_string& operator=(const CharT* s) - { return this->assign(s, s + Traits::length(s)); } - - //! Effects: Assignment from character. - basic_string& operator=(CharT c) - { return this->assign(static_cast(1), c); } - - //! Effects: Returns an iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return this->priv_addr(); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return this->priv_addr(); } - - //! Effects: Returns an iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return this->priv_addr() + this->priv_size(); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->priv_addr() + this->priv_size(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(this->priv_addr() + this->priv_size()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin() const - { return const_reverse_iterator(this->priv_addr() + this->priv_size()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(this->priv_addr()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return const_reverse_iterator(this->priv_addr()); } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - allocator_type get_allocator() const - { return this->alloc(); } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->priv_size(); } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type length() const - { return this->size(); } - - //! Effects: Returns the largest possible size of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return base_t::max_size(); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type n) - { resize(n, this->priv_null()); } - - //! Effects: 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. - //! - //! Throws: 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); - } - } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return this->priv_capacity(); } - - //! Effects: Erases all the elements of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: 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); - } - } - - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->priv_size(); } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return *(this->priv_addr() + n); } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const - { return *(this->priv_addr() + n); } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) { - if (n >= size()) - this->throw_out_of_range(); - return *(this->priv_addr() + n); - } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const { - if (n >= size()) - this->throw_out_of_range(); - return *(this->priv_addr() + n); - } - - //! Effects: Appends string s to *this. - basic_string& operator+=(const basic_string& s) - { return this->append(s); } - - //! Effects: Appends c-string s to *this. - basic_string& operator+=(const CharT* s) - { return this->append(s); } - - //! Effects: Appends character c to *this. - basic_string& operator+=(CharT c) - { this->push_back(c); return *this; } - - //! Effects: Appends string s to *this. - basic_string& append(const basic_string& s) - { return this->append(s.begin(), s.end()); } - - //! Effects: 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)); - } - - //! Effects: 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); } - - //! Effects: Appends the c-string s to *this. - basic_string& append(const CharT* s) - { return this->append(s, s + Traits::length(s)); } - - //! Effects: 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()); } - - //! Effects: Appends the range [first, last) *this. - template - basic_string& append(InputIter first, InputIter last) - { this->insert(this->end(), first, last); return *this; } - - //! Effects: 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); - } - } - - //! Effects: 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);; - } - - //! Effects: Assigns the value s to *this. - basic_string& assign(const basic_string& s) - { return this->operator=(s); } - - //! Effects: Moves the resources from ms *this. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& assign(detail::moved_object ms) - { return this->operator=(ms);} - #else - basic_string& assign(basic_string && ms) - { return this->operator=(ms);} - #endif - - //! Effects: 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)); - } - - //! Effects: 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); } - - //! Effects: Assigns the c-string s to *this. - basic_string& assign(const CharT* s) - { return this->assign(s, s + Traits::length(s)); } - - //! Effects: 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()); } - - //! Effects: Assigns the range [first, last) to *this. - template - basic_string& assign(InputIter first, InputIter last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - return this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: 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(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; - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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()); - } - - //! Effects: Inserts the range [first, last) before position. - template - void insert(iterator p, InputIter first, InputIter last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(p, first, last, Result()); - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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; - } - - //! Effects: 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()); - } - - //! Effects: 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); - } - - //! Effects: 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); - } - - //! Effects: 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)); - } - - //! Effects: 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); - } - - //! Effects: 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()); } - - //! Effects: 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); } - - //! Effects: 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)); } - - //! Effects: 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(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; - } - - //! Effects: Replaces a substring of *this with the range [f, l) - template - basic_string& replace(iterator first, iterator last, - InputIter f, InputIter l) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - return this->priv_replace_dispatch(first, last, f, l, Result()); - } - - //! Effects: 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; - } - - //! Effects: Swaps the contents of two strings. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object x) - { this->swap(x.get()); } - void swap(basic_string& x) - #else - void swap(basic_string &&x) - #endif - { base_t::swap(x); } - - //! Returns: 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()); } - - //! Returns: 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()); } - - //! Effects: 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()); } - - //! Effects: 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)); } - - //! Effects: 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()); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: 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(), c)); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: 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()); } - - //! Effects: 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)); } - - //! Effects: 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()); - return result != last ? result - begin() : npos; - } - } - - //! Effects: 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(), c)); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: 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()); } - - //! Effects: 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)); } - - //! Effects: 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()); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: 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); } - - //! Effects: 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()); } - - //! Effects: 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)); } - - //! Effects: 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()); - return rresult != rend() ? (rresult.base() - 1) - this->priv_addr() : npos; - } - } - - //! Effects: 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); } - - //! Effects: 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()); } - - //! Effects: 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)); } - - //! Effects: 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(s, s + n)); - return result != finish ? result - this->priv_addr() : npos; - } - } - - //! Effects: 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(), c))); - return result != finish ? result - begin() : npos; - } - } - - //! Effects: 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()); } - - //! Effects: 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)); } - - //! Effects: 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(s, s + n)); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: 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(), c))); - return rresult != rend() ? (rresult.base() - 1) - begin() : npos; - } - } - - //! Effects: 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()); - } - - //! Effects: 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()); } - - //! Effects: 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()); - } - - //! Effects: 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)); - } - - //! Effects: 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)); } - - - //! Effects: 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 - 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 - 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(n+1, InternalBufferChars)); - priv_uninitialized_copy(f, l, this->priv_addr()); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_range_initialize(InputIter f, InputIter l) - { - typedef typename std::iterator_traits::iterator_category Category; - this->priv_range_initialize(f, l, Category()); - } - - template - void priv_initialize_dispatch(Integer n, Integer x, detail::true_) - { - this->allocate_initial_block(max_value(n+1, InternalBufferChars)); - priv_uninitialized_fill_n(this->priv_addr(), n, x); - this->priv_size(n); - this->priv_terminate_string(); - } - - template - void priv_initialize_dispatch(InputIter f, InputIter l, detail::false_) - { this->priv_range_initialize(f, l); } - - template 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 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 - basic_string& priv_assign_dispatch(Integer n, Integer x, detail::true_) - { return this->assign((size_type) n, (CharT) x); } - - template - 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 - void priv_insert(iterator p, InputIter first, InputIter last, std::input_iterator_tag) - { - for ( ; first != last; ++first, ++p) { - p = this->insert(p, *first); - } - } - - template - void priv_insert(iterator position, ForwardIter first, - ForwardIter last, std::forward_iterator_tag) - { - if (first != last) { - size_type n = std::distance(first, last); - size_type remaining = this->capacity() - this->priv_size(); - const size_type old_size = this->size(); - pointer old_start = this->priv_addr(); - bool enough_capacity = false; - std::pair 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 - 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 - void priv_insert_dispatch(iterator p, Integer n, Integer x, - detail::true_) - { insert(p, (size_type) n, (CharT) x); } - - template - void priv_insert_dispatch(iterator p, InputIter first, InputIter last, - detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - priv_insert(p, first, last, Category()); - } - - template - void priv_copy(InputIterator first, InputIterator last, iterator result) - { - for ( ; first != last; ++first, ++result) - Traits::assign(*result, *first); - } - - void priv_copy(const CharT* first, const CharT* last, CharT* result) - { Traits::copy(result, first, last - first); } - - template - 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 - basic_string& priv_replace_dispatch(iterator first, iterator last, - InputIter f, InputIter l, - detail::false_) - { - typedef typename std::iterator_traits::iterator_category Category; - return this->priv_replace(first, last, f, l, Category()); - } - - - template - basic_string& priv_replace(iterator first, iterator last, - InputIter f, InputIter l, std::input_iterator_tag) - { - for ( ; first != last && f != l; ++first, ++f) - Traits::assign(*first, *f); - - if (f == l) - this->erase(first, last); - else - this->insert(last, f, l); - return *this; - } - - template - basic_string& priv_replace(iterator first, iterator last, - ForwardIter f, ForwardIter l, - std::forward_iterator_tag) - { - difference_type n = std::distance(f, l); - const difference_type len = last - first; - if (len >= n) { - this->priv_copy(f, l, first); - this->erase(first + n, last); - } - else { - ForwardIter m = f; - std::advance(m, len); - this->priv_copy(f, m, first); - this->insert(last, m, l); - } - return *this; - } - /// @endcond -}; - -template -const typename basic_string::size_type -basic_string::npos - = (typename basic_string::size_type) -1; - -// ------------------------------------------------------------ -// Non-member functions. - -// Operator+ - -template -inline basic_string -operator+(const basic_string& x, - const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, x.size() + y.size(), x.alloc()); - result.append(x); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const basic_string& y) -{ - mx.get() += y; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, - const basic_string& y) -{ - mx += y; - return detail::move_impl(mx); -} -#endif - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(const basic_string& x, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), x); -} -#else -template -inline basic_string && -operator+(const basic_string& x, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), x); -} -#endif - -template -inline basic_string -operator+(const CharT* s, const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - const std::size_t n = Traits::length(s); - str_t result(reserve, n + y.size()); - result.append(s, s + n); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(const CharT* s, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), s); -} -#else -template -inline basic_string && -operator+(const CharT* s, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return detail::move_impl(my.get().replace(size_type(0), size_type(0), s)); -} -#endif - -template -inline basic_string -operator+(CharT c, const basic_string& y) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, 1 + y.size()); - result.push_back(c); - result.append(y); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(CharT c, - detail::moved_object > my) -{ - typedef typename basic_string::size_type size_type; - return my.get().replace(size_type(0), size_type(0), &c, &c + 1); -} -#else -template -inline basic_string && -operator+(CharT c, - basic_string && my) -{ - typedef typename basic_string::size_type size_type; - return my.replace(size_type(0), size_type(0), &c, &c + 1); -} -#endif - -template -inline basic_string -operator+(const basic_string& x, const CharT* s) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - const std::size_t n = Traits::length(s); - str_t result(reserve, x.size() + n, x.alloc()); - result.append(x); - result.append(s, s + n); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const CharT* s) -{ - mx.get() += s; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, - const CharT* s) -{ - mx += s; - return detail::move_impl(mx); -} -#endif - -template -inline basic_string -operator+(const basic_string& x, const CharT c) -{ - typedef basic_string str_t; - typedef typename str_t::reserve_t reserve_t; - reserve_t reserve; - str_t result(reserve, x.size() + 1, x.alloc()); - result.append(x); - result.push_back(c); - return result; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline detail::moved_object > -operator+(detail::moved_object > mx, - const CharT c) -{ - mx.get() += c; - return mx; -} -#else -template -basic_string && -operator+(basic_string && mx, const CharT c) -{ - mx += c; - return detail::move_impl(mx); -} -#endif - -// Operator== and operator!= - -template -inline bool -operator==(const basic_string& x, - const basic_string& y) -{ - return x.size() == y.size() && - Traits::compare(x.data(), y.data(), x.size()) == 0; -} - -template -inline bool -operator==(const CharT* s, const basic_string& y) -{ - std::size_t n = Traits::length(s); - return n == y.size() && Traits::compare(s, y.data(), n) == 0; -} - -template -inline bool -operator==(const basic_string& x, const CharT* s) -{ - std::size_t n = Traits::length(s); - return x.size() == n && Traits::compare(x.data(), s, n) == 0; -} - -template -inline bool -operator!=(const basic_string& x, - const basic_string& y) - { return !(x == y); } - -template -inline bool -operator!=(const CharT* s, const basic_string& y) - { return !(s == y); } - -template -inline bool -operator!=(const basic_string& x, const CharT* s) - { return !(x == s); } - - -// Operator< (and also >, <=, and >=). - -template -inline bool -operator<(const basic_string& x, - const basic_string& y) -{ - return x.compare(y) < 0; -// return basic_string -// ::s_compare(x.begin(), x.end(), y.begin(), y.end()) < 0; -} - -template -inline bool -operator<(const CharT* s, const basic_string& y) -{ - return y.compare(s) > 0; -// std::size_t n = Traits::length(s); -// return basic_string -// ::s_compare(s, s + n, y.begin(), y.end()) < 0; -} - -template -inline bool -operator<(const basic_string& x, - const CharT* s) -{ - return x.compare(s) < 0; -// std::size_t n = Traits::length(s); -// return basic_string -// ::s_compare(x.begin(), x.end(), s, s + n) < 0; -} - -template -inline bool -operator>(const basic_string& x, - const basic_string& y) { - return y < x; -} - -template -inline bool -operator>(const CharT* s, const basic_string& y) { - return y < s; -} - -template -inline bool -operator>(const basic_string& x, const CharT* s) -{ - return s < x; -} - -template -inline bool -operator<=(const basic_string& x, - const basic_string& y) -{ - return !(y < x); -} - -template -inline bool -operator<=(const CharT* s, const basic_string& y) - { return !(y < s); } - -template -inline bool -operator<=(const basic_string& x, const CharT* s) - { return !(s < x); } - -template -inline bool -operator>=(const basic_string& x, - const basic_string& y) - { return !(x < y); } - -template -inline bool -operator>=(const CharT* s, const basic_string& y) - { return !(s < y); } - -template -inline bool -operator>=(const basic_string& x, const CharT* s) - { return !(x < s); } - -// Swap. -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline void swap(basic_string& x, basic_string& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > mx, basic_string& y) -{ mx.get().swap(y); } - -template -inline void swap(basic_string& x, detail::moved_object > my) -{ x.swap(my.get()); } -#else -template -inline void swap(basic_string && x, basic_string &&y) -{ x.swap(y); } -#endif - -/// @cond -// I/O. -namespace detail { - -template -inline bool -interprocess_string_fill(std::basic_ostream& os, - std::basic_streambuf* buf, - std::size_t n) -{ - CharT f = os.fill(); - std::size_t i; - bool ok = true; - - for (i = 0; i < n; i++) - ok = ok && !Traits::eq_int_type(buf->sputc(f), Traits::eof()); - return ok; -} - -} //namespace detail { -/// @endcond - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - const basic_string& s) - #else - const basic_string&&s) - #endif -{ - typename std::basic_ostream::sentry sentry(os); - bool ok = false; - - if (sentry) { - ok = true; - std::size_t n = s.size(); - std::size_t pad_len = 0; - const bool left = (os.flags() & std::ios::left) != 0; - const std::size_t w = os.width(0); - std::basic_streambuf* buf = os.rdbuf(); - - if (w != 0 && n < w) - pad_len = w - n; - - if (!left) - ok = 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_INTERPROCESS_RVALUE_REFERENCE -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - detail::moved_object > ms) -{ return os << ms.get(); } -#endif - - -template -std::basic_istream& -operator>>(std::basic_istream& is, - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& s) - #else - basic_string&&s) - #endif -{ - typename std::basic_istream::sentry sentry(is); - - if (sentry) { - std::basic_streambuf* buf = is.rdbuf(); - const std::ctype& ctype = std::use_facet >(is.getloc()); - - s.clear(); - std::size_t n = is.width(0); - if (n == 0) - n = static_cast(-1); - else - s.reserve(n); - - while (n-- > 0) { - typename Traits::int_type c1 = buf->sbumpc(); - - if (Traits::eq_int_type(c1, Traits::eof())) { - is.setstate(std::ios_base::eofbit); - break; - } - else { - CharT c = Traits::to_char_type(c1); - - if (ctype.is(std::ctype::space, c)) { - if (Traits::eq_int_type(buf->sputbackc(c), Traits::eof())) - is.setstate(std::ios_base::failbit); - break; - } - else - s.push_back(c); - } - } - - // If we have read no characters, then set failbit. - if (s.size() == 0) - is.setstate(std::ios_base::failbit); - } - else - is.setstate(std::ios_base::failbit); - - return is; -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -std::basic_istream& -operator>>(std::basic_istream& is, - detail::moved_object > ms) -{ return is >> ms.get(); } -#endif - -template -std::basic_istream& -getline(std::istream& is, - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_string& s, - #else - basic_string&&s, - #endif - CharT delim) -{ - std::size_t nread = 0; - typename std::basic_istream::sentry sentry(is, true); - if (sentry) { - std::basic_streambuf* buf = is.rdbuf(); - s.clear(); - - int c1; - while (nread < s.max_size()) { - int c1 = buf->sbumpc(); - if (Traits::eq_int_type(c1, Traits::eof())) { - is.setstate(std::ios_base::eofbit); - break; - } - else { - ++nread; - CharT c = Traits::to_char_type(c1); - if (!Traits::eq(c, delim)) - s.push_back(c); - else - break; // Character is extracted but not appended. - } - } - } - if (nread == 0 || nread >= s.max_size()) - is.setstate(std::ios_base::failbit); - - return is; -} - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -std::basic_istream& -getline(std::istream& is, - detail::moved_object > ms, - CharT delim) -{ return getline(is, ms.get(), delim); } -#endif - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline std::basic_istream& -getline(std::basic_istream& is, - basic_string& s) -{ - return getline(is, s, '\n'); -} - -template -std::basic_istream& -getline(std::istream& is, - detail::moved_object > ms) -{ return getline(is, ms.get()); } -#else -template -std::basic_istream& -getline(std::istream& is, - basic_string && ms) -{ return getline(is, ms); } -#endif - -template -inline std::size_t hash_value(basic_string, A> const& v) -{ - return hash_range(v.begin(), v.end()); -} - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond - -}} //namespace boost { namespace interprocess +} //namespace interprocess { +} //namespace boost { #include -#endif // BOOST_INTERPROCESS_STRING_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP diff --git a/include/boost/interprocess/containers/vector.hpp b/include/boost/interprocess/containers/vector.hpp index 680bb82..d6f31c2 100644 --- a/include/boost/interprocess/containers/vector.hpp +++ b/include/boost/interprocess/containers/vector.hpp @@ -1,1998 +1,32 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2008. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// -// -// 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 +#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace interprocess { -/// @cond - -namespace detail { - -//! Const vector_iterator used to iterate through a vector. -template -class vector_const_iterator - : public std::iterator::value_type - ,typename std::iterator_traits::difference_type - ,typename pointer_to_other - ::value_type - >::type - ,const typename std::iterator_traits::value_type &> -{ - public: - typedef const typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename pointer_to_other::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 vector_iterator - : public vector_const_iterator -{ - public: - explicit vector_iterator(Pointer ptr) - : vector_const_iterator(ptr) - {} - - public: - typedef typename std::iterator_traits::value_type value_type; - typedef typename vector_const_iterator::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& right) const - { return static_cast&>(*this) - right; } -}; - -template -struct vector_value_traits -{ - typedef T value_type; - typedef A allocator_type; - static const bool trivial_dctr = boost::has_trivial_destructor::value; - static const bool trivial_dctr_after_move = - has_trivial_destructor_after_move::value || trivial_dctr; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; - static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = has_nothrow_assign::value; - - //This is the anti-exception array destructor - //to deallocate values already constructed - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type OldArrayDestructor; - //This is the anti-exception array destructor - //to destroy objects created with copy construction - typedef typename detail::if_c - - ,detail::scoped_destructor_n - >::type UCopiedArrayDestructor; - //This is the anti-exception array deallocator - typedef typename detail::if_c - - ,detail::scoped_array_deallocator - >::type UCopiedArrayDeallocator; - - //This is the optimized move iterator for copy constructors - //so that std::copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,const T* - ,detail::move_iterator - >::type copy_move_it; - - //This is the optimized move iterator for assignments - //so that std::uninitialized_copy and similar can use memcpy - typedef typename detail::if_c - ::value - #endif - ,const T* - ,detail::move_iterator - >::type assign_move_it; -}; - -//!This struct deallocates and allocated memory -template -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_traits; - - //Constructor, does not throw - vector_alloc_holder(const A &a) - : members_(a) - {} - - //Constructor, does not throw - vector_alloc_holder(const vector_alloc_holder &h) - : members_(h.alloc()) - {} - - //Destructor - ~vector_alloc_holder() - { - this->prot_destroy_all(); - this->prot_deallocate(); - } - - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant allocator_v2; - typedef detail::integral_constant::value> alloc_version; - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, const pointer &reuse = 0) - { - return allocation_command(command, limit_size, preferred_size, - received_size, reuse, alloc_version()); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v1) - { - (void)limit_size; - (void)reuse; - if(!(command & allocate_new)) - return std::pair(pointer(0), 0); - received_size = preferred_size; - return std::make_pair(this->alloc().allocate(received_size), false); - } - - std::pair - allocation_command(allocation_type command, - size_type limit_size, - size_type preferred_size, - size_type &received_size, - const pointer &reuse, - allocator_v2) - { - return 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 vector : private detail::vector_alloc_holder -{ - /// @cond - typedef vector self_t; - typedef detail::vector_alloc_holder 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 iterator; - //! The random access const_iterator - typedef detail::vector_const_iterator const_iterator; - - //! Iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - reverse_iterator; - //! Const iterator used to iterate backwards through a vector. - typedef std::reverse_iterator - const_reverse_iterator; - //! The stored allocator type - typedef allocator_type stored_allocator_type; - - /// @cond - private: - typedef detail::advanced_insert_aux_int advanced_insert_aux_int_t; - typedef detail::vector_value_traits 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 cvalue_iterator; - typedef repeat_iterator repeat_it; - typedef detail::move_iterator repeat_move_it; - /// @endcond - - public: - - //! Effects: Constructs a vector taking the allocator as parameter. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - explicit vector(const A& a = A()) - : base_t(a) - {} - - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's default or copy constructor throws. - //! - //! Complexity: Linear to n. - vector(size_type n, const T& value = T(), - const allocator_type& a = allocator_type()) - : base_t(a) - { this->insert(this->cend(), n, value); } - - //! Effects: Copy constructs a vector. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - vector(const vector& x) - : base_t((base_t&)x) - { *this = x; } - - //! Effects: Move constructor. Moves mx's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - vector(detail::moved_object > mx) - : base_t(mx.get()) - { this->swap(mx.get()); } - #else - vector(vector && mx) - : base_t(detail::move_impl(mx)) - { this->swap(mx); } - #endif - - //! Effects: Constructs a vector that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the vector. - //! - //! Throws: If allocator_type's default constructor or copy constructor - //! throws or T's constructor taking an dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - vector(InIt first, InIt last, const allocator_type& a = allocator_type()) - : base_t(a) - { this->assign(first, last); } - - //! Effects: Destroys the vector. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - ~vector() - {} //vector_alloc_holder clears the data - - //! Effects: Returns an iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator begin() - { return iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator begin() const - { return const_iterator(this->members_.m_start); } - - //! Effects: Returns an iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - iterator end() - { return iterator(this->members_.m_start + this->members_.m_size); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator end() const - { return this->cend(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rbegin() - { return reverse_iterator(this->end()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rbegin()const - { return this->crbegin(); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reverse_iterator rend() - { return reverse_iterator(this->begin()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator rend() const - { return this->crend(); } - - //! Effects: Returns a const_iterator to the first element contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cbegin() const - { return const_iterator(this->members_.m_start); } - - //! Effects: Returns a const_iterator to the end of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_iterator cend() const - { return const_iterator(this->members_.m_start + this->members_.m_size); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crbegin()const - { return const_reverse_iterator(this->end());} - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reverse_iterator crend() const - { return const_reverse_iterator(this->begin()); } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference front() - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference front() const - { return *this->members_.m_start; } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference back() - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference back() const - { return this->members_.m_start[this->members_.m_size - 1]; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - pointer data() - { return this->members_.m_start; } - - //! Returns: A pointer such that [data(),data() + size()) is a valid range. - //! For a non-empty vector, data() == &front(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_pointer data() const - { return this->members_.m_start; } - - //! Effects: Returns the number of the elements contained in the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type size() const - { return this->members_.m_size; } - - //! Effects: Returns the largest possible size of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type max_size() const - { return this->alloc().max_size(); } - - //! Effects: Number of elements for which memory has been allocated. - //! capacity() is always greater than or equal to size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - size_type capacity() const - { return this->members_.m_capacity; } - - //! Effects: Returns true if the vector contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - bool empty() const - { return !this->members_.m_size; } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - reference operator[](size_type n) - { return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - const_reference operator[](size_type n) const - { return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - reference at(size_type n) - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Requires: size() < n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: std::range_error if n >= size() - //! - //! Complexity: Constant. - const_reference at(size_type n) const - { this->priv_check_range(n); return this->members_.m_start[n]; } - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: 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(); } - - //! Effects: 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. - //! - //! Throws: 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 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 - typename value_traits::copy_move_it dummy_it(detail::get_pointer(this->members_.m_start)); - detail::advanced_insert_aux_proxy - proxy(dummy_it, 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); - } - } - } - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - vector& operator=(const vector& x) - { - if (&x != this){ - this->assign(x.members_.m_start, x.members_.m_start + x.members_.m_size); - } - return *this; - } - - //! Effects: Move assignment. All mx's values are transferred to *this. - //! - //! Postcondition: x.empty(). *this contains a the elements x had - //! before the function. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - vector& operator=(detail::moved_object > mx) - { - vector &x = mx.get(); - #else - vector& operator=(vector && x) - { - #endif - if (&x != this){ - this->swap(x); - x.clear(); - } - return *this; - } - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void assign(size_type n, const value_type& val) - { this->assign(cvalue_iterator(val, n), cvalue_iterator()); } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InpIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_assign_dispatch(first, last, Result()); - } - - //! Effects: Inserts a copy of x at the end of the vector. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: 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); - } - } - - //! Effects: Constructs a new element in the end of the vector - //! and moves the resources of mx to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void push_back(detail::moved_object 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(detail::move_impl(x)); - ++this->members_.m_size; - } - else{ - this->insert(this->cend(), detail::move_impl(x)); - } - } - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the vector. - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: Amortized constant time. - template - 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(detail::forward_impl(args)...); - ++this->members_.m_size; - } - else{ - detail::advanced_insert_aux_emplace proxy - (detail::forward_impl(args)...); - priv_range_insert(back_pos, 1, proxy); - } - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before position - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - template - 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 proxy - (detail::forward_impl(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 proxy; - priv_range_insert(back_pos, 1, proxy); - } - } - - iterator emplace(const_iterator position) - { - size_type pos_n = position - cbegin(); - detail::advanced_insert_aux_emplace 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 \ - 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) \ - \ - proxy(BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_FORWARD, _)); \ - priv_range_insert(back_pos, 1, proxy); \ - } \ - } \ - \ - template \ - 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) \ - \ - 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 - - //! Effects: Swaps the contents of *this and x. - //! If this->allocator_type() != x.allocator_type() - //! allocators are also swapped. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object 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); - } - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before position. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: 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); - } - - //! Requires: position must be a valid iterator of *this. - //! - //! Effects: Insert a new element before position with mx's resources. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: If position is end(), amortized constant time - //! Linear time otherwise. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - iterator insert(const_iterator position, detail::moved_object 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); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before pos. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InpIt throws or T's copy constructor throws. - //! - //! Complexity: Linear to std::distance [first, last). - template - void insert(const_iterator pos, InIt first, InIt last) - { - //Dispatch depending on integer/iterator - const bool aux_boolean = detail::is_convertible::value; - typedef detail::bool_ Result; - this->priv_insert_dispatch(pos, first, last, Result()); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - void insert(const_iterator p, size_type n, const T& x) - { this->insert(p, cvalue_iterator(x, n), cvalue_iterator()); } - - //! Effects: Removes the last element from the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: 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); - } - - //! Effects: Erases the element at position pos. - //! - //! Throws: Nothing. - //! - //! Complexity: 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); - typedef typename value_traits::assign_move_it assign_move_it; - std::copy(assign_move_it(pos + 1), assign_move_it(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()); - } - - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and last. - iterator erase(const_iterator first, const_iterator last) - { - typedef typename value_traits::assign_move_it assign_move_it; - 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(std::copy - (assign_move_it(detail::get_pointer(last.get_ptr())) - ,assign_move_it(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()); - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default constructed. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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 proxy(n); - priv_range_insert(this->cend().get_ptr(), n, proxy); - } - } - - //! Effects: Erases all the elements of the vector. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the vector. - void clear() - { this->prot_destroy_all(); } - - /// @cond - - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the vector is unchanged - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: 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(*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 - 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 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 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) - { - typedef typename value_traits::copy_move_it copy_move_it; - typedef typename value_traits::assign_move_it assign_move_it; - //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 - std::uninitialized_copy(copy_move_it(old_finish - n), copy_move_it(old_finish), old_finish); - this->members_.m_size += n; - //Copy previous to last objects to the initialized end - std::copy_backward(assign_move_it(pos), assign_move_it(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 - std::uninitialized_copy - ( copy_move_it(pos), copy_move_it(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) - { - typedef typename value_traits::copy_move_it copy_move_it; - 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 = std::uninitialized_copy - ( copy_move_it(detail::get_pointer(this->members_.m_start)) - , copy_move_it(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 = std::uninitialized_copy - ( copy_move_it(pos) - , copy_move_it(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) - { - typedef typename value_traits::copy_move_it copy_move_it; - typedef typename value_traits::assign_move_it assign_move_it; - - //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 - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(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 - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(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 - std::uninitialized_copy - (copy_move_it(pos), copy_move_it(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 = std::copy(assign_move_it(pos + raw_gap), assign_move_it(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); - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(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 = std::copy(assign_move_it(start_n), assign_move_it(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 = std::copy(assign_move_it(pos), assign_move_it(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 - std::uninitialized_copy(copy_move_it(old_start), copy_move_it(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 = std::copy(copy_move_it(pos), copy_move_it(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); - std::uninitialized_copy - (copy_move_it(finish_n), copy_move_it(old_finish), old_finish); - this->members_.m_size += n_after; - //Displace the rest of old_end to the new position - std::copy_backward(assign_move_it(pos), assign_move_it(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; - std::uninitialized_copy(copy_move_it(pos), copy_move_it(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 - void priv_range_insert(const_iterator pos, InIt first, InIt last, std::input_iterator_tag) - { - for(;first != last; ++first){ - this->insert(pos, detail::move_impl(value_type(*first))); - } - } - - template - void priv_assign_aux(InIt first, InIt last, std::input_iterator_tag) - { - //Overwrite all elements we can from [first, last) - iterator cur = begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ - *cur = *first; - } - - if (first == last){ - //There are no more elements in the sequence, erase remaining - this->erase(cur, cend()); - } - else{ - //There are more elements in the range, insert the remaining ones - this->insert(this->cend(), first, last); - } - } - - template - void priv_assign_aux(FwdIt first, FwdIt last, - std::forward_iterator_tag) - { - size_type n = std::distance(first, last); - //Check if we have enough memory or try to expand current memory - size_type remaining = this->members_.m_capacity - this->members_.m_size; - bool same_buffer_start; - std::pair 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 - 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()); - T *end = std::copy(first, mid, start); - //Initialize the remaining new elements in the uninitialized memory - std::uninitialized_copy(mid, last, end); - this->members_.m_size = n; - } - } - else if(!ret.second){ - typename value_traits::UCopiedArrayDeallocator scoped_alloc(ret.first, this->alloc(), real_cap); - std::uninitialized_copy(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); - std::uninitialized_copy(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); - std::copy(mid, mid2, old_start); - - //Check if we still have to append elements in the - //uninitialized end - if(second_count == 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 - void priv_assign_dispatch(Integer n, Integer val, detail::true_) - { this->assign((size_type) n, (T) val); } - - template - void priv_assign_dispatch(InIt first, InIt last, detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_assign_aux(first, last, ItCat()); - } - - template - void priv_insert_dispatch(const_iterator pos, Integer n, Integer val, detail::true_) - { this->insert(pos, (size_type)n, (T)val); } - - template - void priv_insert_dispatch(const_iterator pos, InIt first, - InIt last, detail::false_) - { - //Dispatch depending on integer/iterator - typedef typename - std::iterator_traits::iterator_category ItCat; - this->priv_range_insert(pos.get_ptr(), first, last, ItCat()); - } - - void priv_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 -inline bool -operator==(const vector& x, const vector& y) -{ - //Check first size and each element if needed - return x.size() == y.size() && - std::equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool -operator!=(const vector& x, const vector& y) -{ - //Check first size and each element if needed - return x.size() != y.size() || - !std::equal(x.begin(), x.end(), y.begin()); -} - -template -inline bool -operator<(const vector& x, const vector& y) -{ - return std::lexicographical_compare(x.begin(), x.end(), - y.begin(), y.end()); -} - -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) -template -inline void swap(vector& x, vector& y) -{ x.swap(y); } - -template -inline void swap(detail::moved_object > x, vector& y) -{ x.get().swap(y); } - -template -inline void swap(vector &x, detail::moved_object > y) -{ x.swap(y.get()); } -#else -template -inline void swap(vector&&x, vector&&y) -{ x.swap(y); } -#endif - -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - enum { value = has_trivial_destructor::value }; -}; -/// @endcond +using boost::interprocess_container::vector; } //namespace interprocess { } //namespace boost { #include -#endif // #ifndef BOOST_INTERPROCESS_VECTOR_HPP +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP diff --git a/include/boost/interprocess/containers/version_type.hpp b/include/boost/interprocess/containers/version_type.hpp new file mode 100644 index 0000000..06e7419 --- /dev/null +++ b/include/boost/interprocess/containers/version_type.hpp @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP +#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace interprocess { + +using boost::interprocess_container::containers_detail::version_type; +using boost::interprocess_container::containers_detail::version; + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP + diff --git a/include/boost/interprocess/detail/atomic.hpp b/include/boost/interprocess/detail/atomic.hpp index 094bc0c..b8a8086 100644 --- a/include/boost/interprocess/detail/atomic.hpp +++ b/include/boost/interprocess/detail/atomic.hpp @@ -48,7 +48,7 @@ inline boost::uint32_t atomic_cas32 } //namespace interprocess{ } //namespace boost{ -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) #include diff --git a/include/boost/interprocess/detail/file_wrapper.hpp b/include/boost/interprocess/detail/file_wrapper.hpp index 22f92e9..091a14f 100644 --- a/include/boost/interprocess/detail/file_wrapper.hpp +++ b/include/boost/interprocess/detail/file_wrapper.hpp @@ -24,7 +24,12 @@ namespace detail{ class file_wrapper { + /// @cond + file_wrapper(file_wrapper&); + file_wrapper & operator=(file_wrapper&); + /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_wrapper) //!Default constructor. //!Represents an empty file_wrapper. @@ -49,34 +54,18 @@ class file_wrapper //!Moves the ownership of "moved"'s file to *this. //!After the call, "moved" does not represent any file. //!Does not throw - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - file_wrapper - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - file_wrapper(file_wrapper &&moved) + file_wrapper(BOOST_INTERPROCESS_RV_REF(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_INTERPROCESS_RVALUE_REFERENCE - file_wrapper &operator= - (detail::moved_object moved) + file_wrapper &operator=(BOOST_INTERPROCESS_RV_REF(file_wrapper) moved) { - file_wrapper tmp(moved); + file_wrapper tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - file_wrapper &operator=(file_wrapper &&moved) - { - file_wrapper tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif //!Swaps to file_wrappers. //!Does not throw diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index ab0744c..72645e2 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -98,7 +98,7 @@ class basic_managed_memory_impl segment_manager::char_ptr_holder_t char_ptr_holder_t; //Experimental. Don't use. - typedef typename segment_manager::multiallocation_iterator multiallocation_iterator; + typedef typename segment_manager::multiallocation_chain multiallocation_chain; /// @endcond @@ -291,7 +291,7 @@ class basic_managed_memory_impl template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0) { @@ -310,21 +310,25 @@ class basic_managed_memory_impl //Experimental. Don't use. //!Allocates n_elements of elem_size bytes. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements) + 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_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements) + 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_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t nothrow) + 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_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow) + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::nothrow_t nothrow) { return mp_header->allocate_many(elem_sizes, n_elements, nothrow); } + //!Allocates n_elements, each one of elem_sizes[i] bytes. + void deallocate_many(multiallocation_chain chain) + { return mp_header->deallocate_many(boost::interprocess::move(chain)); } + /// @endcond //!Marks previously allocated memory as free. Never throws. diff --git a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp index 3a3b0c9..948e865 100644 --- a/include/boost/interprocess/detail/managed_multi_shared_memory.hpp +++ b/include/boost/interprocess/detail/managed_multi_shared_memory.hpp @@ -315,21 +315,21 @@ class basic_managed_multi_shared_memory case create_open_func::DoCreate: { managed_impl shm(create_only, name, size, read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; case create_open_func::DoOpen: { managed_impl shm(open_only, name,read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; case create_open_func::DoOpenOrCreate: { managed_impl shm(open_or_create, name, size, read_write, addr, func); - mshm = detail::move_impl(shm); + mshm = boost::interprocess::move(shm); } break; @@ -339,7 +339,7 @@ class basic_managed_multi_shared_memory } //This can throw. - m_shmem_list.push_back(detail::move_impl(mshm)); + m_shmem_list.push_back(boost::interprocess::move(mshm)); return true; } BOOST_CATCH(const std::bad_alloc&){ diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index caa7741..d71ec1b 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -37,8 +37,8 @@ template class managed_open_or_create_impl { //Non-copyable - managed_open_or_create_impl(const managed_open_or_create_impl &); - managed_open_or_create_impl &operator=(const managed_open_or_create_impl &); + managed_open_or_create_impl(managed_open_or_create_impl &); + managed_open_or_create_impl &operator=(managed_open_or_create_impl &); enum { @@ -49,6 +49,7 @@ class managed_open_or_create_impl }; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(managed_open_or_create_impl) static const std::size_t ManagedOpenOrCreateUserOffset = @@ -154,34 +155,16 @@ class managed_open_or_create_impl , construct_func); } - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl(detail::moved_object moved) - { this->swap(moved.get()); } - #else - managed_open_or_create_impl(managed_open_or_create_impl &&moved) + managed_open_or_create_impl(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved) { this->swap(moved); } - #endif - //!Move assignment. If *this owns a memory mapped region, it will be - //!destroyed and it will take ownership of "other"'s memory mapped region. - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - managed_open_or_create_impl &operator=(detail::moved_object moved) + managed_open_or_create_impl &operator=(BOOST_INTERPROCESS_RV_REF(managed_open_or_create_impl) moved) { - managed_open_or_create_impl tmp(moved); + managed_open_or_create_impl tmp(boost::interprocess::move(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(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif - ~managed_open_or_create_impl() {} @@ -437,20 +420,6 @@ inline void swap(managed_open_or_create_impl &x } //namespace detail { - -///@cond - -//!Trait class to detect if a type is -//!movable -template - -struct is_movable > -{ - enum { value = true }; -}; - -///@endcond - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index ca5c0e2..7fcead5 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -1,175 +1,749 @@ ////////////////////////////////////////////////////////////////////////////// // -// (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) +// (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) // -// See http://www.boost.org/libs/interprocess for documentation. +// See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// +// +// Parts of this file come from Adobe's Move library: +// +// Copyright 2005-2007 Adobe Systems Incorporated +// Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt +// or a copy at http://stlab.adobe.com/licenses.html) +// +////////////////////////////////////////////////////////////////////////////// + +//! \file #ifndef BOOST_INTERPROCESS_MOVE_HPP #define BOOST_INTERPROCESS_MOVE_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include -#include - -//!\file -//!Describes a function and a type to emulate move semantics. +#include +#include //copy, copy_backward +#include //uninitialized_copy +#include //std::iterator +#include +#include +#include namespace boost { namespace interprocess { +namespace move_detail { -//!Trait class to detect if a type is -//!movable template -struct is_movable +struct identity { - enum { value = false }; + typedef T type; }; +template +class is_convertible +{ + typedef char true_t; + class false_t { char dummy[2]; }; + static true_t dispatch(U); + static false_t dispatch(...); + static T trigger(); + public: + enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; +}; + +} //namespace move_detail { } //namespace interprocess { } //namespace boost { -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - -#include -#include +#if !defined(BOOST_HAS_RVALUE_REFS) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) namespace boost { namespace interprocess { -namespace detail { -//!An object that represents a -//!moved object. -template -struct moved_object -{ - moved_object(const T &obj) - : m_obj(const_cast(&obj)) - {} - - T &get() const - { return *m_obj; } - - private: - T *m_obj; -}; - -// Metafunction that, given movable T, provides move_source, else T&. -template -struct move_type +////////////////////////////////////////////////////////////////////////////// +// +// struct rv +// +////////////////////////////////////////////////////////////////////////////// +template +class rv : public T { - public: // metafunction result - typedef typename if_, moved_object, T&>::type type; -}; - -template -class move_return -{ - typedef moved_object moved_type; - private: - mutable T m_moved; - + rv(); + ~rv(); + rv(rv const&); + void operator=(rv const&); public: - typedef T type; - - move_return(const T& returned) - : m_moved(moved_object(returned)) - {} - - move_return(const move_return& operand) - : m_moved(const_cast(operand)) - {} - - operator moved_type() const - { return moved_type(m_moved); } + //T &get() { return *this; } }; -template -struct return_type +////////////////////////////////////////////////////////////////////////////// +// +// move_detail::is_rv +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { + +template +struct is_rv { - public: // metafunction result - - typedef typename if_, move_return, T>::type type; + static const bool value = false; }; -} //namespace detail { -} //namespace interprocess { -} //namespace boost { +template +struct is_rv< rv > +{ + static const bool value = true; +}; -namespace boost { -namespace interprocess { +} //namespace move_detail { -namespace detail{ +////////////////////////////////////////////////////////////////////////////// +// +// is_movable +// +////////////////////////////////////////////////////////////////////////////// +template +class is_movable +{ + public: + static const bool value = move_detail::is_convertible&>::value; +}; -//!A function that converts an object to a moved object so that -//!it can match a function taking a detail::moved_object object. -template -typename detail::move_type::type move_impl(const Object &object) -{ - typedef typename detail::move_type::type type; - return type(object); +template +class is_movable< rv > +{ + public: + static const bool value = false; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// move() +// +////////////////////////////////////////////////////////////////////////////// +template +typename boost::disable_if, T&>::type move(T& x) +{ + return x; } template -inline const T& forward_impl(const T &t) -{ return t; } +typename enable_if, rv&>::type move(T& x) +{ + return static_cast& >(x); +} template -inline T& forward_impl(T &t) -{ return t; } +typename enable_if, rv&>::type move(const rv& x) +{ + return const_cast& >(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// forward() +// +////////////////////////////////////////////////////////////////////////////// template -inline detail::moved_object forward_impl(detail::moved_object &t) -{ return t; } +typename enable_if, T &>::type + forward(const typename move_detail::identity::type &x) +{ + return const_cast(x); +} -} //namespace detail { +/* +template +typename enable_if, T &>::type +forward(typename move_detail::identity::type &x) +{ + return x; +} -//!A function that converts an object to a moved object so that -//!it can match a function taking a detail::moved_object object. -template -typename detail::move_type::type move(const Object &object) -{ return detail::move_impl(object); } +template +typename disable_if, T &>::type + forward(typename move_detail::identity::type &x) +{ + return x; +} +*/ +template +typename disable_if, const T &>::type + forward(const typename move_detail::identity::type &x) +{ + return x; +} +////////////////////////////////////////////////////////////////////////////// +// +// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION +// +////////////////////////////////////////////////////////////////////////////// +#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ + operator boost::interprocess::rv&() \ + { return static_cast& >(*this); }\ + operator const boost::interprocess::rv&() \ + { return static_cast& >(*this); }\ +// + + +#define BOOST_INTERPROCESS_RV_REF(TYPE)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ + boost::interprocess::rv< TYPE >& \ +// + +#define BOOST_INTERPROCESS_FWD_REF(TYPE)\ + const TYPE & \ +// } //namespace interprocess { -} //namespace boost { +} //namespace boost -#else //#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#else //BOOST_HAS_RVALUE_REFS -#include +#include namespace boost { namespace interprocess { -namespace detail { +////////////////////////////////////////////////////////////////////////////// +// +// is_movable +// +////////////////////////////////////////////////////////////////////////////// -template -inline typename detail::remove_reference::type&& move_impl(T&& t) +//! For compilers with rvalue references, this traits class returns true +//! if T && is convertible to T. +//! +//! For other compilers returns true if T is convertible to boost::interprocess::rv& +template +class is_movable +{ + public: + static const bool value = move_detail::is_convertible::value; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +//! This function provides a way to convert a reference into a rvalue reference +//! in compilers with rvalue reference. For other compilers converts T & into +//! boost::interprocess::rv & so that move emulation is activated. +template inline +rvalue_reference move (input_reference); +#else +template inline +typename remove_reference::type&& move(T&& t) { return t; } +#endif -template -inline T&& forward_impl(typename detail::identity::type&& t) +////////////////////////////////////////////////////////////////////////////// +// +// forward +// +////////////////////////////////////////////////////////////////////////////// + + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +//! This function provides limited form of forwarding that is usually enough for +//! in-place construction and avoids the exponential overloading necessary for +//! perfect forwarding in C++03. +//! +//! For compilers with rvalue references this function provides perfect forwarding. +//! +//! Otherwise: +//! * If input_reference binds to const boost::interprocess::rv & then it output_reference is +//! boost::rev & +//! +//! * Else, input_reference is equal to output_reference is equal to input_reference. +template inline output_reference forward(input_reference); +#else +template inline +T&& forward (typename move_detail::identity::type&& t) { return t; } +#endif -} //namespace detail { +////////////////////////////////////////////////////////////////////////////// +// +// BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION +// +////////////////////////////////////////////////////////////////////////////// -template -inline typename detail::remove_reference::type&& move(T&& t) -{ return t; } +//! This macro expands to nothing for compilers with rvalue references. +//! Otherwise expands to: +//! \code +//! operator boost::interprocess::rv&() +//! { return static_cast& >(*this); } +//! \endcode +#define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ +// + +#define BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(TYPE, ARG1, ARG2)\ + TYPE && \ +// + +#define BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(TYPE, ARG1, ARG2, ARG3)\ + TYPE && \ +// + +//! This macro expands to T&& for compilers with rvalue references. +//! Otherwise expands to boost::interprocess::rv &. +#define BOOST_INTERPROCESS_RV_REF(TYPE)\ + TYPE && \ +// + +//! This macro expands to T&& for compilers with rvalue references. +//! Otherwise expands to const T &. +#define BOOST_INTERPROCESS_FWD_REF(TYPE)\ + TYPE && \ +// } //namespace interprocess { } //namespace boost { -#endif //#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#endif //BOOST_HAS_RVALUE_REFS -#include +namespace boost { +namespace interprocess { -#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP +////////////////////////////////////////////////////////////////////////////// +// +// move_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! Class template move_iterator is an iterator adaptor with the same behavior +//! as the underlying iterator except that its dereference operator implicitly +//! converts the value returned by the underlying iterator's dereference operator +//! to an rvalue reference. Some generic algorithms can be called with move +//! iterators to replace copying with moving. +template +class move_iterator +{ + public: + typedef It iterator_type; + typedef typename std::iterator_traits::value_type value_type; + #if defined(BOOST_HAS_RVALUE_REFS) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + typedef value_type && reference; + #else + typedef typename boost::mpl::if_ + < boost::interprocess::is_movable + , boost::interprocess::rv& + , value_type & >::type reference; + #endif + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::iterator_category iterator_category; + + move_iterator() + {} + + explicit move_iterator(It i) + : m_it(i) + {} + + template + move_iterator(const move_iterator& u) + : m_it(u.base()) + {} + + iterator_type base() const + { return m_it; } + + reference operator*() const + { + #if defined(BOOST_HAS_RVALUE_REFS) + return *m_it; + #else + return boost::interprocess::move(*m_it); + #endif + } + + pointer operator->() const + { return m_it; } + + move_iterator& operator++() + { ++m_it; return *this; } + + move_iterator operator++(int) + { move_iterator tmp(*this); ++(*this); return tmp; } + + move_iterator& operator--() + { --m_it; return *this; } + + move_iterator operator--(int) + { move_iterator tmp(*this); --(*this); return tmp; } + + move_iterator operator+ (difference_type n) const + { return move_iterator(m_it + n); } + + move_iterator& operator+=(difference_type n) + { m_it += n; return *this; } + + move_iterator operator- (difference_type n) const + { return move_iterator(m_it - n); } + + move_iterator& operator-=(difference_type n) + { m_it -= n; return *this; } + + reference operator[](difference_type n) const + { + #if defined(BOOST_HAS_RVALUE_REFS) + return m_it[n]; + #else + return boost::interprocess::move(m_it[n]); + #endif + } + + friend bool operator==(const move_iterator& x, const move_iterator& y) + { return x.base() == y.base(); } + + friend bool operator!=(const move_iterator& x, const move_iterator& y) + { return x.base() != y.base(); } + + friend bool operator< (const move_iterator& x, const move_iterator& y) + { return x.base() < y.base(); } + + friend bool operator<=(const move_iterator& x, const move_iterator& y) + { return x.base() <= y.base(); } + + friend bool operator> (const move_iterator& x, const move_iterator& y) + { return x.base() > y.base(); } + + friend bool operator>=(const move_iterator& x, const move_iterator& y) + { return x.base() >= y.base(); } + + friend difference_type operator-(const move_iterator& x, const move_iterator& y) + { return x.base() - y.base(); } + + friend move_iterator operator+(difference_type n, const move_iterator& x) + { return move_iterator(x.base() + n); } + + private: + It m_it; +}; + + +//is_move_iterator +namespace move_detail { + +template +struct is_move_iterator +{ + static const bool value = false; +}; + +template +struct is_move_iterator< ::boost::interprocess::move_iterator > +{ + static const bool value = true; +}; + +} //namespace move_detail { + +////////////////////////////////////////////////////////////////////////////// +// +// move_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! +//! Returns: move_iterator(i). +template +move_iterator make_move_iterator(const It &it) +{ return move_iterator(it); } + +////////////////////////////////////////////////////////////////////////////// +// +// back_move_insert_iterator +// +////////////////////////////////////////////////////////////////////////////// + + +//! A move insert iterator that move constructs elements at the +//! back of a container +template // C models Container +class back_move_insert_iterator + : public std::iterator +{ + C* container_m; + + public: + typedef C container_type; + + explicit back_move_insert_iterator(C& x) : container_m(&x) { } + + back_move_insert_iterator& operator=(typename C::reference x) + { container_m->push_back(boost::interprocess::move(x)); return *this; } + + back_move_insert_iterator& operator*() { return *this; } + back_move_insert_iterator& operator++() { return *this; } + back_move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: back_move_insert_iterator(x). +template // C models Container +inline back_move_insert_iterator back_move_inserter(C& x) +{ + return back_move_insert_iterator(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// front_move_insert_iterator +// +////////////////////////////////////////////////////////////////////////////// + +//! A move insert iterator that move constructs elements int the +//! front of a container +template // C models Container +class front_move_insert_iterator + : public std::iterator +{ + C* container_m; + +public: + typedef C container_type; + + explicit front_move_insert_iterator(C& x) : container_m(&x) { } + + front_move_insert_iterator& operator=(typename C::reference x) + { container_m->push_front(boost::interprocess::move(x)); return *this; } + + front_move_insert_iterator& operator*() { return *this; } + front_move_insert_iterator& operator++() { return *this; } + front_move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: front_move_insert_iterator(x). +template // C models Container +inline front_move_insert_iterator front_move_inserter(C& x) +{ + return front_move_insert_iterator(x); +} + +////////////////////////////////////////////////////////////////////////////// +// +// insert_move_iterator +// +////////////////////////////////////////////////////////////////////////////// +template // C models Container +class move_insert_iterator + : public std::iterator +{ + C* container_m; + typename C::iterator pos_; + + public: + typedef C container_type; + + explicit move_insert_iterator(C& x, typename C::iterator pos) + : container_m(&x), pos_(pos) + {} + + move_insert_iterator& operator=(typename C::reference x) + { + pos_ = container_m->insert(pos_, boost::interprocess::move(x)); + ++pos_; + return *this; + } + + move_insert_iterator& operator*() { return *this; } + move_insert_iterator& operator++() { return *this; } + move_insert_iterator& operator++(int) { return *this; } +}; + +//! +//! Returns: move_insert_iterator(x, it). +template // C models Container +inline move_insert_iterator move_inserter(C& x, typename C::iterator it) +{ + return move_insert_iterator(x, it); +} + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + + +//! Effects: Moves elements in the range [first,last) into the range [result,result + (last - +//! first)) starting from first and proceeding to last. For each non-negative integer n < (last-first), +//! performs *(result + n) = boost::interprocess::move (*(first + n)). +//! +//! Effects: result + (last - first). +//! +//! Requires: result shall not be in the range [first,last). +//! +//! Complexity: Exactly last - first move assignments. +template // O models OutputIterator +O move(I f, I l, O result) +{ + while (f != l) { + *result = boost::interprocess::move(*f); + ++f; ++result; + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// +// move_backward +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: Moves elements in the range [first,last) into the range +//! [result - (last-first),result) starting from last - 1 and proceeding to +//! first. For each positive integer n <= (last - first), +//! performs *(result - n) = boost::interprocess::move(*(last - n)). +//! +//! Requires: result shall not be in the range [first,last). +//! +//! Returns: result - (last - first). +//! +//! Complexity: Exactly last - first assignments. +template // O models BidirectionalIterator +O move_backward(I f, I l, O result) +{ + while (f != l) { + --l; --result; + *result = boost::interprocess::move(*l); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_move +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: +//! \code +//! for (; first != last; ++result, ++first) +//! new (static_cast(&*result)) +//! typename iterator_traits::value_type(boost::interprocess::move(*first)); +//! \endcode +//! +//! Returns: result +template + // F models ForwardIterator +F uninitialized_move(I f, I l, F r + /// @cond + ,typename enable_if::value_type> >::type* = 0 + /// @endcond + ) +{ + typedef typename std::iterator_traits::value_type input_value_type; + while (f != l) { + ::new(static_cast(&*r)) input_value_type(boost::interprocess::move(*f)); + ++f; ++r; + } + return r; +} + +/// @cond + +template + // F models ForwardIterator +F uninitialized_move(I f, I l, F r, + typename disable_if::value_type> >::type* = 0) +{ + return std::uninitialized_copy(f, l, r); +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_copy_or_move +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { + +template + // F models ForwardIterator +F uninitialized_move_move_iterator(I f, I l, F r, + typename enable_if< is_movable >::type* = 0) +{ + return boost::interprocess::uninitialized_move(f, l, r); +} + +template + // F models ForwardIterator +F uninitialized_move_move_iterator(I f, I l, F r, + typename disable_if< is_movable >::type* = 0) +{ + return std::uninitialized_copy(f.base(), l.base(), r); +} + +} //namespace move_detail { + +template + // F models ForwardIterator +F uninitialized_copy_or_move(I f, I l, F r, + typename enable_if< move_detail::is_move_iterator >::type* = 0) +{ + return boost::interprocess::move_detail::uninitialized_move_move_iterator(f, l, r); +} + +/// @endcond + +//! Effects: +//! \code +//! for (; first != last; ++result, ++first) +//! new (static_cast(&*result)) +//! typename iterator_traits::value_type(*first); +//! \endcode +//! +//! Returns: result +//! +//! Note: This function is provided because +//! std::uninitialized_copy from some STL implementations +//! is not compatible with move_iterator +template + // F models ForwardIterator +F uninitialized_copy_or_move(I f, I l, F r + /// @cond + ,typename disable_if< move_detail::is_move_iterator >::type* = 0 + /// @endcond + ) +{ + return std::uninitialized_copy(f, l, r); +} + +///has_trivial_destructor_after_move<> == true_type +///specialization for optimizations +template +struct has_trivial_destructor_after_move + : public boost::has_trivial_destructor +{}; + +} //namespace interprocess { +} //namespace boost { + +#endif //#ifndef BOOST_INTERPROCESS_MOVE_HPP diff --git a/include/boost/interprocess/detail/move_iterator.hpp b/include/boost/interprocess/detail/move_iterator.hpp deleted file mode 100644 index 4c9f282..0000000 --- a/include/boost/interprocess/detail/move_iterator.hpp +++ /dev/null @@ -1,138 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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_MOVE_ITERATOR_HPP_INCLUDED -#define BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED - -#include -#include - -namespace boost{ -namespace interprocess{ -namespace detail{ - -template -class move_iterator -{ - public: - typedef It iterator_type; - typedef typename std::iterator_traits::value_type value_type; - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - typedef typename move_type::type reference; - #else - typedef value_type && reference; - #endif - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::iterator_category iterator_category; - - move_iterator() - {} - - explicit move_iterator(It i) - : m_it(i) - {} - - template - move_iterator(const move_iterator& u) - : m_it(u.base()) - {} - - const iterator_type &base() const - { return m_it; } - - iterator_type &base() - { return m_it; } - - reference operator*() const - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - { return detail::move_impl(*m_it); } - #else - { return *m_it; } - #endif - - pointer operator->() const - { return m_it; } - - move_iterator& operator++() - { ++m_it; return *this; } - - move_iterator operator++(int) - { move_iterator tmp(*this); ++(*this); return tmp; } - - move_iterator& operator--() - { --m_it; return *this; } - - move_iterator operator--(int) - { move_iterator tmp(*this); --(*this); return tmp; } - - move_iterator operator+ (difference_type n) const - { return move_iterator(m_it + n); } - - move_iterator& operator+=(difference_type n) - { m_it += n; return *this; } - - move_iterator operator- (difference_type n) const - { return move_iterator(m_it - n); } - - move_iterator& operator-=(difference_type n) - { m_it -= n; return *this; } - - reference operator[](difference_type n) const - { return detail::move_impl(m_it[n]); } - - private: - It m_it; -}; - -template inline -bool operator==(const move_iterator& x, const move_iterator& y) -{ return x.base() == y.base(); } - -template inline -bool operator!=(const move_iterator& x, const move_iterator& y) -{ return x.base() != y.base(); } - -template inline -bool operator< (const move_iterator& x, const move_iterator& y) -{ return x.base() < y.base(); } - -template inline -bool operator<=(const move_iterator& x, const move_iterator& y) -{ return x.base() <= y.base(); } - -template inline -bool operator> (const move_iterator& x, const move_iterator& y) -{ return x.base() > y.base(); } - -template inline -bool operator>=(const move_iterator& x, const move_iterator& y) -{ return x.base() >= y.base(); } - -template inline -typename move_iterator::difference_type - operator-(const move_iterator& x, const move_iterator& y) -{ return x.base() - y.base(); } - -template inline -move_iterator - operator+(typename move_iterator::difference_type n - ,const move_iterator& x) -{ return move_iterator(x.base() + n); } - -template -move_iterator make_move_iterator(const It &it) -{ return move_iterator(it); } - -} //namespace detail{ -} //namespace interprocess{ -} //namespace boost{ - -#endif //#ifndef BOOST_INTERPROCESS_MOVE_ITERATOR_HPP_INCLUDED diff --git a/include/boost/interprocess/detail/mpl.hpp b/include/boost/interprocess/detail/mpl.hpp index dfdd38c..364a54d 100644 --- a/include/boost/interprocess/detail/mpl.hpp +++ b/include/boost/interprocess/detail/mpl.hpp @@ -59,6 +59,9 @@ struct enable_if_c {}; template struct enable_if : public enable_if_c {}; +template +struct disable_if : public enable_if_c {}; + template class is_convertible { @@ -105,7 +108,8 @@ template struct select1st // : public std::unary_function { - const typename Pair::first_type& operator()(const Pair& x) const + template + 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 diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index b4df4da..b16cf1d 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -72,11 +72,11 @@ struct CtorNArg : public placement_destroy private: template void construct(void *mem, detail::true_, const index_tuple&) - { new((void*)mem)T(*detail::forward_impl(get(args_))...); } + { new((void*)mem)T(*boost::interprocess::forward(get(args_))...); } template void construct(void *mem, detail::false_, const index_tuple&) - { new((void*)mem)T(detail::forward_impl(get(args_))...); } + { new((void*)mem)T(boost::interprocess::forward(get(args_))...); } template void do_increment(detail::true_, const index_tuple&) @@ -120,7 +120,7 @@ class named_proxy template T *operator()(Args &&...args) const { - CtorNArg ctor_obj(detail::forward_impl(args)...); + CtorNArg ctor_obj(boost::interprocess::forward(args)...); return mp_mngr->template generic_construct(mp_name, m_num, m_find, m_dothrow, ctor_obj); } @@ -211,7 +211,7 @@ struct Ctor0Arg : public placement_destroy //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 +//bind lvalues with non-const references, we have to be ugly #define BOOST_PP_LOCAL_MACRO(n) \ template \ struct BOOST_PP_CAT(BOOST_PP_CAT(Ctor, n), Arg) \ diff --git a/include/boost/interprocess/detail/os_file_functions.hpp b/include/boost/interprocess/detail/os_file_functions.hpp index 83f8c7e..78bbe96 100644 --- a/include/boost/interprocess/detail/os_file_functions.hpp +++ b/include/boost/interprocess/detail/os_file_functions.hpp @@ -13,9 +13,9 @@ #include #include -//#include +#include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -35,11 +35,11 @@ namespace boost { namespace interprocess { -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) typedef void * file_handle_t; typedef long long offset_t; -typedef struct{ +typedef struct mapping_handle_impl_t{ void * handle; bool is_shm; } mapping_handle_t; @@ -65,6 +65,14 @@ inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) return ret; } +inline mapping_handle_t mapping_handle_from_shm_handle(file_handle_t hnd) +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_shm = true; + return ret; +} + inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) { return hnd.handle; } @@ -99,10 +107,7 @@ inline file_handle_t open_existing_file } inline bool delete_file(const char *name) -{ return winapi::delete_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); } +{ return winapi::unlink_file(name); } inline bool truncate_file (file_handle_t hnd, std::size_t size) { @@ -191,16 +196,89 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) return (acquired = true); } - - inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +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 struct mapping_handle_impl_t +{ + file_handle_t handle; + bool is_xsi; +} mapping_handle_t; typedef enum { read_only = O_RDONLY , read_write = O_RDWR @@ -216,10 +294,15 @@ typedef enum { file_begin = SEEK_SET namespace detail{ inline mapping_handle_t mapping_handle_from_file_handle(file_handle_t hnd) -{ return hnd; } +{ + mapping_handle_t ret; + ret.handle = hnd; + ret.is_xsi = false; + return ret; +} inline file_handle_t file_handle_from_mapping_handle(mapping_handle_t hnd) -{ return hnd; } +{ return hnd.handle; } inline bool create_directory(const char *path) { return ::mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0; } @@ -263,12 +346,6 @@ inline file_handle_t open_existing_file 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); } @@ -365,7 +442,7 @@ inline bool try_acquire_file_lock_sharable(file_handle_t hnd, bool &acquired) inline bool release_file_lock_sharable(file_handle_t hnd) { return release_file_lock(hnd); } -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) } //namespace detail{ } //namespace interprocess { diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp index eee090e..4d2e3dd 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -14,7 +14,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -30,7 +30,7 @@ namespace boost { namespace interprocess { namespace detail{ -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) typedef unsigned long OS_process_id_t; typedef unsigned long OS_thread_id_t; @@ -40,6 +40,9 @@ typedef OS_thread_id_t OS_systemwide_thread_id_t; 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(); } @@ -59,6 +62,12 @@ inline OS_systemwide_thread_id_t get_current_systemwide_thread_id() return get_current_thread_id(); } +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to = from; +} + inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, const OS_systemwide_thread_id_t &id2) { return equal_thread_id(id1, id2); @@ -69,24 +78,56 @@ inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() return get_invalid_thread_id(); } -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else //#if (defined BOOST_INTERPROCESS_WINDOWS) typedef pthread_t OS_thread_id_t; typedef pid_t OS_process_id_t; struct OS_systemwide_thread_id_t { + OS_systemwide_thread_id_t() + : pid(), tid() + {} + OS_systemwide_thread_id_t(pid_t p, pthread_t t) : pid(p), tid(t) {} + + OS_systemwide_thread_id_t(const OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t(const volatile OS_systemwide_thread_id_t &x) + : pid(x.pid), tid(x.tid) + {} + + OS_systemwide_thread_id_t & operator=(const OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + OS_systemwide_thread_id_t & operator=(const volatile OS_systemwide_thread_id_t &x) + { pid = x.pid; tid = x.tid; return *this; } + + void operator=(const OS_systemwide_thread_id_t &x) volatile + { pid = x.pid; tid = x.tid; } + pid_t pid; pthread_t tid; }; +inline void systemwide_thread_id_copy + (const volatile OS_systemwide_thread_id_t &from, volatile OS_systemwide_thread_id_t &to) +{ + to.pid = from.pid; + to.tid = from.tid; +} + //process inline OS_process_id_t get_current_process_id() { return ::getpid(); } +inline OS_process_id_t get_invalid_process_id() +{ return pid_t(0); } + //thread inline OS_thread_id_t get_current_thread_id() { return ::pthread_self(); } @@ -116,10 +157,10 @@ inline bool equal_systemwide_thread_id(const OS_systemwide_thread_id_t &id1, con inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() { - return OS_systemwide_thread_id_t(pid_t(0), get_invalid_thread_id()); + return OS_systemwide_thread_id_t(get_invalid_process_id(), get_invalid_thread_id()); } -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) } //namespace detail{ } //namespace interprocess { diff --git a/include/boost/interprocess/detail/preprocessor.hpp b/include/boost/interprocess/detail/preprocessor.hpp index 45afb67..b7cb8fd 100644 --- a/include/boost/interprocess/detail/preprocessor.hpp +++ b/include/boost/interprocess/detail/preprocessor.hpp @@ -36,7 +36,7 @@ //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_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_PP_PARAM_LIST(z, n, data) \ BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ //! @@ -46,7 +46,7 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#ifdef BOOST_HAS_RVALUE_REFS #define BOOST_INTERPROCESS_PARAM(U, u) \ U && u \ //! @@ -56,7 +56,7 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#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)) \ //! @@ -70,7 +70,7 @@ BOOST_PP_CAT(++m_p, n) \ //! -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE +#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); \ //! @@ -80,25 +80,13 @@ //! #endif -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ - detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ - //! -#else - #define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ - BOOST_PP_CAT(p, n) \ - //! -#endif +#define BOOST_INTERPROCESS_PP_PARAM_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ +//! -#ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ - detail::forward_impl< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ - //! -#else - #define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ - BOOST_PP_CAT(m_p, n) \ - //! -#endif +#define BOOST_INTERPROCESS_PP_MEMBER_FORWARD(z, n, data) \ +boost::interprocess::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(m_p, n) ) \ +//! #define BOOST_INTERPROCESS_PP_MEMBER_IT_FORWARD(z, n, data) \ BOOST_PP_CAT(*m_p, n) \ diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index ffbe9fb..0301dfe 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -27,6 +29,8 @@ #include //char_traits #include //std::nothrow #include //std::pair +#include //assert +#include //unary_function #ifndef BOOST_NO_EXCEPTIONS #include #endif @@ -75,7 +79,7 @@ struct block_header block_header(std::size_t value_bytes ,std::size_t value_alignment - ,std::size_t allocation_type + ,std::size_t alloc_type ,std::size_t sizeof_char ,std::size_t num_char ) @@ -83,7 +87,7 @@ struct block_header , m_num_char(num_char) , m_value_alignment(value_alignment) , m_alloc_type_sizeof_char - ( ((unsigned char)allocation_type << 5u) | + ( ((unsigned char)alloc_type << 5u) | ((unsigned char)sizeof_char & 0x1F) ) {}; @@ -94,7 +98,7 @@ struct block_header std::size_t total_size() const { - if(allocation_type() != anonymous_type){ + if(alloc_type() != anonymous_type){ return name_offset() + (m_num_char+1)*sizeof_char(); } else{ @@ -114,7 +118,7 @@ struct block_header + total_size(); } - std::size_t allocation_type() const + std::size_t alloc_type() const { return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; } std::size_t sizeof_char() const @@ -252,6 +256,7 @@ struct char_if_void typedef instance_t anonymous_instance_t; typedef instance_t unique_instance_t; + template struct intrusive_value_type_impl : public Hook @@ -325,7 +330,7 @@ class char_ptr_holder template struct index_key { - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_char_ptr_t; typedef CharT char_type; @@ -471,6 +476,26 @@ struct segment_manager_iterator_transform } //namespace detail { +//These pointers are the ones the user will use to +//indicate previous allocation types +static const detail::anonymous_instance_t * anonymous_instance = 0; +static const detail::unique_instance_t * unique_instance = 0; + +namespace detail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)anonymous_instance; + (void)unique_instance; + } +}; + +} //detail_really_deep_namespace + }} //namespace boost { namespace interprocess #include diff --git a/include/boost/interprocess/detail/tmp_dir_helpers.hpp b/include/boost/interprocess/detail/tmp_dir_helpers.hpp index 34db635..2c0ccc5 100644 --- a/include/boost/interprocess/detail/tmp_dir_helpers.hpp +++ b/include/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -18,10 +18,87 @@ #include #include +#if (defined BOOST_INTERPROCESS_WINDOWS) +# include +#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(); @@ -61,6 +138,8 @@ inline void create_tmp_dir_and_get_filename(const char *filename, std::string &t tmp_name += filename; } +#endif + inline void add_leading_slash(const char *name, std::string &new_name) { if(name[0] != '/'){ diff --git a/include/boost/interprocess/detail/transform_iterator.hpp b/include/boost/interprocess/detail/transform_iterator.hpp new file mode 100644 index 0000000..eb081c2 --- /dev/null +++ b/include/boost/interprocess/detail/transform_iterator.hpp @@ -0,0 +1,180 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2008. +// (C) Copyright Gennaro Prota 2003 - 2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP +#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include + +namespace boost { +namespace interprocess { + +template +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 +struct operator_arrow_proxy +{ + 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 transform_iterator + : public UnaryFunction + , public std::iterator + < typename Iterator::iterator_category + , typename detail::remove_reference::type + , typename Iterator::difference_type + , operator_arrow_proxy + , 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 + operator->() const + { return operator_arrow_proxy(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 +transform_iterator +make_transform_iterator(Iterator it, UnaryFunc fun) +{ + return transform_iterator(it, fun); +} + +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP + diff --git a/include/boost/interprocess/detail/type_traits.hpp b/include/boost/interprocess/detail/type_traits.hpp index 44066b7..d4ee029 100644 --- a/include/boost/interprocess/detail/type_traits.hpp +++ b/include/boost/interprocess/detail/type_traits.hpp @@ -120,13 +120,13 @@ struct add_reference template<> struct add_reference { - typedef nat& type; + typedef nat &type; }; template<> struct add_reference { - typedef const nat& type; + typedef const nat &type; }; template diff --git a/include/boost/interprocess/detail/utilities.hpp b/include/boost/interprocess/detail/utilities.hpp index a96215e..166cf2e 100644 --- a/include/boost/interprocess/detail/utilities.hpp +++ b/include/boost/interprocess/detail/utilities.hpp @@ -26,11 +26,10 @@ #include #include #include -#include -#include -#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING -#include -#endif +#include +#include +#include +#include #include #include @@ -70,321 +69,6 @@ inline void do_swap(T& x, T& y) swap(x, y); } -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an object using a STL allocator. -template -struct scoped_ptr_dealloc_functor -{ - typedef typename Allocator::pointer pointer; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant 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 -struct scoped_deallocator -{ - typedef typename Allocator::pointer pointer; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant 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(const scoped_deallocator &); - scoped_deallocator& operator=(const scoped_deallocator &); - - public: - pointer m_ptr; - Allocator& m_alloc; - - scoped_deallocator(pointer p, Allocator& a) - : m_ptr(p), m_alloc(a) {} - - ~scoped_deallocator() - { if (m_ptr)priv_deallocate(alloc_version()); } - - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_deallocator(scoped_deallocator &&o) - : m_ptr(o.m_ptr), m_alloc(o.m_alloc) - { - #else - scoped_deallocator(moved_object 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; } -}; - -} //namespace detail { - -template -struct is_movable > -{ - static const bool value = true; -}; - -namespace detail { - -//!A deleter for scoped_ptr that deallocates the memory -//!allocated for an array of objects using a STL allocator. -template -struct scoped_array_deallocator -{ - typedef typename Allocator::pointer pointer; - 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 -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 -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 -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 allocator_destroyer -{ - typedef typename A::value_type value_type; - typedef detail::integral_constant::value> alloc_version; - typedef detail::integral_constant allocator_v1; - typedef detail::integral_constant 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 allocator_destroyer_and_chain_builder -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - - A & a_; - multiallocation_chain &c_; - - public: - allocator_destroyer_and_chain_builder(A &a, multiallocation_chain &c) - : a_(a), c_(c) - {} - - void operator()(const typename A::pointer &p) - { - value_type *vp = detail::get_pointer(p); - vp->~value_type(); - c_.push_back(vp); - } -}; - -template -class allocator_multialloc_chain_node_deallocator -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_node_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_node_deallocator() - { - multiallocation_iterator it(c_.get_it()); - if(it != multiallocation_iterator()) - a_.deallocate_individual(it); - } -}; - -template -class allocator_multialloc_chain_array_deallocator -{ - typedef typename A::value_type value_type; - typedef typename A::multiallocation_iterator multiallocation_iterator; - typedef typename A::multiallocation_chain multiallocation_chain; - typedef allocator_destroyer_and_chain_builder chain_builder; - - A & a_; - multiallocation_chain c_; - - public: - allocator_multialloc_chain_array_deallocator(A &a) - : a_(a), c_() - {} - - chain_builder get_chain_builder() - { return chain_builder(a_, c_); } - - ~allocator_multialloc_chain_array_deallocator() - { - multiallocation_iterator it(c_.get_it()); - if(it != multiallocation_iterator()) - a_.deallocate_many(it); - } -}; - -//!A class used for exception-safe multi-allocation + construction. -template -struct multiallocation_destroy_dealloc -{ - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; - typedef typename Allocator::value_type value_type; - - multiallocation_iterator m_itbeg; - Allocator& m_alloc; - - multiallocation_destroy_dealloc(multiallocation_iterator itbeg, Allocator& a) - : m_itbeg(itbeg), m_alloc(a) {} - - ~multiallocation_destroy_dealloc() - { - multiallocation_iterator endit; - while(m_itbeg != endit){ - detail::get_pointer(&*m_itbeg)->~value_type(); - m_alloc.deallocate(&*m_itbeg, 1); - ++m_itbeg; - } - } - - void next() - { ++m_itbeg; } - - void release() - { m_itbeg = multiallocation_iterator(); } -}; - //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) { @@ -415,18 +99,6 @@ struct ct_rounded_size enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; }; -template -struct ct_min -{ - enum { value = (Value1 < Value2)? Value1 : Value2 }; -}; - -template -struct ct_max -{ - enum { value = (Value1 > Value2)? Value1 : Value2 }; -}; - // Gennaro Prota wrote this. Thanks! template struct ct_max_pow2_less @@ -443,38 +115,6 @@ 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 -template -struct pointer_to_other; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template class Sp> -struct pointer_to_other< Sp, U > -{ - typedef Sp type; -}; - -template -struct pointer_to_other< T*, U > -{ - typedef U* type; -}; - } //namespace detail { //!Trait class to detect if an index is a node @@ -486,7 +126,6 @@ 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 @@ -497,334 +136,6 @@ struct is_intrusive_index enum { value = false }; }; -template -SizeType - get_next_capacity(const SizeType max_size - ,const SizeType capacity - ,const SizeType n) -{ -// if (n > max_size - capacity) -// throw std::length_error("get_next_capacity"); - - const SizeType m3 = max_size/3; - - if (capacity < m3) - return capacity + max_value(3*(capacity+1)/5, n); - - if (capacity < m3*2) - return capacity + max_value((capacity+1)/2, n); - - return max_size; -} - -namespace detail { - -template -struct pair -{ - typedef T1 first_type; - typedef T2 second_type; - - T1 first; - T2 second; - - //std::pair compatibility - template - pair(const std::pair& p) - : first(p.first), second(p.second) - {} - - //To resolve ambiguity with the variadic constructor of 1 argument - //and the previous constructor - pair(std::pair& x) - : first(x.first), second(x.second) - {} - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - template - pair(std::pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - pair() - : first(), second() - {} - - pair(const pair& x) - : first(x.first), second(x.second) - {} - - //To resolve ambiguity with the variadic constructor of 1 argument - //and the copy constructor - pair(pair& x) - : first(x.first), second(x.second) - {} - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - pair(pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair(detail::moved_object > p) - : first(detail::move_impl(p.get().first)), second(detail::move_impl(p.get().second)) - {} - #else - template - pair(pair && p) - : first(detail::move_impl(p.first)), second(detail::move_impl(p.second)) - {} - #endif - - #ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING - - template - pair(U &&u, Args &&... args) - : first(detail::forward_impl(u)) - , second(detail::forward_impl(args)...) - {} - - #else - - template - pair(BOOST_INTERPROCESS_PARAM(U, u)) - : first(detail::forward_impl(u)) - {} - - #define BOOST_PP_LOCAL_MACRO(n) \ - template \ - pair(BOOST_INTERPROCESS_PARAM(U, u) \ - ,BOOST_PP_ENUM(n, BOOST_INTERPROCESS_PP_PARAM_LIST, _)) \ - : first(detail::forward_impl(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_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - pair& operator=(pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - pair& operator=(std::pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - template - pair& operator=(detail::moved_object > p) - { - first = detail::move_impl(p.get().first); - second = detail::move_impl(p.get().second); - return *this; - } - #else - template - pair& operator=(std::pair &&p) - { - first = detail::move_impl(p.first); - second = detail::move_impl(p.second); - return *this; - } - #endif - - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - void swap(detail::moved_object 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 -inline bool operator==(const pair& x, const pair& y) -{ return static_cast(x.first == y.first && x.second == y.second); } - -template -inline bool operator< (const pair& x, const pair& y) -{ return static_cast(x.first < y.first || - (!(y.first < x.first) && x.second < y.second)); } - -template -inline bool operator!=(const pair& x, const pair& y) -{ return static_cast(!(x == y)); } - -template -inline bool operator> (const pair& x, const pair& y) -{ return y < x; } - -template -inline bool operator>=(const pair& x, const pair& y) -{ return static_cast(!(x < y)); } - -template -inline bool operator<=(const pair& x, const pair& y) -{ return static_cast(!(y < x)); } - -template -inline pair make_pair(T1 x, T2 y) -{ return pair(x, y); } - -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -template -inline void swap(detail::moved_object > &x, pair y) -{ - swap(x.get().first, y.first); - swap(x.get().second, y.second); -} - -template -inline void swap(pair& x, detail::moved_object > y) -{ - swap(x.first, y.get().first); - swap(x.second, y.get().second); -} - -template -inline void swap(pair& x, pair& y) -{ - swap(x.first, y.first); - swap(x.second, y.second); -} - -#else -template -inline void swap(pair&&x, pair&&y) -{ - swap(x.first, y.first); - swap(x.second, y.second); -} -#endif - -template -struct cast_functor -{ - typedef typename detail::add_reference::type result_type; - result_type operator()(char &ptr) const - { return *static_cast(static_cast(&ptr)); } -}; - -template -class multiallocation_chain_adaptor -{ - private: - MultiallocChain chain_; - - multiallocation_chain_adaptor - (const multiallocation_chain_adaptor &); - multiallocation_chain_adaptor &operator= - (const multiallocation_chain_adaptor &); - - public: - typedef transform_iterator - < typename MultiallocChain:: - multiallocation_iterator - , detail::cast_functor > multiallocation_iterator; - - multiallocation_chain_adaptor() - : chain_() - {} - - void push_back(T *mem) - { chain_.push_back(mem); } - - void push_front(T *mem) - { chain_.push_front(mem); } - - void swap(multiallocation_chain_adaptor &other_chain) - { chain_.swap(other_chain.chain_); } - - void splice_back(multiallocation_chain_adaptor &other_chain) - { chain_.splice_back(other_chain.chain_); } - - T *pop_front() - { return static_cast(chain_.pop_front()); } - - bool empty() const - { return chain_.empty(); } - - multiallocation_iterator get_it() const - { return multiallocation_iterator(chain_.get_it()); } - - std::size_t size() const - { return chain_.size(); } -}; - -template -struct value_init -{ - value_init() - : m_t() - {} - - T m_t; -}; - -} //namespace detail { - -//!The pair is movable if any of its members is movable -template -struct is_movable > -{ - enum { value = is_movable::value || is_movable::value }; -}; - -//!The pair is movable if any of its members is movable -template -struct is_movable > -{ - enum { value = is_movable::value || is_movable::value }; -}; - -///has_trivial_destructor_after_move<> == true_type -///specialization for optimizations -template -struct has_trivial_destructor_after_move - : public boost::has_trivial_destructor -{}; - template T* addressof(T& v) { @@ -850,36 +161,6 @@ class value_eraser bool m_erase; }; -template -struct sizeof_value -{ - static const std::size_t value = sizeof(T); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - -template <> -struct sizeof_value -{ - static const std::size_t value = sizeof(void*); -}; - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index fa26ee9..cfe0afc 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -14,13 +14,15 @@ #include #include #include +#include +#include #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once # pragma comment( lib, "advapi32.lib" ) #endif -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include # include #else @@ -37,6 +39,7 @@ namespace winapi { 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; @@ -62,6 +65,15 @@ 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; @@ -74,6 +86,15 @@ 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; @@ -109,8 +130,6 @@ static const unsigned long open_existing = 3; static const unsigned long open_always = 4; static const unsigned long truncate_existing = 5; -static const unsigned long file_attribute_temporary = 0x00000100; - static const unsigned long file_begin = 0; static const unsigned long file_current = 1; static const unsigned long file_end = 2; @@ -120,6 +139,13 @@ 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 { @@ -151,6 +177,20 @@ struct interprocess_filetime 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; @@ -208,6 +248,126 @@ typedef struct _interprocess_security_descriptor 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(); @@ -220,6 +380,9 @@ extern "C" __declspec(dllimport) int __stdcall DuplicateHandle , 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 *); @@ -245,6 +408,7 @@ extern "C" __declspec(dllimport) unsigned long __stdcall FormatMessageA 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); @@ -257,6 +421,25 @@ extern "C" __declspec(dllimport) int __stdcall UnlockFileEx(void *hnd, unsigned 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 { @@ -298,6 +481,15 @@ static inline unsigned long get_current_process_id() 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) { @@ -384,6 +576,9 @@ static inline bool get_file_size(void *handle, __int64 &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); } @@ -417,6 +612,274 @@ static inline long interlocked_exchange_add(long volatile* addend, long value) static inline long interlocked_exchange(long volatile* addend, long value) { return BOOST_INTERLOCKED_EXCHANGE(const_cast(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(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(BootAndSystemstampLength); ++i){ + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0xF0)>>4]; + bootsystemstamp[char_counter++] = Characters[(info.Reserved1[i]&0x0F)]; + } + s = BootAndSystemstampLength*2; + return true; +} + +static inline bool unlink_file(const char *filename) +{ + try{ + NtSetInformationFile_t pNtSetInformationFile = + (NtSetInformationFile_t)get_proc_address(get_module_handle("ntdll.dll"), "NtSetInformationFile"); + if(!pNtSetInformationFile){ + return false; + } + + NtQueryObject_t pNtQueryObject = + (NtQueryObject_t)get_proc_address(get_module_handle("ntdll.dll"), "NtQueryObject"); + + //First step: Obtain a handle to the file using Win32 rules. This resolves relative paths + void *fh = create_file(filename, generic_read | delete_access, open_existing, + file_flag_backup_semantics | file_flag_delete_on_close); + if(fh == invalid_handle_value){ + return false; + } + + class handle_closer + { + void *handle_; + public: + handle_closer(void *handle) : handle_(handle){} + ~handle_closer(){ close_handle(handle_); } + } handle_closer(fh); + + const std::size_t CharArraySize = 32767; //Max name length + + union mem_t + { + object_name_information_t name; + struct ren_t + { + file_rename_information_t info; + wchar_t buf[CharArraySize]; + } ren; + }; + + class auto_ptr + { + public: + explicit auto_ptr(mem_t *ptr) : ptr_(ptr){} + ~auto_ptr(){ delete ptr_; } + mem_t *get() const{ return (ptr_); } + mem_t *operator->() const{ return this->get(); } + private: + mem_t *ptr_; + } pmem(new mem_t); + + file_rename_information_t *pfri = (file_rename_information_t*)&pmem->ren.info; + const std::size_t RenMaxNumChars = + ((char*)pmem.get() - (char*)&pmem->ren.info.FileName[0])/sizeof(wchar_t); + + //Obtain file name + unsigned long size; + if(pNtQueryObject(fh, object_name_information, pmem.get(), sizeof(mem_t), &size)){ + return false; + } + + //Copy filename to the rename member + std::memmove(pmem->ren.info.FileName, pmem->name.Name.Buffer, pmem->name.Name.Length); + std::size_t filename_string_length = pmem->name.Name.Length/sizeof(wchar_t); + + //Second step: obtain the complete native-nt filename + //if(!get_file_name_from_handle_function(fh, pfri->FileName, RenMaxNumChars, filename_string_length)){ + //return 0; + //} + + //Add trailing mark + if((RenMaxNumChars-filename_string_length) < (SystemTimeOfDayInfoLength*2)){ + return false; + } + + //Search '\\' character to replace it + for(std::size_t i = filename_string_length; i != 0; --filename_string_length){ + if(pmem->ren.info.FileName[--i] == L'\\') + break; + } + + //Add random number + std::size_t s = RenMaxNumChars - filename_string_length; + if(!get_boot_and_system_time_wstr(&pfri->FileName[filename_string_length], s)){ + return false; + } + filename_string_length += s; + + //Fill rename information (FileNameLength is in bytes) + pfri->FileNameLength = static_cast(sizeof(wchar_t)*(filename_string_length)); + pfri->Replace = 1; + pfri->RootDir = 0; + + //Final step: change the name of the in-use file: + io_status_block_t io; + if(0 != pNtSetInformationFile(fh, &io, pfri, sizeof(mem_t::ren_t), file_rename_information)){ + return false; + } + return true; + } + catch(...){ + return false; + } +} + } //namespace winapi } //namespace interprocess } //namespace boost diff --git a/include/boost/interprocess/detail/workaround.hpp b/include/boost/interprocess/detail/workaround.hpp index e21164d..80168c7 100644 --- a/include/boost/interprocess/detail/workaround.hpp +++ b/include/boost/interprocess/detail/workaround.hpp @@ -13,7 +13,19 @@ #include -#if !(defined BOOST_WINDOWS) || (defined BOOST_DISABLE_WIN32) +#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 @@ -30,10 +42,12 @@ # endif #if ((_POSIX_SEMAPHORES - 0) > 0) - # define BOOST_INTERPROCESS_POSIX_SEMAPHORES + # 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)) ||\ @@ -51,10 +65,15 @@ #if ((_POSIX_SHARED_MEMORY_OBJECTS - 0) > 0) # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS #else + //VMS and MACOS don't define it but the have shm_open/close interface # if defined(__vms) # if __CRTL_VER >= 70200000 # define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS # endif + # define BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS + //Mac OS has some non-conformant features like names limited to SHM_NAME_MAX + //# elif defined (__APPLE__) + //# define BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS # endif #endif @@ -76,7 +95,7 @@ #endif #endif - #ifdef BOOST_INTERPROCESS_POSIX_SEMAPHORES + #ifdef BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES #if defined(BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_RESOURCES) #define BOOST_INTERPROCESS_FILESYSTEM_BASED_POSIX_SEMAPHORES #endif @@ -88,34 +107,20 @@ #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_INTERPROCESS_RVALUE_REFERENCE -# define BOOST_INTERPROCESS_VARIADIC_TEMPLATES -# if defined(__GLIBCPP__) || defined(__GLIBCXX__) -# define BOOST_INTERPROCESS_RVALUE_PAIR -# endif -# endif -#endif - -#if defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && defined(BOOST_INTERPROCESS_VARIADIC_TEMPLATES) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)\ + && !defined(BOOST_INTERPROCESS_DISABLE_VARIADIC_TMPL) #define BOOST_INTERPROCESS_PERFECT_FORWARDING #endif //Now declare some Boost.Interprocess features depending on the implementation -#if defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) +#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_SEMAPHORES) && !defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES_NO_UNLINK) +#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 diff --git a/include/boost/interprocess/errors.hpp b/include/boost/interprocess/errors.hpp index 8c17c2c..cdd4208 100644 --- a/include/boost/interprocess/errors.hpp +++ b/include/boost/interprocess/errors.hpp @@ -33,7 +33,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -42,7 +42,7 @@ # else //ifdef BOOST_HAS_UNISTD_H # error Unknown platform # endif //ifdef BOOST_HAS_UNISTD_H -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) //!\file //!Describes the error numbering of interprocess classes @@ -52,7 +52,7 @@ namespace interprocess { /// @cond static inline int system_error_code() // artifact of POSIX and WINDOWS error reporting { - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) return winapi::get_last_error(); #else return errno; // GCC 3.1 won't accept ::errno @@ -60,7 +60,7 @@ static inline int system_error_code() // artifact of POSIX and WINDOWS error rep } -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) inline void fill_system_message(int sys_err_code, std::string &str) { void *lpMsgBuf; @@ -110,7 +110,9 @@ enum error_code_t sem_error, mode_error, size_error, - corrupted_error + corrupted_error, + not_such_file_or_directory, + invalid_argument }; typedef int native_error_t; @@ -124,7 +126,7 @@ struct ec_xlate static const ec_xlate ec_table[] = { - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #if (defined BOOST_INTERPROCESS_WINDOWS) { /*ERROR_ACCESS_DENIED*/5L, security_error }, { /*ERROR_INVALID_ACCESS*/12L, security_error }, { /*ERROR_SHARING_VIOLATION*/32L, security_error }, @@ -156,7 +158,7 @@ static const ec_xlate ec_table[] = { /*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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #else //#if (defined BOOST_INTERPROCESS_WINDOWS) { EACCES, security_error }, { EROFS, read_only_error }, { EIO, io_error }, @@ -171,8 +173,10 @@ static const ec_xlate ec_table[] = { EISDIR, is_directory_error }, { ENOSPC, out_of_space_error }, { ENOMEM, out_of_memory_error }, - { EMFILE, out_of_resource_error } - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + { EMFILE, out_of_resource_error }, + { ENOENT, not_such_file_or_directory }, + { EINVAL, invalid_argument } + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) }; static inline error_code_t lookup_error(native_error_t err) diff --git a/include/boost/interprocess/file_mapping.hpp b/include/boost/interprocess/file_mapping.hpp index 37391e2..6dbefb4 100644 --- a/include/boost/interprocess/file_mapping.hpp +++ b/include/boost/interprocess/file_mapping.hpp @@ -21,8 +21,6 @@ #include #include #include //std::string -#include //std::remove -#include //!\file //!Describes file_mapping and mapped region classes @@ -30,31 +28,19 @@ namespace boost { namespace interprocess { -///@cond - -class file_mapping; - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - -///@endcond - //!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(const file_mapping &); - file_mapping &operator=(const file_mapping &); + file_mapping(file_mapping &); + file_mapping &operator=(file_mapping &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_mapping) + //!Constructs an empty file mapping. //!Does not throw file_mapping(); @@ -68,41 +54,23 @@ class file_mapping //!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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_mapping(detail::moved_object moved) - : m_handle(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - file_mapping(file_mapping &&moved) + file_mapping(BOOST_INTERPROCESS_RV_REF(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_mapping &operator=(detail::moved_object m_other) - { - file_mapping &moved = m_other.get(); - #else - file_mapping &operator=(file_mapping &&moved) - { - #endif - file_mapping tmp(detail::move_impl(moved)); + file_mapping &operator=(BOOST_INTERPROCESS_RV_REF(file_mapping) moved) + { + file_mapping tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } //!Swaps to file_mappings. //!Does not throw. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(file_mapping &other); - #else - void swap(file_mapping &&other); - #endif //!Returns access mode //!used in the constructor @@ -120,6 +88,12 @@ class file_mapping //!used in the constructor. const char *get_name() const; + //!Removes the file named "filename" even if it's been memory mapped. + //!Returns true on success. + //!The function might fail in some operating systems if the file is + //!being used other processes and no deletion permission was shared. + static bool remove(const char *filename); + /// @cond private: //!Closes a previously opened file mapping. Never throws. @@ -140,11 +114,7 @@ inline file_mapping::~file_mapping() inline const char *file_mapping::get_name() const { return m_filename.c_str(); } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !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); @@ -179,6 +149,9 @@ inline file_mapping::file_mapping m_mode = mode; } +inline bool file_mapping::remove(const char *filename) +{ return detail::delete_file(filename); } + ///@cond inline void file_mapping::priv_close() @@ -192,7 +165,7 @@ inline void file_mapping::priv_close() ///@endcond //!A class that stores the name of a file -//!and call std::remove(name) in its destructor +//!and tries to remove it in its destructor //!Useful to remove temporary files in the presence //!of exceptions class remove_file_on_destroy @@ -204,7 +177,7 @@ class remove_file_on_destroy {} ~remove_file_on_destroy() - { std::remove(m_name); } + { detail::delete_file(m_name); } }; } //namespace interprocess { diff --git a/include/boost/interprocess/indexes/iunordered_set_index.hpp b/include/boost/interprocess/indexes/iunordered_set_index.hpp index 1b059a3..522ab4a 100644 --- a/include/boost/interprocess/indexes/iunordered_set_index.hpp +++ b/include/boost/interprocess/indexes/iunordered_set_index.hpp @@ -176,7 +176,7 @@ class iunordered_set_index 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){ + (boost::interprocess::try_shrink_in_place | boost::interprocess::nothrow_allocation, old_size, new_size, received_size, buckets).first){ return old_size; } @@ -188,7 +188,7 @@ class iunordered_set_index } bucket_ptr shunk_p = alloc.allocation_command - (shrink_in_place | nothrow_allocation, received_size, received_size, received_size, buckets).first; + (boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_size, received_size, received_size, buckets).first; BOOST_ASSERT(buckets == shunk_p); bucket_ptr buckets_init = buckets + received_size; @@ -205,7 +205,7 @@ class iunordered_set_index std::size_t received_size; std::pair ret = alloc.allocation_command - (expand_fwd | allocate_new, new_num, new_num, received_size, old_buckets); + (boost::interprocess::expand_fwd | boost::interprocess::allocate_new, new_num, new_num, received_size, old_buckets); if(ret.first == old_buckets){ bucket_ptr buckets_init = old_buckets + old_num; for(std::size_t i = 0; i < (new_num - old_num); ++i){ diff --git a/include/boost/interprocess/interprocess_fwd.hpp b/include/boost/interprocess/interprocess_fwd.hpp index aca3960..575a2a9 100644 --- a/include/boost/interprocess/interprocess_fwd.hpp +++ b/include/boost/interprocess/interprocess_fwd.hpp @@ -11,12 +11,12 @@ #ifndef BOOST_INTERPROCESS_FWD_HPP #define BOOST_INTERPROCESS_FWD_HPP -#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#if defined (_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif -//#include -//#include +#include +#include #include @@ -61,9 +61,9 @@ namespace boost { namespace interprocess { class shared_memory_object; -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if defined (BOOST_INTERPROCESS_WINDOWS) class windows_shared_memory; -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) ////////////////////////////////////////////////////////////////////////////// // mapped file/mapped region/mapped_file @@ -113,6 +113,9 @@ class scoped_lock; template class sharable_lock; +template +class upgradable_lock; + ////////////////////////////////////////////////////////////////////////////// // STL compatible allocators ////////////////////////////////////////////////////////////////////////////// @@ -230,7 +233,7 @@ wmanaged_shared_memory; // Windows shared memory managed memory classes ////////////////////////////////////////////////////////////////////////////// -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if defined (BOOST_INTERPROCESS_WINDOWS) template wmanaged_windows_shared_memory; -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#else + +template class IndexType> +class basic_managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +managed_xsi_shared_memory; + +typedef basic_managed_xsi_shared_memory + + ,iset_index> +wmanaged_xsi_shared_memory; + +#endif //#if defined (BOOST_INTERPROCESS_WINDOWS) ////////////////////////////////////////////////////////////////////////////// // Fixed address shared memory @@ -382,98 +404,12 @@ class weak_ptr; class message_queue; -////////////////////////////////////////////////////////////////////////////// -// Containers -////////////////////////////////////////////////////////////////////////////// - -//vector class -template > -class vector; - -//vector class -template > -class deque; - -//list class -template > -class list; - -//slist class -template > -class slist; - -//set class -template - ,class Alloc = std::allocator > -class set; - -//multiset class -template - ,class Alloc = std::allocator > -class multiset; - -//map class -template - ,class Alloc = std::allocator > > -class map; - -//multimap class -template - ,class Alloc = std::allocator > > -class multimap; - -//flat_set class -template - ,class Alloc = std::allocator > -class flat_set; - -//flat_multiset class -template - ,class Alloc = std::allocator > -class flat_multiset; - -//flat_map class -template - ,class Alloc = std::allocator > > -class flat_map; - -//flat_multimap class -template - ,class Alloc = std::allocator > > -class flat_multimap; - -//basic_string class -template - ,class Alloc = std::allocator > -class basic_string; - -//string class -typedef basic_string - - ,std::allocator > -string; - }} //namespace boost { namespace interprocess { -//#include +////////////////////////////////////////////////////////////////////////////// +// CONTAINERS +////////////////////////////////////////////////////////////////////////////// + +#include #endif //#ifndef BOOST_INTERPROCESS_FWD_HPP - diff --git a/include/boost/interprocess/managed_external_buffer.hpp b/include/boost/interprocess/managed_external_buffer.hpp index 88550f6..30b822a 100644 --- a/include/boost/interprocess/managed_external_buffer.hpp +++ b/include/boost/interprocess/managed_external_buffer.hpp @@ -43,9 +43,12 @@ class basic_managed_external_buffer /// @cond typedef detail::basic_managed_memory_impl base_t; + basic_managed_external_buffer(basic_managed_external_buffer&); + basic_managed_external_buffer & operator=(basic_managed_external_buffer&); /// @endcond - + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_external_buffer) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -75,25 +78,15 @@ class basic_managed_external_buffer } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_external_buffer(detail::moved_object mother) + basic_managed_external_buffer(BOOST_INTERPROCESS_RV_REF(basic_managed_external_buffer) moved) { - basic_managed_external_buffer &moved = mother.get(); - #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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_external_buffer &operator=(detail::moved_object moved) - #else - basic_managed_external_buffer &operator=(basic_managed_external_buffer &&moved) - #endif + basic_managed_external_buffer &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_external_buffer) moved) { - basic_managed_external_buffer tmp(detail::move_impl(moved)); + basic_managed_external_buffer tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -103,36 +96,10 @@ class basic_managed_external_buffer //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } void swap(basic_managed_external_buffer &other) - #else - void swap(basic_managed_external_buffer &&other) - #endif { base_t::swap(other); } }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_heap_memory.hpp b/include/boost/interprocess/managed_heap_memory.hpp index 87a5452..5bc4509 100644 --- a/include/boost/interprocess/managed_heap_memory.hpp +++ b/include/boost/interprocess/managed_heap_memory.hpp @@ -46,9 +46,12 @@ class basic_managed_heap_memory typedef detail::basic_managed_memory_impl base_t; + basic_managed_heap_memory(basic_managed_heap_memory&); + basic_managed_heap_memory & operator=(basic_managed_heap_memory&); /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_heap_memory) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -71,26 +74,13 @@ class basic_managed_heap_memory } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_heap_memory - (detail::moved_object mother) - { - basic_managed_heap_memory &moved = mother.get(); - #else - basic_managed_heap_memory(basic_managed_heap_memory &&moved) - { - #endif - this->swap(moved); - } + basic_managed_heap_memory(BOOST_INTERPROCESS_RV_REF(basic_managed_heap_memory) moved) + { this->swap(moved); } //!Moves the ownership of "moved"'s managed memory to *this. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_heap_memory &operator=(detail::moved_object moved) - #else - basic_managed_heap_memory &operator=(basic_managed_heap_memory &&moved) - #endif + basic_managed_heap_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_heap_memory) moved) { - basic_managed_heap_memory tmp(detail::move_impl(moved)); + basic_managed_heap_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -125,13 +115,7 @@ class basic_managed_heap_memory //!Swaps the ownership of the managed heap memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.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); @@ -150,27 +134,8 @@ class basic_managed_heap_memory /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond } //namespace interprocess { - } //namespace boost { #include diff --git a/include/boost/interprocess/managed_mapped_file.hpp b/include/boost/interprocess/managed_mapped_file.hpp index dee8488..065c424 100644 --- a/include/boost/interprocess/managed_mapped_file.hpp +++ b/include/boost/interprocess/managed_mapped_file.hpp @@ -47,6 +47,8 @@ class basic_managed_mapped_file ::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: @@ -61,6 +63,7 @@ class basic_managed_mapped_file /// @endcond public: //functions + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_mapped_file) //!Creates mapped file and creates and places the segment manager. //!This can throw. @@ -118,27 +121,16 @@ class basic_managed_mapped_file //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_mapped_file - (detail::moved_object mother) + basic_managed_mapped_file(BOOST_INTERPROCESS_RV_REF(basic_managed_mapped_file) moved) { - basic_managed_mapped_file &moved = mother.get(); - #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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_mapped_file &operator=(detail::moved_object moved) - #else - basic_managed_mapped_file &operator=(basic_managed_mapped_file &&moved) - #endif + basic_managed_mapped_file &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_mapped_file) moved) { - basic_managed_mapped_file tmp(detail::move_impl(moved)); + basic_managed_mapped_file tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -154,14 +146,7 @@ class basic_managed_mapped_file //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.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); @@ -214,27 +199,7 @@ class basic_managed_mapped_file /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - } //namespace interprocess { - } //namespace boost { #include diff --git a/include/boost/interprocess/managed_shared_memory.hpp b/include/boost/interprocess/managed_shared_memory.hpp index a726e06..990585e 100644 --- a/include/boost/interprocess/managed_shared_memory.hpp +++ b/include/boost/interprocess/managed_shared_memory.hpp @@ -60,9 +60,12 @@ class basic_managed_shared_memory 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_INTERPROCESS_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 @@ -134,14 +137,8 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_shared_memory(detail::moved_object mother) + basic_managed_shared_memory(BOOST_INTERPROCESS_RV_REF(basic_managed_shared_memory) moved) { - basic_managed_shared_memory &moved = mother.get(); - #else - basic_managed_shared_memory(basic_managed_shared_memory &&moved) - { - #endif basic_managed_shared_memory tmp; this->swap(moved); tmp.swap(moved); @@ -149,26 +146,16 @@ class basic_managed_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_shared_memory &operator=(detail::moved_object moved) - #else - basic_managed_shared_memory &operator=(basic_managed_shared_memory &&moved) - #endif + basic_managed_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_shared_memory) moved) { - basic_managed_shared_memory tmp(detail::move_impl(moved)); + basic_managed_shared_memory tmp(boost::interprocess::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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.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); @@ -179,20 +166,20 @@ class basic_managed_shared_memory //! //!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) + static bool grow(const char *shmname, std::size_t extra_bytes) { return base_t::template grow - (filename, extra_bytes); + (shmname, 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) + static bool shrink_to_fit(const char *shmname) { return base_t::template shrink_to_fit - (filename); + (shmname); } /// @cond @@ -214,25 +201,6 @@ class basic_managed_shared_memory /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/managed_windows_shared_memory.hpp b/include/boost/interprocess/managed_windows_shared_memory.hpp index a0e9a92..144352b 100644 --- a/include/boost/interprocess/managed_windows_shared_memory.hpp +++ b/include/boost/interprocess/managed_windows_shared_memory.hpp @@ -60,9 +60,13 @@ class basic_managed_windows_shared_memory 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_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_managed_windows_shared_memory) //!Default constructor. Does nothing. //!Useful in combination with move semantics @@ -121,24 +125,15 @@ class basic_managed_windows_shared_memory //!Moves the ownership of "moved"'s managed memory to *this. //!Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) basic_managed_windows_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - basic_managed_windows_shared_memory(basic_managed_windows_shared_memory &&moved) + (BOOST_INTERPROCESS_RV_REF(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - basic_managed_windows_shared_memory &operator=(detail::moved_object moved) - #else - basic_managed_windows_shared_memory &operator=(basic_managed_windows_shared_memory &&moved) - #endif + basic_managed_windows_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(basic_managed_windows_shared_memory) moved) { - basic_managed_windows_shared_memory tmp(detail::move_impl(moved)); + basic_managed_windows_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -153,19 +148,14 @@ class basic_managed_windows_shared_memory //!Swaps the ownership of the managed mapped memories managed by *this and other. //!Never throws. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.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. @@ -185,25 +175,6 @@ class basic_managed_windows_shared_memory /// @endcond }; -///@cond - -//!Trait class to detect if a type is -//!movable -template - < - class CharType, - class AllocationAlgorithm, - template class IndexType - > -struct is_movable -> -{ - static const bool value = true; -}; - -///@endcond - } //namespace interprocess { } //namespace boost { diff --git a/include/boost/interprocess/mapped_region.hpp b/include/boost/interprocess/mapped_region.hpp index 115b25d..f571272 100644 --- a/include/boost/interprocess/mapped_region.hpp +++ b/include/boost/interprocess/mapped_region.hpp @@ -22,7 +22,7 @@ #include #include -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#if (defined BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H @@ -31,11 +31,13 @@ # include # include # include +# include +# include # else # error Unknown platform # endif -#endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //#if (defined BOOST_INTERPROCESS_WINDOWS) //!\file //!Describes memory_mappable and mapped region classes @@ -55,11 +57,12 @@ class mapped_region { /// @cond //Non-copyable - mapped_region(const mapped_region &); - mapped_region &operator=(const mapped_region &); + mapped_region(mapped_region &); + mapped_region &operator=(mapped_region &); /// @endcond public: + BOOST_INTERPROCESS_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 @@ -78,11 +81,7 @@ class 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - mapped_region(detail::moved_object other); - #else - mapped_region(mapped_region &&other); - #endif + mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other); //!Destroys the mapped region. //!Does not throw @@ -90,11 +89,7 @@ class 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - mapped_region &operator=(detail::moved_object other); - #else - mapped_region &operator=(mapped_region &&other); - #endif + mapped_region &operator=(BOOST_INTERPROCESS_RV_REF(mapped_region) other); //!Returns the size of the mapping. Note for windows users: If //!windows_shared_memory is mapped using 0 as the size, it returns 0 @@ -119,13 +114,7 @@ class mapped_region //!Swaps the mapped_region with another //!mapped region - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.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. @@ -148,8 +137,10 @@ class mapped_region offset_t m_offset; offset_t m_extra_offset; mode_t m_mode; - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) - file_handle_t m_file_mapping_hnd; + #if (defined BOOST_INTERPROCESS_WINDOWS) + file_handle_t m_file_mapping_hnd; + #else + bool m_is_xsi; #endif friend class detail::interprocess_tester; @@ -163,14 +154,9 @@ class mapped_region inline void swap(mapped_region &x, mapped_region &y) { x.swap(y); } -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region &mapped_region::operator=(detail::moved_object moved) +inline mapped_region &mapped_region::operator=(BOOST_INTERPROCESS_RV_REF(mapped_region) moved) { -#else -inline mapped_region &mapped_region::operator=(mapped_region &&moved) -{ -#endif - mapped_region tmp(detail::move_impl(moved)); + mapped_region tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -190,28 +176,19 @@ inline mode_t mapped_region::get_mode() const inline void* mapped_region::get_address() const { return m_base; } -#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#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_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region::mapped_region(detail::moved_object 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.get()); } -#else -inline mapped_region::mapped_region(mapped_region &&other) +inline mapped_region::mapped_region(BOOST_INTERPROCESS_RV_REF(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 inline std::size_t mapped_region::page_size_holder::get_page_size() @@ -264,7 +241,9 @@ inline mapped_region::mapped_region //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)){ + 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); } @@ -382,11 +361,10 @@ inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbyte inline void mapped_region::priv_close() { if(m_base){ - this->flush(); winapi::unmap_view_of_file(static_cast(m_base) - m_extra_offset); m_base = 0; } - #if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #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(); @@ -397,22 +375,15 @@ inline void mapped_region::priv_close() inline void mapped_region::dont_close_on_destruction() {} -#else //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#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) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false) {} -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline mapped_region::mapped_region(detail::moved_object other) - : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only) -{ this->swap(other.get()); } -#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) +inline mapped_region::mapped_region(BOOST_INTERPROCESS_RV_REF(mapped_region) other) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(read_only), m_is_xsi(false) { this->swap(other); } -#endif template inline std::size_t mapped_region::page_size_holder::get_page_size() @@ -425,13 +396,55 @@ inline mapped_region::mapped_region 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) + : m_base(MAP_FAILED), m_size(0), m_offset(0), m_extra_offset(0), m_mode(mode), m_is_xsi(false) { + mapping_handle_t map_hnd = mapping.get_mapping_handle(); + + if(map_hnd.is_xsi){ + //Get the size + ::shmid_ds xsi_ds; + int ret = ::shmctl(map_hnd.handle, IPC_STAT, &xsi_ds); + if(ret == -1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Compare sizess + if(size == 0){ + size = (std::size_t)xsi_ds.shm_segsz; + } + else if(size != (std::size_t)xsi_ds.shm_segsz){ + error_info err(size_error); + throw interprocess_exception(err); + } + //Calculate flag + int flag = 0; + if(m_mode == read_only){ + flag |= SHM_RDONLY; + } + else if(m_mode != read_write){ + error_info err(mode_error); + throw interprocess_exception(err); + } + //Attach memory + void *base = ::shmat(map_hnd.handle, (void*)address, flag); + if(base == (void*)-1){ + error_info err(system_error_code()); + throw interprocess_exception(err); + } + //Update members + m_base = base; + m_offset = offset; + m_size = size; + m_mode = mode; + m_extra_offset = 0; + m_is_xsi = true; + + return; + } + if(size == 0){ -// offset_t filesize = lseek64 offset_t filesize = lseek - (mapping.get_mapping_handle(), offset, SEEK_END); - + (map_hnd.handle, offset, SEEK_END); if(filesize == -1 ){ error_info err(system_error_code()); throw interprocess_exception(err); @@ -440,12 +453,13 @@ inline mapped_region::mapped_region 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); + throw interprocess_exception(err); } } @@ -459,7 +473,7 @@ inline mapped_region::mapped_region prot |= PROT_READ; flags |= MAP_SHARED; break; - + case read_write: prot |= (PROT_WRITE | PROT_READ); flags |= MAP_SHARED; @@ -469,7 +483,7 @@ inline mapped_region::mapped_region prot |= (PROT_WRITE | PROT_READ); flags |= MAP_PRIVATE; break; - + default: { error_info err(mode_error); @@ -496,7 +510,7 @@ inline mapped_region::mapped_region , static_cast(m_extra_offset + m_size) , prot , flags - , mapping.get_mapping_handle() + , mapping.get_mapping_handle().handle , offset - m_extra_offset); //Check if mapping was successful @@ -537,7 +551,12 @@ inline bool mapped_region::flush(std::size_t mapping_offset, std::size_t numbyte inline void mapped_region::priv_close() { if(m_base != MAP_FAILED){ - this->flush(); + if(m_is_xsi){ + int ret = ::shmdt(m_base); + assert(ret == 0); + (void)ret; + return; + } munmap(static_cast(m_base) - m_extra_offset, m_size + m_extra_offset); m_base = MAP_FAILED; } @@ -546,7 +565,7 @@ inline void mapped_region::priv_close() inline void mapped_region::dont_close_on_destruction() { m_base = MAP_FAILED; } -#endif //##if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) +#endif //##if (defined BOOST_INTERPROCESS_WINDOWS) template const std::size_t mapped_region::page_size_holder::PageSize @@ -560,19 +579,17 @@ inline std::size_t mapped_region::get_page_size() return page_size_holder<0>::PageSize; } -#if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + 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); + #else + detail::do_swap(this->m_is_xsi, other.m_is_xsi); #endif } @@ -583,13 +600,6 @@ struct null_mapped_region_function { return true; } }; -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; /// @endcond } //namespace interprocess { diff --git a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp index 2cdc2ce..dec5300 100644 --- a/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp +++ b/include/boost/interprocess/mem_algo/detail/mem_algo_common.hpp @@ -19,14 +19,17 @@ #include #include -#include +#include #include #include -#include #include #include +#include #include #include +#include +#include +#include //!\file //!Implements common operations for memory algorithms. @@ -36,206 +39,527 @@ namespace interprocess { namespace detail { template -struct multi_allocation_next +class basic_multiallocation_slist { - typedef typename detail:: - pointer_to_other::type - multi_allocation_next_ptr; - - multi_allocation_next(multi_allocation_next_ptr n) - : next_(n) - {} - multi_allocation_next_ptr next_; -}; - -//!This iterator is returned by "allocate_many" functions so that -//!the user can access the multiple buffers allocated in a single call -template -class basic_multiallocation_iterator - : public std::iterator -{ - void unspecified_bool_type_func() const {} - typedef void (basic_multiallocation_iterator::*unspecified_bool_type)() const; - typedef typename detail:: - pointer_to_other - >::type - multi_allocation_next_ptr; - public: - typedef char value_type; - typedef value_type & reference; - typedef value_type * pointer; - - basic_multiallocation_iterator() - : next_alloc_(0) - {} - - basic_multiallocation_iterator(multi_allocation_next_ptr next) - : next_alloc_(next) - {} - - basic_multiallocation_iterator &operator=(const basic_multiallocation_iterator &other) - { next_alloc_ = other.next_alloc_; return *this; } - - public: - basic_multiallocation_iterator& operator++() - { next_alloc_.next_ = detail::get_pointer(next_alloc_.next_->next_); return *this; } - - basic_multiallocation_iterator operator++(int) - { - basic_multiallocation_iterator result(next_alloc_.next_); - ++*this; - return result; - } - - bool operator== (const basic_multiallocation_iterator& other) const - { return next_alloc_.next_ == other.next_alloc_.next_; } - - bool operator!= (const basic_multiallocation_iterator& other) const - { return !operator== (other); } - - reference operator*() const - { return *reinterpret_cast(detail::get_pointer(next_alloc_.next_)); } - - operator unspecified_bool_type() const - { return next_alloc_.next_? &basic_multiallocation_iterator::unspecified_bool_type_func : 0; } - - pointer operator->() const - { return &(*(*this)); } - - static basic_multiallocation_iterator create_simple_range(void *mem) - { - basic_multiallocation_iterator it; - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); - it = basic_multiallocation_iterator(tmp_mem); - tmp_mem->next_ = 0; - return it; - } - - multi_allocation_next &get_multi_allocation_next() - { return *next_alloc_.next_; } + typedef VoidPointer void_pointer; private: - multi_allocation_next next_alloc_; -}; + static VoidPointer &priv_get_ref(const VoidPointer &p) + { return *static_cast(detail::get_pointer(p)); } -template -class basic_multiallocation_chain -{ - private: - basic_multiallocation_iterator it_; - VoidPointer last_mem_; - std::size_t num_mem_; - - basic_multiallocation_chain(const basic_multiallocation_chain &); - basic_multiallocation_chain &operator=(const basic_multiallocation_chain &); + basic_multiallocation_slist(basic_multiallocation_slist &); + basic_multiallocation_slist &operator=(basic_multiallocation_slist &); public: - typedef basic_multiallocation_iterator multiallocation_iterator; + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_slist) - basic_multiallocation_chain() - : it_(0), last_mem_(0), num_mem_(0) - {} - - void reset() + //!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 { - this->it_ = multiallocation_iterator(); - this->last_mem_ = 0; - this->num_mem_ = 0; - } + friend class basic_multiallocation_slist; + void unspecified_bool_type_func() const {} + typedef void (iterator::*unspecified_bool_type)() const; - void push_back(void *mem) - { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); + 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(detail::get_pointer(next_node_)); + return *this; + } - if(!this->last_mem_){ - this->it_ = basic_multiallocation_iterator(tmp_mem); + iterator operator++(int) + { + iterator result(*this); + ++*this; + return result; } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ = tmp_mem; - } - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - ++num_mem_; - } - void push_front(void *mem) + 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(detail::get_pointer(next_node_)); } + + operator unspecified_bool_type() const + { return next_node_? &iterator::unspecified_bool_type_func : 0; } + + pointer operator->() const + { return &(*(*this)); } + + private: + void_pointer next_node_; + }; + + private: + iterator it_; + + public: + basic_multiallocation_slist() + : it_(iterator()) + {} + + basic_multiallocation_slist(void_pointer p) + : it_(p ? iterator_to(p) : iterator()) + {} + + basic_multiallocation_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) + : it_(iterator()) + { this->swap(other); } + + basic_multiallocation_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_slist) other) { - typedef multi_allocation_next next_impl_t; - next_impl_t * tmp_mem = static_cast(mem); - ++num_mem_; - - if(!this->last_mem_){ - this->it_ = basic_multiallocation_iterator(tmp_mem); - tmp_mem->next_ = 0; - this->last_mem_ = tmp_mem; - } - else{ - next_impl_t * old_first = &this->it_.get_multi_allocation_next(); - tmp_mem->next_ = old_first; - this->it_ = basic_multiallocation_iterator(tmp_mem); - } - } - - void swap(basic_multiallocation_chain &other_chain) - { - std::swap(this->it_, other_chain.it_); - std::swap(this->last_mem_, other_chain.last_mem_); - std::swap(this->num_mem_, other_chain.num_mem_); - } - - void splice_back(basic_multiallocation_chain &other_chain) - { - typedef multi_allocation_next next_impl_t; - multiallocation_iterator end_it; - multiallocation_iterator other_it = other_chain.get_it(); - multiallocation_iterator this_it = this->get_it(); - if(end_it == other_it){ - return; - } - else if(end_it == this_it){ - this->swap(other_chain); - } - else{ - static_cast(detail::get_pointer(this->last_mem_))->next_ - = &other_chain.it_.get_multi_allocation_next(); - this->last_mem_ = other_chain.last_mem_; - this->num_mem_ += other_chain.num_mem_; - } - } - - void *pop_front() - { - multiallocation_iterator itend; - if(this->it_ == itend){ - this->last_mem_= 0; - this->num_mem_ = 0; - return 0; - } - else{ - void *addr = &*it_; - ++it_; - --num_mem_; - if(!num_mem_){ - this->last_mem_ = 0; - this->it_ = multiallocation_iterator(); - } - return addr; - } + basic_multiallocation_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; } bool empty() const - { return !num_mem_; } + { return !it_; } - multiallocation_iterator get_it() const - { return it_; } + iterator before_begin() const + { return iterator(void_pointer(const_cast(static_cast(&it_.next_node_)))); } - std::size_t size() const - { return num_mem_; } + 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 basic_multiallocation_cached_slist +{ + private: + basic_multiallocation_slist slist_; + typename basic_multiallocation_slist::iterator last_; + + basic_multiallocation_cached_slist(basic_multiallocation_cached_slist &); + basic_multiallocation_cached_slist &operator=(basic_multiallocation_cached_slist &); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_slist) + + typedef typename basic_multiallocation_slist::void_pointer void_pointer; + typedef typename basic_multiallocation_slist::iterator iterator; + + basic_multiallocation_cached_slist() + : slist_(), last_(slist_.before_begin()) + {} +/* + basic_multiallocation_cached_slist(iterator first_node) + : slist_(first_node), last_(slist_.before_begin()) + { + iterator end; + while(first_node != end){ + ++last_; + } + }*/ + + basic_multiallocation_cached_slist(void_pointer p1, void_pointer p2) + : slist_(p1), last_(p2 ? iterator_to(p2) : slist_.before_begin()) + {} + + basic_multiallocation_cached_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + : slist_(), last_(slist_.before_begin()) + { this->swap(other); } + + basic_multiallocation_cached_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_slist) other) + { + basic_multiallocation_cached_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + bool empty() const + { return slist_.empty(); } + + iterator before_begin() const + { return slist_.before_begin(); } + + iterator begin() const + { return slist_.begin(); } + + iterator end() const + { return slist_.end(); } + + iterator last() const + { return last_; } + + void clear() + { + slist_.clear(); + last_ = slist_.before_begin(); + } + + iterator insert_after(iterator it, void_pointer m) + { + slist_.insert_after(it, m); + if(it == last_){ + last_ = slist_.iterator_to(m); + } + return iterator_to(m); + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(last_, m); } + + void pop_front() + { + if(last_ == slist_.begin()){ + last_ = slist_.before_begin(); + } + slist_.pop_front(); + } + + void *front() const + { return slist_.front(); } + + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { + if(before_begin == before_end) + return; + if(after_this == last_){ + last_ = before_end; + } + slist_.splice_after(after_this, before_begin, before_end); + } + + void swap(basic_multiallocation_cached_slist &x) + { + slist_.swap(x.slist_); + using std::swap; + swap(last_, x.last_); + if(last_ == x.before_begin()){ + last_ = this->before_begin(); + } + if(x.last_ == this->before_begin()){ + x.last_ = x.before_begin(); + } + } + + static iterator iterator_to(void_pointer p) + { return basic_multiallocation_slist::iterator_to(p); } + + std::pair extract_data() + { + if(this->empty()){ + return std::pair(void_pointer(0), void_pointer(0)); + } + else{ + void_pointer p1 = slist_.extract_data(); + void_pointer p2 = void_pointer(&*last_); + last_ = iterator(); + return std::pair(p1, p2); + } + } +}; + +template +class basic_multiallocation_cached_counted_slist +{ + private: + MultiallocatorCachedSlist cached_slist_; + std::size_t size_; + + basic_multiallocation_cached_counted_slist(basic_multiallocation_cached_counted_slist &); + basic_multiallocation_cached_counted_slist &operator=(basic_multiallocation_cached_counted_slist &); + + public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(basic_multiallocation_cached_counted_slist) + + typedef typename MultiallocatorCachedSlist::void_pointer void_pointer; + typedef typename MultiallocatorCachedSlist::iterator iterator; + + basic_multiallocation_cached_counted_slist() + : cached_slist_(), size_(0) + {} + + basic_multiallocation_cached_counted_slist(void_pointer p1, void_pointer p2, std::size_t n) + : cached_slist_(p1, p2), size_(n) + {} + + basic_multiallocation_cached_counted_slist(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + : cached_slist_(), size_(0) + { this->swap(other); } + + basic_multiallocation_cached_counted_slist& operator=(BOOST_INTERPROCESS_RV_REF(basic_multiallocation_cached_counted_slist) other) + { + basic_multiallocation_cached_counted_slist tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + basic_multiallocation_cached_counted_slist (MultiallocatorCachedSlist mem, std::size_t n) + : cached_slist_(boost::interprocess::move(mem)), size_(n) + {} + + bool empty() const + { return cached_slist_.empty(); } + + std::size_t size() const + { return size_; } + + iterator before_begin() const + { return cached_slist_.before_begin(); } + + iterator begin() const + { return cached_slist_.begin(); } + + iterator end() const + { return cached_slist_.end(); } + + iterator last() const + { return cached_slist_.last(); } + + void clear() + { + cached_slist_.clear(); + size_ = 0; + } + + iterator insert_after(iterator it, void_pointer m) + { + iterator ret = cached_slist_.insert_after(it, m); + ++size_; + return ret; + } + + void push_front(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void push_back(void_pointer m) + { this->insert_after(this->before_begin(), m); } + + void pop_front() + { + cached_slist_.pop_front(); + --size_; + } + + void *front() const + { return cached_slist_.front(); } + + void splice_after(iterator after_this, basic_multiallocation_cached_counted_slist &x, iterator before_begin, iterator before_end) + { + std::size_t n = static_cast(std::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 extract_data() + { + size_ = 0; + return cached_slist_.extract_data(); + } +}; + +template +struct cast_functor +{ + typedef typename detail::add_reference::type result_type; + result_type operator()(char &ptr) const + { return *static_cast(static_cast(&ptr)); } +}; + + +template +class transform_multiallocation_chain +{ +private: + + MultiallocationChain holder_; + typedef typename MultiallocationChain::void_pointer void_pointer; + typedef typename boost::pointer_to_other + ::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(detail::get_pointer(p))); + } + +public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(transform_multiallocation_chain) + + typedef transform_iterator + < typename MultiallocationChain::iterator + , detail::cast_functor > iterator; + + transform_multiallocation_chain(void_pointer p1, void_pointer p2, std::size_t n) + : holder_(p1, p2, n) + {} + + transform_multiallocation_chain() + : holder_() + {} + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + : holder_() + { this->swap(other); } + + transform_multiallocation_chain(BOOST_INTERPROCESS_RV_REF(MultiallocationChain) other) + : holder_(boost::interprocess::move(other)) + {} + + transform_multiallocation_chain& operator=(BOOST_INTERPROCESS_RV_REF(transform_multiallocation_chain) other) + { + transform_multiallocation_chain tmp(boost::interprocess::move(other)); + this->swap(tmp); + return *this; + } + + void push_front(pointer mem) + { holder_.push_front(mem); } + + void swap(transform_multiallocation_chain &other_chain) + { holder_.swap(other_chain.holder_); } + /* + void splice_after(iterator after_this, iterator before_begin, iterator before_end) + { holder_.splice_after(after_this.base(), before_begin.base(), before_end.base()); } + */ + void splice_after(iterator after_this, transform_multiallocation_chain &x, iterator before_begin, iterator before_end, std::size_t n) + { holder_.splice_after(after_this.base(), x.holder_, before_begin.base(), before_end.base(), n); } + + void pop_front() + { holder_.pop_front(); } + + pointer front() const + { return cast(holder_.front()); } + + bool empty() const + { return holder_.empty(); } + + iterator before_begin() const + { return iterator(holder_.before_begin()); } + + iterator begin() const + { return iterator(holder_.begin()); } + + iterator end() const + { return iterator(holder_.end()); } + + iterator last() const + { return iterator(holder_.last()); } + + std::size_t size() const + { return holder_.size(); } + + void clear() + { holder_.clear(); } + + iterator insert_after(iterator it, pointer m) + { return iterator(holder_.insert_after(it.base(), m)); } + + static iterator iterator_to(pointer p) + { return iterator(MultiallocationChain::iterator_to(p)); } + + std::pair extract_data() + { return holder_.extract_data(); } + + MultiallocationChain extract_multiallocation_chain() + { + return MultiallocationChain(boost::interprocess::move(holder_)); + } +}; //!This class implements several allocation functions shared by different algorithms //!(aligned allocation, multiple allocation...). @@ -245,19 +569,16 @@ class memory_algorithm_common public: typedef typename MemoryAlgorithm::void_pointer void_pointer; typedef typename MemoryAlgorithm::block_ctrl block_ctrl; - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; - typedef multi_allocation_next multi_allocation_next_t; - typedef typename multi_allocation_next_t:: - multi_allocation_next_ptr multi_allocation_next_ptr; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; typedef memory_algorithm_common 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 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); } @@ -280,12 +601,17 @@ class memory_algorithm_common static std::size_t multiple_of_units(std::size_t size) { return detail::get_rounded_size(size, Alignment); } - static multiallocation_iterator allocate_many + 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::interprocess::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) @@ -381,7 +707,7 @@ class memory_algorithm_common return true; } - static multiallocation_iterator allocate_many + static multiallocation_chain allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes , std::size_t n_elements @@ -403,7 +729,8 @@ class memory_algorithm_common std::size_t real_size; if(alignment <= Alignment){ - return memory_algo->priv_allocate(allocate_new, nbytes, nbytes, real_size).first; + return memory_algo->priv_allocate + (boost::interprocess::allocate_new, nbytes, nbytes, real_size).first; } if(nbytes > UsableByPreviousChunk) @@ -428,7 +755,8 @@ class memory_algorithm_common ); //Now allocate the buffer - void *buffer = memory_algo->priv_allocate(allocate_new, request, request, real_size).first; + void *buffer = memory_algo->priv_allocate + (boost::interprocess::allocate_new, request, request, real_size).first; if(!buffer){ return 0; } @@ -608,7 +936,7 @@ class memory_algorithm_common } private: - static multiallocation_iterator priv_allocate_many + static multiallocation_chain priv_allocate_many ( MemoryAlgorithm *memory_algo , const std::size_t *elem_sizes , std::size_t n_elements @@ -620,7 +948,7 @@ class memory_algorithm_common //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(multi_allocation_next_ptr)); + 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; @@ -634,7 +962,8 @@ class memory_algorithm_common } } - multi_allocation_next_ptr first = 0, previous = 0; + 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; @@ -645,7 +974,7 @@ class memory_algorithm_common std::size_t received_size; std::pair ret = memory_algo->priv_allocate - (allocate_new, min_allocation, total_bytes, received_size, 0); + (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0); if(!ret.first){ break; } @@ -710,33 +1039,28 @@ class memory_algorithm_common 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(multi_allocation_next_t)); - multi_allocation_next_ptr p = new(memory_algo->priv_get_user_buffer(new_block))multi_allocation_next_t(0); - - if(!first){ - first = p; - } - else{ - previous->next_ = p; - } - previous = p; + 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){ - while(first){ - multi_allocation_next_ptr prev = first; - first = first->next_; - memory_algo->priv_deallocate(detail::get_pointer(prev)); - } - return multiallocation_iterator(); + priv_deallocate_many(memory_algo, boost::interprocess::move(chain)); } - else{ - return multiallocation_iterator(first); + return boost::interprocess::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); } } }; diff --git a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp index b196faf..80c6209 100644 --- a/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/multi_simple_seq_fit_impl.hpp @@ -18,8 +18,10 @@ #include #include +#include + #include -#include +#include #include #include #include @@ -67,7 +69,7 @@ class simple_seq_fit_impl private: struct block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; /*!Block control structure*/ @@ -149,7 +151,7 @@ class simple_seq_fit_impl void clear_free_memory(); std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::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); @@ -169,7 +171,7 @@ class simple_seq_fit_impl private: /*!Real allocation algorithm with min allocation option*/ - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -188,7 +190,7 @@ class simple_seq_fit_impl ,std::size_t &received_size); /*!Real expand to both sides implementation*/ - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -375,7 +377,7 @@ inline void* simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } template @@ -390,7 +392,7 @@ inline void* simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - allocation_command (allocation_type command, std::size_t min_size, + allocation_command (boost::interprocess::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) { @@ -398,7 +400,7 @@ inline std::pair simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- (void)backwards_multiple; - command &= ~expand_bwd; + command &= ~boost::interprocess::expand_bwd; if(!command) return std::pair(0, false); return priv_allocate(command, min_size, preferred_size, received_size, reuse_ptr); @@ -426,7 +428,7 @@ inline void* simple_seq_fit_impl:: //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; + void *addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; if(!addr){ //If this fails we will try the allocation through the segment //creator. @@ -447,7 +449,7 @@ inline void* simple_seq_fit_impl:: 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; + addr = this->priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } } return addr; @@ -455,7 +457,7 @@ inline void* simple_seq_fit_impl:: template void* simple_seq_fit_impl:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -471,14 +473,14 @@ void* simple_seq_fit_impl:: return reuse_ptr; } - if(command & expand_fwd){ + if(command & boost::interprocess::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){ + if(command & boost::interprocess::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; @@ -534,13 +536,13 @@ void* simple_seq_fit_impl:: template std::pair simple_seq_fit_impl:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::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){ + if(command & boost::interprocess::shrink_in_place){ bool success = this->priv_shrink(reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -565,14 +567,14 @@ std::pair simple_seq_fit_impl:: //Expand in place //reuse_ptr, limit_size, preferred_size, received_size // - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::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){ + if(command & boost::interprocess::allocate_new){ received_size = 0; while(block != root){ //Update biggest block pointers @@ -600,7 +602,7 @@ std::pair simple_seq_fit_impl:: } } //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return return_type(priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false), true); } @@ -809,12 +811,12 @@ inline void* simple_seq_fit_impl:: std::size_t ignore; if(alignment <= Alignment){ - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::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; + void *buffer = priv_allocate(boost::interprocess::allocate_new, request, request, ignore).first; if(!buffer) return 0; else if ((((std::size_t)(buffer)) % alignment) == 0) diff --git a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp index bd0773a..19ed89d 100644 --- a/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp +++ b/include/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp @@ -18,8 +18,10 @@ #include #include +#include + #include -#include +#include #include #include #include @@ -61,15 +63,13 @@ class simple_seq_fit_impl typedef MutexFamily mutex_family; //!Pointer type to be used with the rest of the Interprocess framework typedef VoidPointer void_pointer; - - typedef detail::basic_multiallocation_iterator - multiallocation_iterator; - typedef detail::basic_multiallocation_chain - multiallocation_chain; + typedef detail::basic_multiallocation_cached_slist multialloc_cached; + typedef detail::basic_multiallocation_cached_counted_slist + multiallocation_chain; private: class block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; class block_ctrl; @@ -109,7 +109,6 @@ class simple_seq_fit_impl std::size_t m_extra_hdr_bytes; } m_header; - friend class detail::basic_multiallocation_iterator; friend class detail::memory_algorithm_common; typedef detail::memory_algorithm_common algo_impl_t; @@ -134,13 +133,27 @@ class simple_seq_fit_impl /// @cond //!Multiple element allocation, same size - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); + multiallocation_chain + allocate_many(std::size_t elem_bytes, std::size_t num_elements) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_bytes, num_elements); + } //!Multiple element allocation, different size - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + multiallocation_chain + allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) + { + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + } //!Multiple element deallocation - void deallocate_many(multiallocation_iterator it); + void deallocate_many(multiallocation_chain chain); /// @endcond @@ -171,12 +184,12 @@ class simple_seq_fit_impl template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair - raw_allocation_command (allocation_type command, std::size_t limit_size, + raw_allocation_command (boost::interprocess::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); @@ -196,13 +209,13 @@ class simple_seq_fit_impl static block_ctrl *priv_get_block(const void *ptr); //!Real allocation algorithm with min allocation option - std::pair priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size ,void *reuse_ptr = 0); - std::pair priv_allocation_command(allocation_type command + std::pair priv_allocation_command(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -233,7 +246,7 @@ class simple_seq_fit_impl ,std::size_t &received_size); //!Real expand to both sides implementation - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -386,7 +399,7 @@ void simple_seq_fit_impl::shrink_to_fit() if(!m_header.m_allocated){ assert(prev == root); std::size_t ignore; - unique_block = priv_allocate(allocate_new, 0, 0, ignore).first; + unique_block = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; if(!unique_block) return; last = detail::get_pointer(m_header.m_root.m_next); @@ -547,7 +560,7 @@ inline void* simple_seq_fit_impl:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - return priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + return priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; } template @@ -564,7 +577,7 @@ inline void* simple_seq_fit_impl:: template template inline std::pair simple_seq_fit_impl:: - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { @@ -577,13 +590,13 @@ inline std::pair simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::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(static_cast(0), 0); - if(command & try_shrink_in_place){ + if(command & boost::interprocess::try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object , preferred_objects*sizeof_object, received_objects); @@ -596,11 +609,11 @@ inline std::pair simple_seq_fit_impl:: template inline std::pair simple_seq_fit_impl:: - priv_allocation_command (allocation_type command, std::size_t limit_size, + priv_allocation_command (boost::interprocess::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; + command &= ~boost::interprocess::expand_bwd; if(!command) return std::pair(static_cast(0), false); std::pair ret; @@ -634,7 +647,7 @@ inline std::size_t simple_seq_fit_impl:: template void* simple_seq_fit_impl:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -650,14 +663,14 @@ void* simple_seq_fit_impl:: return reuse_ptr; } - if(command & expand_fwd){ + if(command & boost::interprocess::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){ + if(command & boost::interprocess::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; @@ -711,43 +724,20 @@ void* simple_seq_fit_impl:: return 0; } -template -inline typename simple_seq_fit_impl::multiallocation_iterator - simple_seq_fit_impl:: - allocate_many(std::size_t elem_bytes, std::size_t num_elements) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t:: - allocate_many(this, elem_bytes, num_elements); -} - template inline void simple_seq_fit_impl:: - deallocate_many(typename simple_seq_fit_impl::multiallocation_iterator it) + deallocate_many(typename simple_seq_fit_impl::multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - while(it){ - void *addr = &*it; - ++it; + while(!chain.empty()){ + void *addr = chain.front(); + chain.pop_front(); this->priv_deallocate(addr); } } -template -inline typename simple_seq_fit_impl::multiallocation_iterator - simple_seq_fit_impl:: - allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); -} - template inline std::size_t simple_seq_fit_impl:: priv_get_total_units(std::size_t userbytes) @@ -759,13 +749,13 @@ inline std::size_t simple_seq_fit_impl:: template std::pair simple_seq_fit_impl:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::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){ + if(command & boost::interprocess::shrink_in_place){ bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -790,7 +780,7 @@ std::pair simple_seq_fit_impl:: //Expand in place //reuse_ptr, limit_size, preferred_size, received_size // - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ void *ret = priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, true); if(ret){ @@ -799,7 +789,7 @@ std::pair simple_seq_fit_impl:: } } - if(command & allocate_new){ + if(command & boost::interprocess::allocate_new){ received_size = 0; while(block != root){ //Update biggest block pointers @@ -835,7 +825,7 @@ std::pair simple_seq_fit_impl:: } } //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::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); diff --git a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp index 5379139..d4299b3 100644 --- a/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp +++ b/include/boost/interprocess/mem_algo/rbtree_best_fit.hpp @@ -18,9 +18,11 @@ #include #include +#include + #include #include -#include +#include #include #include #include @@ -40,15 +42,7 @@ #include #include -//#define BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY - -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY #include -#else -//#include -//#include -#include -#endif //!\file //!Describes a best-fit algorithm based in an intrusive red-black tree used to allocate @@ -75,35 +69,26 @@ class rbtree_best_fit typedef MutexFamily mutex_family; //!Pointer type to be used with the rest of the Interprocess framework typedef VoidPointer void_pointer; - typedef detail::basic_multiallocation_iterator - multiallocation_iterator; - typedef detail::basic_multiallocation_chain - multiallocation_chain; + //typedef detail::basic_multiallocation_cached_counted_slist multiallocation_chain; + + typedef detail::basic_multiallocation_cached_slist multialloc_cached; + typedef detail::basic_multiallocation_cached_counted_slist + multiallocation_chain; /// @cond private: struct block_ctrl; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type block_ctrl_ptr; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type char_ptr; -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY typedef typename bi::make_set_base_hook -#else -// typedef typename bi::make_splay_set_base_hook -// typedef typename bi::make_avl_set_base_hook - typedef typename bi::make_sg_set_base_hook -#endif < bi::void_pointer , bi::optimize_size , bi::link_mode >::type TreeHook; - typedef detail::multi_allocation_next multi_allocation_next_t; - typedef typename multi_allocation_next_t:: - multi_allocation_next_ptr multi_allocation_next_ptr; - struct SizeHolder { //!This block's memory size (including block_ctrl @@ -138,13 +123,7 @@ class rbtree_best_fit //!Shared interprocess_mutex to protect memory allocate/deallocate typedef typename MutexFamily::mutex_type interprocess_mutex; -#ifndef BOOST_INTERPROCESS_RBTREE_BEST_FIT_USE_SPLAY typedef typename bi::make_multiset -#else - //typedef typename bi::make_splay_multiset - //typedef typename bi::make_avl_multiset - typedef typename bi::make_sg_multiset -#endif >::type Imultiset; typedef typename Imultiset::iterator imultiset_iterator; @@ -163,7 +142,6 @@ class rbtree_best_fit std::size_t m_size; } m_header; - friend class detail::basic_multiallocation_iterator; friend class detail::memory_algorithm_common; typedef detail::memory_algorithm_common algo_impl_t; @@ -192,13 +170,27 @@ class rbtree_best_fit //Experimental. Dont' use //!Multiple element allocation, same size - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements); + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) + { + + //----------------------- + boost::interprocess::scoped_lock guard(m_header); + //----------------------- + return algo_impl_t::allocate_many(this, elem_bytes, num_elements); + } //!Multiple element allocation, different size - multiallocation_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element); + multiallocation_chain allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) + { + + //----------------------- + boost::interprocess::scoped_lock 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_iterator it); + void deallocate_many(multiallocation_chain chain); /// @endcond @@ -231,12 +223,12 @@ class rbtree_best_fit template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0); std::pair - raw_allocation_command (allocation_type command, std::size_t limit_object, + raw_allocation_command (boost::interprocess::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); @@ -252,13 +244,13 @@ class rbtree_best_fit static std::size_t priv_first_block_offset(const void *this_ptr, std::size_t extra_hdr_bytes); std::pair - priv_allocation_command(allocation_type command, std::size_t limit_size, + priv_allocation_command(boost::interprocess::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 priv_allocate(allocation_type command + std::pair priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size @@ -281,7 +273,7 @@ class rbtree_best_fit ,std::size_t &received_size); //!Real expand to both sides implementation - void* priv_expand_both_sides(allocation_type command + void* priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -463,7 +455,7 @@ void rbtree_best_fit::shrink_to_fit() 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; + unique_buffer = priv_allocate(boost::interprocess::allocate_new, 0, 0, ignore).first; if(!unique_buffer) return; algo_impl_t::assert_alignment(unique_buffer); @@ -631,7 +623,7 @@ inline void* rbtree_best_fit:: boost::interprocess::scoped_lock guard(m_header); //----------------------- std::size_t ignore; - void * ret = priv_allocate(allocate_new, nbytes, nbytes, ignore).first; + void * ret = priv_allocate(boost::interprocess::allocate_new, nbytes, nbytes, ignore).first; return ret; } @@ -648,7 +640,7 @@ inline void* rbtree_best_fit:: template template inline std::pair rbtree_best_fit:: - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr) { @@ -661,13 +653,13 @@ inline std::pair rbtree_best_fit inline std::pair rbtree_best_fit:: - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::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(static_cast(0), 0); - if(command & try_shrink_in_place){ + if(command & boost::interprocess::try_shrink_in_place){ bool success = algo_impl_t::try_shrink ( this, reuse_ptr, limit_objects*sizeof_object , preferred_objects*sizeof_object, received_objects); @@ -681,7 +673,7 @@ inline std::pair rbtree_best_fit inline std::pair rbtree_best_fit:: - priv_allocation_command (allocation_type command, std::size_t limit_size, + priv_allocation_command (boost::interprocess::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) { @@ -732,7 +724,7 @@ inline void rbtree_best_fit::zero_free_m template void* rbtree_best_fit:: - priv_expand_both_sides(allocation_type command + priv_expand_both_sides(boost::interprocess::allocation_type command ,std::size_t min_size ,std::size_t preferred_size ,std::size_t &received_size @@ -741,7 +733,7 @@ void* rbtree_best_fit:: ,std::size_t backwards_multiple) { algo_impl_t::assert_alignment(reuse_ptr); - if(command & expand_fwd){ + if(command & boost::interprocess::expand_fwd){ if(priv_expand(reuse_ptr, min_size, preferred_size, received_size)) return reuse_ptr; } @@ -756,7 +748,7 @@ void* rbtree_best_fit:: BOOST_ASSERT(0 == (preferred_size % backwards_multiple)); } - if(command & expand_bwd){ + if(command & boost::interprocess::expand_bwd){ //Obtain the real size of the block block_ctrl *reuse = priv_get_block(reuse_ptr); @@ -791,7 +783,7 @@ void* rbtree_best_fit:: //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){ + if(command & boost::interprocess::expand_fwd){ std::size_t received_size2; if(!priv_expand(reuse_ptr, received_size, received_size, received_size2)){ assert(0); @@ -873,45 +865,19 @@ void* rbtree_best_fit:: return 0; } -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: - allocate_many(std::size_t elem_bytes, std::size_t num_elements) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_bytes, num_elements); -} - template inline void rbtree_best_fit:: - deallocate_many(typename rbtree_best_fit::multiallocation_iterator it) + deallocate_many(typename rbtree_best_fit::multiallocation_chain chain) { //----------------------- boost::interprocess::scoped_lock guard(m_header); //----------------------- - while(it){ - void *addr = &*it; - ++it; - this->priv_deallocate(addr); - } -} - -template -inline typename rbtree_best_fit::multiallocation_iterator - rbtree_best_fit:: - allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element) -{ - //----------------------- - boost::interprocess::scoped_lock guard(m_header); - //----------------------- - return algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element); + algo_impl_t::deallocate_many(this, boost::interprocess::move(chain)); } template std::pair rbtree_best_fit:: - priv_allocate(allocation_type command + priv_allocate(boost::interprocess::allocation_type command ,std::size_t limit_size ,std::size_t preferred_size ,std::size_t &received_size @@ -919,9 +885,9 @@ std::pair rbtree_best_fit: ,std::size_t backwards_multiple) { //Remove me. Forbid backwards allocation - //command &= (~expand_bwd); + //command &= (~boost::interprocess::expand_bwd); - if(command & shrink_in_place){ + if(command & boost::interprocess::shrink_in_place){ bool success = algo_impl_t::shrink(this, reuse_ptr, limit_size, preferred_size, received_size); return std::pair ((success ? reuse_ptr : 0), true); @@ -940,14 +906,14 @@ std::pair rbtree_best_fit: std::size_t limit_units = priv_get_total_units(limit_size); //Expand in place - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::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){ + if(command & boost::interprocess::allocate_new){ size_block_ctrl_compare comp; imultiset_iterator it(m_header.m_imultiset.lower_bound(preferred_units, comp)); @@ -965,7 +931,7 @@ std::pair rbtree_best_fit: //Now try to expand both sides with min size - if(reuse_ptr && (command & (expand_fwd | expand_bwd))){ + if(reuse_ptr && (command & (boost::interprocess::expand_fwd | boost::interprocess::expand_bwd))){ return return_type(priv_expand_both_sides (command, limit_size, preferred_size, received_size, reuse_ptr, false, backwards_multiple), true); } diff --git a/include/boost/interprocess/offset_ptr.hpp b/include/boost/interprocess/offset_ptr.hpp index e89ef76..c1ae9f4 100644 --- a/include/boost/interprocess/offset_ptr.hpp +++ b/include/boost/interprocess/offset_ptr.hpp @@ -162,7 +162,11 @@ class offset_ptr //!Dereferencing operator, if it is a null offset_ptr behavior //! is undefined. Never throws. reference operator* () const - { return *(this->get()); } + { + pointer p = this->get(); + reference r = *p; + return r; + } //!Indexing operator. //!Never throws. diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index a9836f6..972e08c 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -72,8 +72,7 @@ class segment_manager_base /// @cond //Experimental. Don't use - typedef typename MemoryAlgorithm::multiallocation_iterator multiallocation_iterator; - typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; + typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain; /// @endcond @@ -123,38 +122,40 @@ class segment_manager_base //Experimental. Dont' use. //!Allocates n_elements of //!elem_size bytes. Throws bad_alloc on failure. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements) + multiallocation_chain allocate_many(std::size_t elem_bytes, std::size_t num_elements) { - multiallocation_iterator ret = MemoryAlgorithm::allocate_many(elem_bytes, num_elements); - if(!ret) throw bad_alloc(); - return ret; + multiallocation_chain mem(MemoryAlgorithm::allocate_many(elem_bytes, num_elements)); + if(mem.empty()) throw bad_alloc(); + return boost::interprocess::move(mem); } //!Allocates n_elements, each one of //!element_lenghts[i]*sizeof_element bytes. Throws bad_alloc on failure. - multiallocation_iterator allocate_many + multiallocation_chain allocate_many (const std::size_t *element_lenghts, std::size_t n_elements, std::size_t sizeof_element = 1) { - multiallocation_iterator ret = MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element); - if(!ret) throw bad_alloc(); - return ret; + multiallocation_chain mem(MemoryAlgorithm::allocate_many(element_lenghts, n_elements, sizeof_element)); + if(mem.empty()) throw bad_alloc(); + return boost::interprocess::move(mem); } //!Allocates n_elements of //!elem_size bytes. Returns a default constructed iterator on failure. - multiallocation_iterator allocate_many(std::size_t elem_bytes, std::size_t num_elements, std::nothrow_t) + 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_iterator allocate_many(const std::size_t *elem_sizes, std::size_t n_elements, std::size_t sizeof_element, std::nothrow_t) + 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_iterator it) - { MemoryAlgorithm::deallocate_many(it); } + void deallocate_many(multiallocation_chain chain) + { MemoryAlgorithm::deallocate_many(boost::interprocess::move(chain)); } /// @endcond @@ -185,27 +186,27 @@ class segment_manager_base template std::pair - allocation_command (allocation_type command, std::size_t limit_size, + allocation_command (boost::interprocess::allocation_type command, std::size_t limit_size, std::size_t preferred_size,std::size_t &received_size, T *reuse_ptr = 0) { std::pair ret = MemoryAlgorithm::allocation_command - ( command | nothrow_allocation, limit_size, preferred_size, received_size + ( command | boost::interprocess::nothrow_allocation, limit_size, preferred_size, received_size , reuse_ptr); - if(!(command & nothrow_allocation) && !ret.first) + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) throw bad_alloc(); return ret; } std::pair - raw_allocation_command (allocation_type command, std::size_t limit_objects, + raw_allocation_command (boost::interprocess::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 ret = MemoryAlgorithm::raw_allocation_command - ( command | nothrow_allocation, limit_objects, preferred_objects, received_objects + ( command | boost::interprocess::nothrow_allocation, limit_objects, preferred_objects, received_objects , reuse_ptr, sizeof_object); - if(!(command & nothrow_allocation) && !ret.first) + if(!(command & boost::interprocess::nothrow_allocation) && !ret.first) throw bad_alloc(); return ret; } @@ -297,7 +298,7 @@ class segment_manager_base //scoped_lock guard(m_header); //------------------------------- - if(ctrl_data->allocation_type() != anonymous_type){ + if(ctrl_data->alloc_type() != anonymous_type){ //This is not an anonymous object, the pointer is wrong! assert(0); } @@ -311,11 +312,6 @@ class segment_manager_base /// @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 @@ -351,7 +347,6 @@ class segment_manager typedef MemoryAlgorithm memory_algorithm; typedef typename Base::void_pointer void_pointer; typedef CharType char_type; - typedef typename Base::multiallocation_iterator multiallocation_iterator; typedef segment_manager_base segment_manager_base_type; @@ -672,6 +667,7 @@ class segment_manager typename deleter::type get_deleter() { return typename deleter::type(this); } + /// @cond //!Generic named/anonymous new function. Offers all the possibilities, @@ -753,7 +749,7 @@ class segment_manager 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()){ + switch(ctrl_data->alloc_type()){ case anonymous_type: this->prot_anonymous_destroy(ptr, dtor); break; @@ -779,7 +775,7 @@ class segment_manager //!functions. Does not throw static const CharType *priv_get_instance_name(block_header_t *ctrl_data) { - allocation_type type = ctrl_data->allocation_type(); + boost::interprocess::allocation_type type = ctrl_data->alloc_type(); if(type != named_type){ assert((type == anonymous_type && ctrl_data->m_num_char == 0) || (type == unique_type && ctrl_data->m_num_char != 0) ); @@ -805,8 +801,8 @@ class segment_manager 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(); + assert((instance_type)ctrl_data->alloc_type() < max_allocation_type); + return (instance_type)ctrl_data->alloc_type(); } static std::size_t priv_get_reserved_bytes() @@ -1311,18 +1307,13 @@ class segment_manager typedef typename MemoryAlgorithm::mutex_family::recursive_mutex_type rmutex; - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - scoped_lock - #else - detail::move_return > - #endif - priv_get_lock(bool use_lock) + scoped_lock priv_get_lock(bool use_lock) { scoped_lock local(m_header, defer_lock); if(use_lock){ local.lock(); } - return local; + return scoped_lock(boost::interprocess::move(local)); } //!This struct includes needed data and derives from @@ -1338,6 +1329,7 @@ class segment_manager , m_unique_index(restricted_segment_mngr) {} } m_header; + /// @endcond }; diff --git a/include/boost/interprocess/shared_memory_object.hpp b/include/boost/interprocess/shared_memory_object.hpp index f84c0c7..b1a9b34 100644 --- a/include/boost/interprocess/shared_memory_object.hpp +++ b/include/boost/interprocess/shared_memory_object.hpp @@ -22,10 +22,11 @@ #include #include #include -#include //std::remove #include -#ifdef BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS +#if defined(BOOST_INTERPROCESS_SYSTEM_V_SHARED_MEMORY_OBJECTS) +# include //System V shared memory... +#elif defined(BOOST_INTERPROCESS_POSIX_SHARED_MEMORY_OBJECTS) # include //O_CREAT, O_*... # include //shm_xxx # include //ftruncate, close @@ -46,11 +47,12 @@ class shared_memory_object { /// @cond //Non-copyable and non-assignable - shared_memory_object(const shared_memory_object &); - shared_memory_object &operator=(const shared_memory_object &); + shared_memory_object(shared_memory_object &); + shared_memory_object &operator=(shared_memory_object &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(shared_memory_object) //!Default constructor. Represents an empty shared_memory_object. shared_memory_object(); @@ -74,44 +76,22 @@ class shared_memory_object //!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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_memory_object(detail::moved_object moved) - : m_handle(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - shared_memory_object(shared_memory_object &&moved) + shared_memory_object(BOOST_INTERPROCESS_RV_REF(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_memory_object &operator= - (detail::moved_object moved) + shared_memory_object &operator=(BOOST_INTERPROCESS_RV_REF(shared_memory_object) moved) { - shared_memory_object tmp(moved); + shared_memory_object tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } - #else - shared_memory_object &operator=(shared_memory_object &&moved) - { - shared_memory_object tmp(detail::move_impl(moved)); - this->swap(tmp); - return *this; - } - #endif //!Swaps the shared_memory_objects. Does not throw - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.get()); } - void swap(shared_memory_object &other); - #else - void swap(shared_memory_object &&other); - #endif + void swap(shared_memory_object &moved); //!Erases a shared memory object from the system. //!Returns false on error. Never throws @@ -173,11 +153,7 @@ inline const char *shared_memory_object::get_name() const 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_INTERPROCESS_RVALUE_REFERENCE) && !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); @@ -185,7 +161,9 @@ inline void shared_memory_object::swap(shared_memory_object &&other) } inline mapping_handle_t shared_memory_object::get_mapping_handle() const -{ return detail::mapping_handle_from_file_handle(m_handle); } +{ + return detail::mapping_handle_from_file_handle(m_handle); +} inline mode_t shared_memory_object::get_mode() const { return m_mode; } @@ -229,7 +207,6 @@ inline bool shared_memory_object::priv_open_or_create throw interprocess_exception(err); } - //detail::delete_file_on_reboot_if_possible(shmfile.c_str()); m_mode = mode; return true; } @@ -240,7 +217,7 @@ inline bool shared_memory_object::remove(const char *filename) //Make sure a temporary path is created for shared memory std::string shmfile; detail::tmp_filename(filename, shmfile); - return std::remove(shmfile.c_str()) == 0; + return detail::delete_file(shmfile.c_str()) == 0; } catch(...){ return false; @@ -355,14 +332,6 @@ inline void shared_memory_object::priv_close() #endif -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - ///@endcond //!A class that stores the name of a shared memory diff --git a/include/boost/interprocess/smart_ptr/deleter.hpp b/include/boost/interprocess/smart_ptr/deleter.hpp index 5909808..c223e4f 100644 --- a/include/boost/interprocess/smart_ptr/deleter.hpp +++ b/include/boost/interprocess/smart_ptr/deleter.hpp @@ -20,6 +20,7 @@ #include #include #include +#include //!\file //!Describes the functor to delete objects from the segment. @@ -35,11 +36,11 @@ template class deleter { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type segment_manager_pointer; segment_manager_pointer mp_mngr; diff --git a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp index 8e4db51..39a64da 100644 --- a/include/boost/interprocess/smart_ptr/detail/shared_count.hpp +++ b/include/boost/interprocess/smart_ptr/detail/shared_count.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -41,20 +42,20 @@ template class shared_count { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: typedef sp_counted_impl_pd counted_impl; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_impl_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_base_ptr; typedef typename VoidAllocator::template rebind ::other counted_impl_allocator; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; pointer m_px; @@ -212,14 +213,14 @@ template class weak_count { public: - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; private: typedef sp_counted_impl_pd counted_impl; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_impl_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type counted_base_ptr; pointer m_px; diff --git a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp index 51f44e9..9d799fa 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace boost { @@ -33,6 +34,34 @@ namespace interprocess { namespace detail { +//!A deleter for scoped_ptr that deallocates the memory +//!allocated for an object using a STL allocator. +template +struct scoped_ptr_dealloc_functor +{ + typedef typename Allocator::pointer pointer; + typedef detail::integral_constant::value> alloc_version; + typedef detail::integral_constant allocator_v1; + typedef detail::integral_constant 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()); } +}; + template class sp_counted_impl_pd : public sp_counted_base @@ -50,10 +79,10 @@ class sp_counted_impl_pd 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 + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; typedef typename D::pointer pointer; @@ -73,7 +102,7 @@ class sp_counted_impl_pd { return const_allocator_pointer(&static_cast(*this)); } void dispose() // nothrow - { static_cast(*this)(m_ptr); } + { static_cast(*this)(m_ptr); } void destroy() // nothrow { @@ -83,8 +112,8 @@ class sp_counted_impl_pd BOOST_ASSERT(a_copy == *this); this_pointer this_ptr (this); //Do it now! - scoped_ptr > deallocator(this_ptr, a_copy); + scoped_ptr< this_type, scoped_ptr_dealloc_functor > + deleter(this_ptr, a_copy); typedef typename this_allocator::value_type value_type; detail::get_pointer(this_ptr)->~value_type(); } diff --git a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp index 5ebac3c..86df285 100644 --- a/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/intrusive_ptr.hpp @@ -22,6 +22,7 @@ #include #include +#include #include // for std::less #include // for std::basic_ostream @@ -49,7 +50,7 @@ class intrusive_ptr { public: //!Provides the type of the internal stored pointer. - typedef typename detail::pointer_to_other::type pointer; + typedef typename boost::pointer_to_other::type pointer; //!Provides the type of the stored pointer. typedef T element_type; diff --git a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp index a21ba60..74fe1d6 100644 --- a/include/boost/interprocess/smart_ptr/scoped_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/scoped_ptr.hpp @@ -19,6 +19,7 @@ #include #include #include +#include //!\file //!Describes the smart pointer scoped_ptr @@ -54,7 +55,7 @@ class scoped_ptr typedef typename detail::pointer_type::type pointer; //!Provides the type of the internal stored pointer -// typedef typename detail::pointer_to_other +// typedef typename boost::pointer_to_other // ::type pointer; //!Constructs a scoped_ptr, storing a copy of p(which can be 0) and d. diff --git a/include/boost/interprocess/smart_ptr/shared_ptr.hpp b/include/boost/interprocess/smart_ptr/shared_ptr.hpp index ddf6f7d..5d650e2 100644 --- a/include/boost/interprocess/smart_ptr/shared_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/shared_ptr.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include // for std::swap #include // for std::less @@ -96,18 +97,20 @@ class shared_ptr typedef T element_type; typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; typedef typename detail::add_reference ::type reference; typedef typename detail::add_reference ::type const_reference; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_deleter_pointer; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type const_allocator_pointer; public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(shared_ptr) + //!Constructs an empty shared_ptr. //!Use_count() == 0 && get()== 0. shared_ptr() @@ -122,7 +125,7 @@ class shared_ptr { //Check that the pointer passed is of the same type that //the pointer the allocator defines or it's a raw pointer - typedef typename detail::pointer_to_other::type ParameterPointer; + typedef typename boost::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); detail::sp_enable_shared_from_this( m_pn, detail::get_pointer(p), detail::get_pointer(p) ); @@ -153,15 +156,9 @@ class shared_ptr //!Move-Constructs a shared_ptr that takes ownership of other resource and //!other is put in default-constructed state. //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - explicit shared_ptr(detail::moved_object other) - : m_pn() - { this->swap(other.get()); } - #else - explicit shared_ptr(shared_ptr &&other) + explicit shared_ptr(BOOST_INTERPROCESS_RV_REF(shared_ptr) other) : m_pn() { this->swap(other); } - #endif /// @cond template @@ -198,19 +195,11 @@ class shared_ptr //!Move-assignment. Equivalent to shared_ptr(other).swap(*this). //!Never throws - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - shared_ptr & operator=(detail::moved_object other) // never throws + shared_ptr & operator=(BOOST_INTERPROCESS_RV_REF(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); @@ -226,7 +215,7 @@ class shared_ptr { //Check that the pointer passed is of the same type that //the pointer the allocator defines or it's a raw pointer - typedef typename detail::pointer_to_other::type ParameterPointer; + typedef typename boost::pointer_to_other::type ParameterPointer; BOOST_STATIC_ASSERT((detail::is_same::value) || (detail::is_pointer::value)); this_type(p, a, d).swap(*this); @@ -371,26 +360,6 @@ inline typename managed_shared_ptr::type ); } - -/* -// get_deleter (experimental) -template -typename detail::pointer_to_other, Deleter>::type - get_deleter(shared_ptr const & p) -{ return static_cast(p._internal_get_deleter(typeid(Deleter))); } -*/ - -/// @cond - -//!This class has move constructor -template -struct is_movable > -{ - enum { value = true }; -}; - -/// @endcond - } // namespace interprocess /// @cond diff --git a/include/boost/interprocess/smart_ptr/unique_ptr.hpp b/include/boost/interprocess/smart_ptr/unique_ptr.hpp index 064af09..36a7507 100644 --- a/include/boost/interprocess/smart_ptr/unique_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/unique_ptr.hpp @@ -88,6 +88,8 @@ class unique_ptr /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(unique_ptr) + typedef T element_type; typedef D deleter_type; typedef typename detail::pointer_type::type pointer; @@ -142,7 +144,7 @@ class unique_ptr //! //!After the construction, u no longer owns a pointer. //![ Note: The deleter constructor can be implemented with - //!std::detail::forward_impl. -end note ] + //! boost::interprocess::forward. -end note ] //! //!Postconditions: get() == value u.get() had before the construction. //!get_deleter() returns a reference to the internally stored deleter which @@ -150,15 +152,9 @@ class unique_ptr //!deleter() and u.get_deleter() both reference the same lvalue deleter. //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr(detail::moved_object u) - : ptr_(u.get().release(), detail::move_impl(u.get().get_deleter())) + unique_ptr(BOOST_INTERPROCESS_RV_REF(unique_ptr) u) + : ptr_(u.release(), boost::interprocess::forward(u.get_deleter())) {} - #else - unique_ptr(unique_ptr &&u) - : ptr_(u.release(), detail::forward_impl(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 @@ -179,9 +175,8 @@ class unique_ptr //!was constructed from u.get_deleter(). //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) template - unique_ptr(detail::moved_object > u, + unique_ptr(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(unique_ptr, U, E) u, typename detail::enable_if_c< detail::is_convertible::pointer, pointer>::value && detail::is_convertible::value && @@ -192,24 +187,8 @@ class unique_ptr , nat >::type = nat()) - : ptr_(const_cast&>(u.get()).release(), detail::move_impl(u.get().get_deleter())) + : ptr_(const_cast&>(u).release(), boost::interprocess::move(u.get_deleter())) {} - #else - template - unique_ptr(unique_ptr && u, - typename detail::enable_if_c< - detail::is_convertible::pointer, pointer>::value && - detail::is_convertible::value && - ( - !detail::is_reference::value || - detail::is_same::value - ) - , - nat - >::type = nat()) - : ptr_(const_cast&>(u).release(), detail::forward_impl(u.get_deleter())) - {} - #endif //!Effects: If get() == 0 there are no effects. Otherwise get_deleter()(get()). //! @@ -230,21 +209,12 @@ class unique_ptr //!Returns: *this. //! //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr& operator=(detail::moved_object u) - { - reset(u.get().release()); - ptr_.second() = detail::move_impl(u.get().get_deleter()); - return *this; - } - #else - unique_ptr& operator=(unique_ptr && u) + unique_ptr& operator=(BOOST_INTERPROCESS_RV_REF(unique_ptr) u) { reset(u.release()); - ptr_.second() = detail::move_impl(u.get_deleter()); + ptr_.second() = boost::interprocess::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*. @@ -261,21 +231,12 @@ class unique_ptr //! //!Throws: nothing. template - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - unique_ptr& operator=(detail::moved_object > mu) - { - reset(mu.get().release()); - ptr_.second() = detail::move_impl(mu.get().get_deleter()); - return *this; - } - #else - unique_ptr& operator=(unique_ptr && u) + unique_ptr& operator=(BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(unique_ptr, U, E) u) { reset(u.release()); - ptr_.second() = detail::move_impl(u.get_deleter()); + ptr_.second() = boost::interprocess::move(u.get_deleter()); return *this; } - #endif //!Assigns from the literal 0 or NULL. //! @@ -359,23 +320,14 @@ class unique_ptr //!Effects: The stored pointers of this and u are exchanged. //! The stored deleters are swapped (unqualified). //!Throws: nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) void swap(unique_ptr& u) { ptr_.swap(u.ptr_); } - void swap(detail::moved_object mu) - { ptr_.swap(mu.get().ptr_); } - #else - void swap(unique_ptr&&u) - { ptr_.swap(u.ptr_); } - #endif - /// @cond private: boost::compressed_pair ptr_; - //This private constructor avoids moving from non-const lvalues - unique_ptr(const unique_ptr&); + unique_ptr(unique_ptr&); template unique_ptr(unique_ptr&); template unique_ptr(U&, typename detail::unique_ptr_error::type = 0); @@ -570,16 +522,6 @@ template inline bool operator>=(const unique_ptr& x, const unique_ptr& y) { return x.get() >= y.get(); } -/// @cond - -//!This class has move constructor -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - //!Returns the type of a unique pointer //!of type T with boost::interprocess::deleter deleter @@ -597,20 +539,11 @@ struct managed_unique_ptr //!with boost::interproces::deleter from a pointer //!of type T that has been allocated in the passed managed segment template -#ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE -inline typename detail::return_type - ::type - >::type -#else -typename managed_unique_ptr::type -#endif +inline typename managed_unique_ptr::type make_managed_unique_ptr(T *constructed_object, ManagedMemory &managed_memory) { - typename managed_unique_ptr::type to_return - ( constructed_object - , managed_memory.template get_deleter() - ); - return to_return; + return typename managed_unique_ptr::type + (constructed_object, managed_memory.template get_deleter()); } } //namespace interprocess{ diff --git a/include/boost/interprocess/smart_ptr/weak_ptr.hpp b/include/boost/interprocess/smart_ptr/weak_ptr.hpp index d69e4fe..4019f47 100644 --- a/include/boost/interprocess/smart_ptr/weak_ptr.hpp +++ b/include/boost/interprocess/smart_ptr/weak_ptr.hpp @@ -22,6 +22,7 @@ #include #include #include +#include //!\file //!Describes the smart pointer weak_ptr. @@ -53,7 +54,7 @@ class weak_ptr private: // Borland 5.5.1 specific workarounds typedef weak_ptr this_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; typedef typename detail::add_reference ::type reference; diff --git a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp index b40e3c7..32b236f 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_condition.hpp @@ -94,11 +94,11 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_enter_mut, abs_time); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } else{ InternalLock dummy(m_enter_mut); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } if(!lock) @@ -161,15 +161,18 @@ inline bool interprocess_condition::do_timed_wait(bool tout_enabled, InternalLock lock; if(tout_enabled){ InternalLock dummy(m_check_mut, abs_time); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } else{ InternalLock dummy(m_check_mut); - lock = detail::move_impl(dummy); + lock = boost::interprocess::move(dummy); } - if(!lock) - return false; + if(!lock){ + timed_out = true; + unlock_enter_mut = true; + break; + } //--------------------------------------------------------------- boost::uint32_t result = detail::atomic_cas32 (const_cast(&m_command), SLEEP, NOTIFY_ONE); diff --git a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp index c659e20..c6bc907 100644 --- a/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp @@ -39,8 +39,11 @@ inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){} inline void interprocess_recursive_mutex::lock() { - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)){ + typedef detail::OS_systemwide_thread_id_t handle_t; + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + if(detail::equal_systemwide_thread_id(thr_id , old_id)){ if((unsigned int)(m_nLockCount+1) == 0){ //Overflow, throw an exception throw interprocess_exception(); @@ -49,15 +52,18 @@ inline void interprocess_recursive_mutex::lock() } else{ m_mutex.lock(); - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; } } inline bool interprocess_recursive_mutex::try_lock() { - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it + typedef detail::OS_systemwide_thread_id_t handle_t; + handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + 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(); @@ -66,7 +72,7 @@ inline bool interprocess_recursive_mutex::try_lock() return true; } if(m_mutex.try_lock()){ - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } @@ -75,12 +81,15 @@ inline bool interprocess_recursive_mutex::try_lock() inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time) { + typedef detail::OS_systemwide_thread_id_t handle_t; if(abs_time == boost::posix_time::pos_infin){ this->lock(); return true; } - detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); - if(detail::equal_systemwide_thread_id(th_id, m_nOwner)) { // we own it + const handle_t thr_id(detail::get_current_systemwide_thread_id()); + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + 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(); @@ -89,7 +98,7 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt return true; } if(m_mutex.timed_lock(abs_time)){ - m_nOwner = th_id; + detail::systemwide_thread_id_copy(thr_id, m_nOwner); m_nLockCount = 1; return true; } @@ -98,10 +107,16 @@ inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::pt inline void interprocess_recursive_mutex::unlock() { - assert(detail::equal_systemwide_thread_id(detail::get_current_systemwide_thread_id(), m_nOwner)); + typedef detail::OS_systemwide_thread_id_t handle_t; + handle_t old_id; + detail::systemwide_thread_id_copy(m_nOwner, old_id); + const handle_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 = detail::get_invalid_systemwide_thread_id(); + const handle_t new_id(detail::get_invalid_systemwide_thread_id()); + detail::systemwide_thread_id_copy(new_id, m_nOwner); m_mutex.unlock(); } } diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 75a2693..d0f329d 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -29,19 +29,6 @@ namespace boost { namespace interprocess { -///@cond - -class file_lock; - -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - enum { value = true }; -}; - -///@endcond //!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 @@ -56,6 +43,7 @@ class file_lock file_lock &operator=(const file_lock &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(file_lock) //!Constructs an empty file mapping. //!Does not throw @@ -70,28 +58,16 @@ class file_lock //!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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_lock(detail::moved_object moved) - : m_file_hnd(file_handle_t(detail::invalid_file())) - { this->swap(moved.get()); } - #else - file_lock(file_lock &&moved) + file_lock(BOOST_INTERPROCESS_RV_REF(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - file_lock &operator=(detail::moved_object m_other) + file_lock &operator=(BOOST_INTERPROCESS_RV_REF(file_lock) moved) { - file_lock &moved = m_other.get(); - #else - file_lock &operator=(file_lock &&moved) - { - #endif - file_lock tmp(detail::move_impl(moved)); + file_lock tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -101,13 +77,7 @@ class file_lock //!Swaps two file_locks. //!Does not throw. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object mother) - { this->swap(mother.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; diff --git a/include/boost/interprocess/sync/interprocess_barrier.hpp b/include/boost/interprocess/sync/interprocess_barrier.hpp index 6ba5a66..3133668 100644 --- a/include/boost/interprocess/sync/interprocess_barrier.hpp +++ b/include/boost/interprocess/sync/interprocess_barrier.hpp @@ -26,6 +26,8 @@ #ifndef BOOST_INTERPROCESS_BARRIER_HPP #define BOOST_INTERPROCESS_BARRIER_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -48,6 +50,8 @@ # include +/// @endcond + namespace boost { namespace interprocess { diff --git a/include/boost/interprocess/sync/interprocess_condition.hpp b/include/boost/interprocess/sync/interprocess_condition.hpp index 5c4a123..73b9e67 100644 --- a/include/boost/interprocess/sync/interprocess_condition.hpp +++ b/include/boost/interprocess/sync/interprocess_condition.hpp @@ -15,6 +15,8 @@ # pragma once #endif +/// @cond + #include #include @@ -38,6 +40,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes process-shared variables interprocess_condition class diff --git a/include/boost/interprocess/sync/interprocess_mutex.hpp b/include/boost/interprocess/sync/interprocess_mutex.hpp index 5717725..8d7192b 100644 --- a/include/boost/interprocess/sync/interprocess_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_mutex.hpp @@ -27,6 +27,8 @@ #ifndef BOOST_INTERPROCESS_MUTEX_HPP #define BOOST_INTERPROCESS_MUTEX_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -48,6 +50,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes a mutex class that can be placed in memory shared by //!several processes. @@ -110,7 +114,7 @@ class interprocess_mutex volatile boost::uint32_t m_s; #elif defined(BOOST_INTERPROCESS_USE_POSIX) pthread_mutex_t m_mut; - #endif //#if (defined BOOST_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp index 13c0eb0..96369cc 100644 --- a/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp +++ b/include/boost/interprocess/sync/interprocess_recursive_mutex.hpp @@ -27,6 +27,8 @@ #ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP #define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -50,6 +52,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes @@ -106,10 +110,10 @@ class interprocess_recursive_mutex #if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION) interprocess_mutex m_mutex; unsigned int m_nLockCount; - detail::OS_systemwide_thread_id_t m_nOwner; + 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_WINDOWS) && !(defined BOOST_DISABLE_WIN32) + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) /// @endcond }; diff --git a/include/boost/interprocess/sync/interprocess_semaphore.hpp b/include/boost/interprocess/sync/interprocess_semaphore.hpp index b10eb89..0fe15ad 100644 --- a/include/boost/interprocess/sync/interprocess_semaphore.hpp +++ b/include/boost/interprocess/sync/interprocess_semaphore.hpp @@ -11,6 +11,8 @@ #ifndef BOOST_INTERPROCESS_SEMAPHORE_HPP #define BOOST_INTERPROCESS_SEMAPHORE_HPP +/// @cond + #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif @@ -22,7 +24,7 @@ #include #if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \ - (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_SEMAPHORES)) + (defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined(BOOST_INTERPROCESS_POSIX_NAMED_SEMAPHORES)) #include //O_CREAT, O_*... #include //close #include //std::string @@ -39,6 +41,8 @@ #define BOOST_INTERPROCESS_USE_GENERIC_EMULATION #endif +/// @endcond + //!\file //!Describes a interprocess_semaphore class for inter-process synchronization diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index 38ce368..417bee0 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -24,6 +26,7 @@ #include #include #include +#include #if defined BOOST_INTERPROCESS_NAMED_MUTEX_USES_POSIX_SEMAPHORES #include #include @@ -85,7 +88,7 @@ class named_condition //!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 + //!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 @@ -96,7 +99,7 @@ class named_condition template void wait(L& lock, Pr pred); - //!Releases the lock on the interprocess_mutex object associated with lock, blocks + //!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. @@ -148,7 +151,10 @@ class named_condition template void do_wait(Lock& lock) - { + { + //named_condition only works with named_mutex + BOOST_STATIC_ASSERT((detail::is_same::value == true)); + //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex()); lock_inverter inverted_lock(lock); @@ -163,6 +169,8 @@ class named_condition template 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::value == true)); //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex(), abs_time); if(!internal_lock) return false; diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp index 67b6998..f76212f 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -20,7 +20,7 @@ #include #ifdef SEM_FAILED -#define BOOST_INTERPROCESS_POSIX_SEM_FAILED SEM_FAILED +#define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(SEM_FAILED)) #else #define BOOST_INTERPROCESS_POSIX_SEM_FAILED (reinterpret_cast(-1)) #endif diff --git a/include/boost/interprocess/sync/scoped_lock.hpp b/include/boost/interprocess/sync/scoped_lock.hpp index 2bdfa3e..8dd1e57 100644 --- a/include/boost/interprocess/sync/scoped_lock.hpp +++ b/include/boost/interprocess/sync/scoped_lock.hpp @@ -22,8 +22,11 @@ #include #include +#include #include #include +#include +#include #include #include @@ -33,11 +36,6 @@ namespace boost { namespace interprocess { -template -class sharable_lock; - -template -class upgradable_lock; //!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 @@ -55,11 +53,13 @@ class scoped_lock /// @cond private: typedef scoped_lock this_type; - scoped_lock(scoped_lock const&); - scoped_lock& operator= (scoped_lock const&); + scoped_lock(scoped_lock&); + scoped_lock& operator= (scoped_lock&); typedef bool this_type::*unspecified_bool_type; /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(scoped_lock) + typedef Mutex mutex_type; //!Effects: Default constructs a scoped_lock. @@ -122,18 +122,12 @@ class scoped_lock //! 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: "detail::move_impl(lock);". This + //! can be moved with the expression: "boost::interprocess::move(lock);". This //! constructor does not alter the state of the mutex, only potentially //! who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(scop.get().owns()) - { mp_mutex = scop.get().release(); } - #else - scoped_lock(scoped_lock &&scop) + scoped_lock(BOOST_INTERPROCESS_RV_REF(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. @@ -144,22 +138,12 @@ class scoped_lock //! 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: "detail::move_impl(lock);" This constructor may block if + //! the expression: "boost::interprocess::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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &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 &&upgr) + template + explicit scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -169,7 +153,6 @@ class scoped_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If upgr.owns() then calls try_unlock_upgradable_and_lock() on the //!referenced mutex: @@ -185,25 +168,10 @@ class scoped_lock //! "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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr - ,try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &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 &&upgr - ,try_to_lock_type) + //! do so in a non-blocking manner. + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -216,7 +184,6 @@ class scoped_lock u_lock.release(); } } - #endif //!Effects: If upgr.owns() then calls timed_unlock_upgradable_and_lock(abs_time) //! on the referenced mutex: @@ -232,24 +199,9 @@ class scoped_lock //! "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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > upgr - ,boost::posix_time::ptime &abs_time) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &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 &&upgr - ,boost::posix_time::ptime &abs_time) + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr, boost::posix_time::ptime &abs_time + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -262,7 +214,6 @@ class scoped_lock u_lock.release(); } } - #endif //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock() on the //!referenced mutex. @@ -279,24 +230,9 @@ class scoped_lock //! 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock(detail::moved_object > shar - ,try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - sharable_lock &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 - scoped_lock(sharable_lock &&shar - ,try_to_lock_type) + template + scoped_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock) shar, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -309,7 +245,6 @@ class scoped_lock s_lock.release(); } } - #endif //!Effects: if (owns()) mp_mutex->unlock(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked.*/ @@ -325,17 +260,7 @@ class scoped_lock //! 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - scoped_lock &operator=(detail::moved_object 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) + scoped_lock &operator=(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop) { if(this->owns()) this->unlock(); @@ -343,7 +268,6 @@ class scoped_lock 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. @@ -429,19 +353,11 @@ class scoped_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(scoped_lock &&other) + void swap( scoped_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -450,16 +366,6 @@ class scoped_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/sync/sharable_lock.hpp b/include/boost/interprocess/sync/sharable_lock.hpp index ea97864..b7baf04 100644 --- a/include/boost/interprocess/sync/sharable_lock.hpp +++ b/include/boost/interprocess/sync/sharable_lock.hpp @@ -22,10 +22,12 @@ #include #include +#include #include #include +#include +#include #include -//Ig#include #include //!\file @@ -35,11 +37,6 @@ namespace boost { namespace interprocess { -template -class scoped_lock; - -template -class upgradable_lock; //!sharable_lock is meant to carry out the tasks for sharable-locking //!(such as read-locking), unlocking, try-sharable-locking and timed-sharable-locking @@ -57,13 +54,14 @@ class sharable_lock /// @cond private: typedef sharable_lock this_type; - sharable_lock(sharable_lock const&); - explicit sharable_lock(scoped_lock const&); + sharable_lock(sharable_lock&); + explicit sharable_lock(scoped_lock&); typedef bool this_type::*unspecified_bool_type; - sharable_lock& operator=(sharable_lock const&); - sharable_lock& operator=(scoped_lock const&); + sharable_lock& operator=(sharable_lock&); + sharable_lock& operator=(scoped_lock&); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(sharable_lock) //!Effects: Default constructs a sharable_lock. //!Postconditions: owns() == false and mutex() == 0. @@ -127,17 +125,11 @@ class sharable_lock //! 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: - //! "detail::move_impl(lock);". This constructor does not alter the state of the mutex, + //! "boost::interprocess::move(lock);". This constructor does not alter the state of the mutex, //! only potentially who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(upgr.get().owns()) - { mp_mutex = upgr.get().release(); } - #else - sharable_lock(sharable_lock &&upgr) + sharable_lock(BOOST_INTERPROCESS_RV_REF(sharable_lock) 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. @@ -147,20 +139,10 @@ class sharable_lock //!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: - //! "detail::move_impl(lock);".*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(false) - { - upgradable_lock &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 &&upgr) + //! "boost::interprocess::move(lock);".*/ + template + sharable_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { upgradable_lock &u_lock = upgr; @@ -170,7 +152,6 @@ class sharable_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If scop.owns() then calls unlock_and_lock_sharable() on the //! referenced mutex. @@ -181,20 +162,10 @@ class sharable_lock //! 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: - //! "detail::move_impl(lock);".*/ - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(false) - { - scoped_lock &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 &&scop) + //! "boost::interprocess::move(lock);". + template + sharable_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { scoped_lock &e_lock = scop; @@ -204,7 +175,6 @@ class sharable_lock } 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. @@ -221,17 +191,7 @@ class sharable_lock //!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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - sharable_lock &operator=(detail::moved_object > upgr) - { - if(this->owns()) - this->unlock(); - m_locked = upgr.get().owns(); - mp_mutex = upgr.get().release(); - return *this; - } - #else - sharable_lock &operator=(sharable_lock &&upgr) + sharable_lock &operator=(BOOST_INTERPROCESS_RV_REF(sharable_lock) upgr) { if(this->owns()) this->unlock(); @@ -239,7 +199,6 @@ class sharable_lock 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. @@ -328,19 +287,11 @@ class sharable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(sharable_lock &&other) + void swap(sharable_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -349,16 +300,6 @@ class sharable_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/sync/upgradable_lock.hpp b/include/boost/interprocess/sync/upgradable_lock.hpp index 386187d..fe3744b 100644 --- a/include/boost/interprocess/sync/upgradable_lock.hpp +++ b/include/boost/interprocess/sync/upgradable_lock.hpp @@ -22,7 +22,11 @@ #include #include +#include #include +#include +#include + #include #include #include @@ -34,12 +38,6 @@ namespace boost { namespace interprocess { -template -class scoped_lock; - -template -class sharable_lock; - //!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 @@ -57,13 +55,14 @@ class upgradable_lock /// @cond private: typedef upgradable_lock this_type; - upgradable_lock(upgradable_lock const&); - explicit upgradable_lock(scoped_lock const&); + upgradable_lock(upgradable_lock&); + explicit upgradable_lock(scoped_lock&); typedef bool this_type::*unspecified_bool_type; - upgradable_lock& operator=(upgradable_lock const&); - upgradable_lock& operator=(scoped_lock const&); + upgradable_lock& operator=(upgradable_lock&); + upgradable_lock& operator=(scoped_lock&); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(upgradable_lock) //!Effects: Default constructs a upgradable_lock. //!Postconditions: owns() == false and mutex() == 0. @@ -121,17 +120,11 @@ class 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: "detail::move_impl(lock);". This constructor does not alter the + //! expression: "boost::interprocess::move(lock);". This constructor does not alter the //! state of the mutex, only potentially who owns it. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock(detail::moved_object > upgr) - : mp_mutex(0), m_locked(upgr.get().owns()) - { mp_mutex = upgr.get().release(); } - #else - upgradable_lock(upgradable_lock &&upgr) + upgradable_lock(BOOST_INTERPROCESS_RV_REF(upgradable_lock) 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. @@ -141,20 +134,10 @@ class upgradable_lock //! 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: "detail::move_impl(lock);". - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock(detail::moved_object > scop) - : mp_mutex(0), m_locked(false) - { - scoped_lock &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 &&scop) + //! expression: "boost::interprocess::move(lock);". + template + upgradable_lock(BOOST_INTERPROCESS_RV_REF(scoped_lock) scop + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { scoped_lock &u_lock = scop; @@ -164,7 +147,6 @@ class upgradable_lock } mp_mutex = u_lock.release(); } - #endif //!Effects: If shar.owns() then calls try_unlock_sharable_and_lock_upgradable() //! on the referenced mutex. @@ -181,24 +163,9 @@ class upgradable_lock //! 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock( detail::moved_object > shar - , try_to_lock_type) - : mp_mutex(0), m_locked(false) - { - sharable_lock &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 &&shar - , try_to_lock_type) + template + upgradable_lock( BOOST_INTERPROCESS_RV_REF(sharable_lock) shar, try_to_lock_type + , typename detail::enable_if< detail::is_same >::type * = 0) : mp_mutex(0), m_locked(false) { sharable_lock &s_lock = shar; @@ -211,7 +178,6 @@ class upgradable_lock s_lock.release(); } } - #endif //!Effects: if (owns()) m_->unlock_upgradable(). //!Notes: The destructor behavior ensures that the mutex lock is not leaked. @@ -229,17 +195,7 @@ class upgradable_lock //! 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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - upgradable_lock &operator=(detail::moved_object > upgr) - { - if(this->owns()) - this->unlock(); - m_locked = upgr.get().owns(); - mp_mutex = upgr.get().release(); - return *this; - } - #else - upgradable_lock &operator=(upgradable_lock &&upgr) + upgradable_lock &operator=(BOOST_INTERPROCESS_RV_REF(upgradable_lock) upgr) { if(this->owns()) this->unlock(); @@ -247,7 +203,6 @@ class upgradable_lock 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. @@ -336,19 +291,11 @@ class upgradable_lock //!Effects: Swaps state with moved lock. //!Throws: Nothing. - #if !defined(BOOST_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - void swap(detail::moved_object > other) - { - std::swap(mp_mutex, other.get().mp_mutex); - std::swap(m_locked, other.get().m_locked); - } - #else - void swap(upgradable_lock &&other) + void swap(upgradable_lock &other) { std::swap(mp_mutex, other.mp_mutex); std::swap(m_locked, other.m_locked); } - #endif /// @cond private: @@ -357,16 +304,6 @@ class upgradable_lock /// @endcond }; -/// @cond - -//!This class is movable -template -struct is_movable > -{ - enum { value = true }; -}; -/// @endcond - } // namespace interprocess } // namespace boost diff --git a/include/boost/interprocess/windows_shared_memory.hpp b/include/boost/interprocess/windows_shared_memory.hpp index cd82e01..8b86710 100644 --- a/include/boost/interprocess/windows_shared_memory.hpp +++ b/include/boost/interprocess/windows_shared_memory.hpp @@ -15,7 +15,7 @@ #include #include -#if !defined(BOOST_WINDOWS) || defined(BOOST_DISABLE_WIN32) +#if !defined(BOOST_INTERPROCESS_WINDOWS) #error "This header can only be used in Windows operating systems" #endif @@ -51,11 +51,12 @@ class windows_shared_memory { /// @cond //Non-copyable and non-assignable - windows_shared_memory(const windows_shared_memory &); - windows_shared_memory &operator=(const windows_shared_memory &); + windows_shared_memory(windows_shared_memory &); + windows_shared_memory &operator=(windows_shared_memory &); /// @endcond public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(windows_shared_memory) //!Default constructor. //!Represents an empty windows_shared_memory. @@ -81,26 +82,15 @@ class windows_shared_memory //!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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - windows_shared_memory - (detail::moved_object moved) - { this->swap(moved.get()); } - #else - windows_shared_memory(windows_shared_memory &&moved) + windows_shared_memory(BOOST_INTERPROCESS_RV_REF(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_INTERPROCESS_RVALUE_REFERENCE) && !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) - windows_shared_memory &operator= - (detail::moved_object moved) - #else - windows_shared_memory &operator=(windows_shared_memory &&moved) - #endif + windows_shared_memory &operator=(BOOST_INTERPROCESS_RV_REF(windows_shared_memory) moved) { - windows_shared_memory tmp(detail::move_impl(moved)); + windows_shared_memory tmp(boost::interprocess::move(moved)); this->swap(tmp); return *this; } @@ -232,14 +222,6 @@ inline void windows_shared_memory::priv_close() } } -//!Trait class to detect if a type is -//!movable -template<> -struct is_movable -{ - static const bool value = true; -}; - ///@endcond } //namespace interprocess { diff --git a/proj/to-do.txt b/proj/to-do.txt index 3ac56ac..623bd5d 100644 --- a/proj/to-do.txt +++ b/proj/to-do.txt @@ -1,5 +1,3 @@ --> change rvalue reference signatures in all containers - -> add private_read_only to mapped_region to support MAP_PRIVATE plus PROT_READ -> add contiguous_elements option to burst allocation @@ -43,28 +41,26 @@ -> barrier_test fails on MacOS X on PowerPC. -->use virtual functions to minimize template explosion in managed classes +-> use virtual functions to minimize template explosion in managed classes -->Insertions with InpIt are not tested in containers +-> Insertions with InpIt are not tested in containers -->Run tests with rvalue reference compilers with no variadic insertions +-> Run tests with rvalue reference compilers with no variadic insertions -->find a way to pass security attributes to shared memory +-> find a way to pass security attributes to shared memory -->Explain in docs that shared memory can't be used between different users in windows +-> Explain in docs that shared memory can't be used between different users in windows -> Implement vector with memcpy/memmove for trivially copyable types. --> Update all swap() calls to work with rvalues in all classes - --> correct swap overloads for the documentation so that just appears a single rvalue swap - --> correct splice()/merg overloads for the documentation so that just appears a single rvalue splice - -> flat_xxx constructors are not documented -> operator >> eta antzekoek moved_value behar dute --> make file_lock movable - -> Add cmath workaround for Boost < 1.37 + +-> rvalue reference enabled compilers are not optimized with is_movable and move_iterator + +-> Add allocator test template that test all new functions (allocate_many, etc.) + +-> MacOS shm_open is non-conformant. Is there a way to know the size of a shared memory object? diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index ed25a07..dfbe26e 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -103,18 +103,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_cont", "doc_cont.vcproj ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contA", "doc_contA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_contB", "doc_contB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792651}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory", "doc_shared_memory.vcproj", "{58CCE183-6032-12FE-4FC7-83A79F760B61}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_test", "unique_ptr_test.vcproj", "{571C3383-6092-A877-1238-B3786BAE7605}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -139,14 +127,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iunordered_set_index_alloca ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory2", "doc_shared_memory2.vcproj", "{58CE1D83-F31E-4FD7-6132-8A79F6307B61}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping2", "doc_file_mapping2.vcproj", "{5CE19883-F413-7EFD-6342-B79639F7B611}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_file_mapping", "doc_file_mapping.vcproj", "{58DE18C3-3261-2F3E-FD47-83760B9FA761}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -223,10 +203,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory", ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_windows_shared_memory2", "doc_windows_shared_memory2.vcproj", "{5E1D6C83-31DE-4F6F-6132-87A9FB663041}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_node_pool_test", "adaptive_node_pool_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -295,26 +271,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_intrusive", "doc_intrus ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageA", "doc_ipc_messageA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_messageB", "doc_ipc_messageB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792648}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_managed_mapped_file", "doc_managed_mapped_file.vcproj", "{58CCE183-5091-48FE-A4FC-BA0D3A792446}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocA", "doc_named_allocA.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_allocB", "doc_named_allocB.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792644}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_offset_ptr", "doc_offset_ptr.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792643}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -463,11 +423,33 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_construct_test", "nam ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stable_vector_test", "stable_vector_test.vcproj", "{5E11C8D3-FA52-760A-84FE-943A6BA05A21}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_spawn_vector", "doc_spawn_vector.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792652}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_ipc_message", "doc_ipc_message.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792649}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_named_alloc", "doc_named_alloc.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792645}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_shared_memory", "doc_shared_memory.vcproj", "{58CCE183-6032-12FE-4FC7-83A79F760B61}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Release = Release EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.ActiveCfg = Debug|Win32 {5CE18C83-6025-36FE-A4F7-BA09176D3A11}.Debug.Build.0 = Debug|Win32 @@ -573,18 +555,6 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792653}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792651}.Release.Build.0 = Release|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.Build.0 = Debug|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.ActiveCfg = Release|Win32 - {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.Build.0 = Release|Win32 {571C3383-6092-A877-1238-B3786BAE7605}.Debug.ActiveCfg = Debug|Win32 {571C3383-6092-A877-1238-B3786BAE7605}.Debug.Build.0 = Debug|Win32 {571C3383-6092-A877-1238-B3786BAE7605}.Release.ActiveCfg = Release|Win32 @@ -609,14 +579,6 @@ Global {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Debug.Build.0 = Debug|Win32 {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.ActiveCfg = Release|Win32 {5BD1C7C3-3F7F-6972-84BE-B731D9236035}.Release.Build.0 = Release|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.ActiveCfg = Debug|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Debug.Build.0 = Debug|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.ActiveCfg = Release|Win32 - {58CE1D83-F31E-4FD7-6132-8A79F6307B61}.Release.Build.0 = Release|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.ActiveCfg = Debug|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Debug.Build.0 = Debug|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.ActiveCfg = Release|Win32 - {5CE19883-F413-7EFD-6342-B79639F7B611}.Release.Build.0 = Release|Win32 {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.ActiveCfg = Debug|Win32 {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Debug.Build.0 = Debug|Win32 {58DE18C3-3261-2F3E-FD47-83760B9FA761}.Release.ActiveCfg = Release|Win32 @@ -693,10 +655,6 @@ Global {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Debug.Build.0 = Debug|Win32 {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.ActiveCfg = Release|Win32 {5E17C9C3-1362-2E1E-C84F-8A76B6739F21}.Release.Build.0 = Release|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.ActiveCfg = Debug|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Debug.Build.0 = Debug|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.ActiveCfg = Release|Win32 - {5E1D6C83-31DE-4F6F-6132-87A9FB663041}.Release.Build.0 = Release|Win32 {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 @@ -765,26 +723,10 @@ Global {5E18CC83-6092-48FE-A677-B832A0D3A650}.Debug.Build.0 = Debug|Win32 {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.ActiveCfg = Release|Win32 {5E18CC83-6092-48FE-A677-B832A0D3A650}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792648}.Release.Build.0 = Release|Win32 {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.ActiveCfg = Debug|Win32 {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Debug.Build.0 = Debug|Win32 {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.ActiveCfg = Release|Win32 {58CCE183-5091-48FE-A4FC-BA0D3A792446}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792644}.Release.Build.0 = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.ActiveCfg = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792643}.Release.ActiveCfg = Release|Win32 @@ -933,6 +875,26 @@ Global {5183C8CE-F2E1-3620-237A-B765C9896390}.Debug.Build.0 = Debug|Win32 {5183C8CE-F2E1-3620-237A-B765C9896390}.Release.ActiveCfg = Release|Win32 {5183C8CE-F2E1-3620-237A-B765C9896390}.Release.Build.0 = Release|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.ActiveCfg = Debug|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Debug.Build.0 = Debug|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.ActiveCfg = Release|Win32 + {5E11C8D3-FA52-760A-84FE-943A6BA05A21}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792652}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792649}.Release.Build.0 = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Debug.Build.0 = Debug|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.ActiveCfg = Release|Win32 + {58CCE183-6092-48FE-A4F7-BA0D3A792645}.Release.Build.0 = Release|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.ActiveCfg = Debug|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Debug.Build.0 = Debug|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.ActiveCfg = Release|Win32 + {58CCE183-6032-12FE-4FC7-83A79F760B61}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/adaptive_node_pool_test.vcproj b/proj/vc7ide/adaptive_node_pool_test.vcproj index e67a6c8..5ede3e9 100644 --- a/proj/vc7ide/adaptive_node_pool_test.vcproj +++ b/proj/vc7ide/adaptive_node_pool_test.vcproj @@ -21,6 +21,7 @@ Optimization="0" AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" + GeneratePreprocessedFile="0" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" diff --git a/proj/vc7ide/doc_adaptive_pool.vcproj b/proj/vc7ide/doc_adaptive_pool.vcproj index 1961a35..39d77ad 100644 --- a/proj/vc7ide/doc_adaptive_pool.vcproj +++ b/proj/vc7ide/doc_adaptive_pool.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_adaptive_pool.cpp"> - - diff --git a/proj/vc7ide/doc_allocator.vcproj b/proj/vc7ide/doc_allocator.vcproj index f87a509..a59fe9f 100644 --- a/proj/vc7ide/doc_allocator.vcproj +++ b/proj/vc7ide/doc_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_conditionA.vcproj b/proj/vc7ide/doc_anonymous_conditionA.vcproj index f572274..f1e0831 100644 --- a/proj/vc7ide/doc_anonymous_conditionA.vcproj +++ b/proj/vc7ide/doc_anonymous_conditionA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BE2BEF1-C8A9-53BC-1A02-952FFA2D75A2}"> + RelativePath="..\..\example\comp_doc_anonymous_conditionA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_conditionB.vcproj b/proj/vc7ide/doc_anonymous_conditionB.vcproj index 7005b51..e4a4028 100644 --- a/proj/vc7ide/doc_anonymous_conditionB.vcproj +++ b/proj/vc7ide/doc_anonymous_conditionB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4B2EF711-14CA-5347-F025-7F75AF2D22A2}"> + RelativePath="..\..\example\comp_doc_anonymous_conditionB.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_mutexA.vcproj b/proj/vc7ide/doc_anonymous_mutexA.vcproj index f97c3ba..e562362 100644 --- a/proj/vc7ide/doc_anonymous_mutexA.vcproj +++ b/proj/vc7ide/doc_anonymous_mutexA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BE712F1-C98A-4537-12A0-72D752FFA2A2}"> + RelativePath="..\..\example\comp_doc_anonymous_mutexA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_mutexB.vcproj b/proj/vc7ide/doc_anonymous_mutexB.vcproj index f696723..bde78a6 100644 --- a/proj/vc7ide/doc_anonymous_mutexB.vcproj +++ b/proj/vc7ide/doc_anonymous_mutexB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4B712EF1-98CA-4537-A012-72D2FF75A2A2}"> + RelativePath="..\..\example\comp_doc_anonymous_mutexB.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_semaphoreA.vcproj b/proj/vc7ide/doc_anonymous_semaphoreA.vcproj index 21d58f3..07786c5 100644 --- a/proj/vc7ide/doc_anonymous_semaphoreA.vcproj +++ b/proj/vc7ide/doc_anonymous_semaphoreA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BEFCAB1-8AC0-3B5C-AF1B-9522D75AFFA2}"> + RelativePath="..\..\example\comp_doc_anonymous_semaphoreA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_semaphoreB.vcproj b/proj/vc7ide/doc_anonymous_semaphoreB.vcproj index 30b1dd4..3d39e30 100644 --- a/proj/vc7ide/doc_anonymous_semaphoreB.vcproj +++ b/proj/vc7ide/doc_anonymous_semaphoreB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BCDF711-5717-14CA-F250-F2D8F75A22A2}"> + RelativePath="..\..\example\comp_doc_anonymous_semaphoreB.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_shared_memory.vcproj b/proj/vc7ide/doc_anonymous_shared_memory.vcproj index cd5d7a4..04cbf00 100644 --- a/proj/vc7ide/doc_anonymous_shared_memory.vcproj +++ b/proj/vc7ide/doc_anonymous_shared_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_anonymous_shared_memory.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj b/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj index 2df71b6..af3aca3 100644 --- a/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj +++ b/proj/vc7ide/doc_anonymous_upgradable_mutexA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4BF1E712-4FB5-08CB-2A11-752DCD72F2B2}"> + RelativePath="..\..\example\comp_doc_anonymous_upgradable_mutexA.cpp"> - - diff --git a/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj b/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj index e5b0250..5204ec5 100644 --- a/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj +++ b/proj/vc7ide/doc_anonymous_upgradable_mutexB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4B712E2E-5347-A352-8C9F-FF72D27982A2}"> + RelativePath="..\..\example\comp_doc_anonymous_upgradable_mutexB.cpp"> - - diff --git a/proj/vc7ide/doc_bufferstream.vcproj b/proj/vc7ide/doc_bufferstream.vcproj index 1430223..129e265 100644 --- a/proj/vc7ide/doc_bufferstream.vcproj +++ b/proj/vc7ide/doc_bufferstream.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_bufferstream.cpp"> - - diff --git a/proj/vc7ide/doc_cached_adaptive_pool.vcproj b/proj/vc7ide/doc_cached_adaptive_pool.vcproj index 86c6b9d..5164354 100644 --- a/proj/vc7ide/doc_cached_adaptive_pool.vcproj +++ b/proj/vc7ide/doc_cached_adaptive_pool.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_cached_adaptive_pool.cpp"> - - diff --git a/proj/vc7ide/doc_cached_node_allocator.vcproj b/proj/vc7ide/doc_cached_node_allocator.vcproj index 3824942..e2f4655 100644 --- a/proj/vc7ide/doc_cached_node_allocator.vcproj +++ b/proj/vc7ide/doc_cached_node_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_cached_node_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_cont.vcproj b/proj/vc7ide/doc_cont.vcproj index 9d9126c..f19202d 100644 --- a/proj/vc7ide/doc_cont.vcproj +++ b/proj/vc7ide/doc_cont.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_cont.cpp"> - - diff --git a/proj/vc7ide/doc_contB.vcproj b/proj/vc7ide/doc_contB.vcproj index 85807ca..9f545a6 100644 --- a/proj/vc7ide/doc_contB.vcproj +++ b/proj/vc7ide/doc_contB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + RelativePath="..\..\example\comp_doc_contB.cpp"> - - diff --git a/proj/vc7ide/doc_file_mapping.vcproj b/proj/vc7ide/doc_file_mapping.vcproj index b71b7cb..215ca40 100644 --- a/proj/vc7ide/doc_file_mapping.vcproj +++ b/proj/vc7ide/doc_file_mapping.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_file_mapping.cpp"> - - diff --git a/proj/vc7ide/doc_file_mapping2.vcproj b/proj/vc7ide/doc_file_mapping2.vcproj deleted file mode 100644 index 9071a47..0000000 --- a/proj/vc7ide/doc_file_mapping2.vcproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/proj/vc7ide/doc_intrusive.vcproj b/proj/vc7ide/doc_intrusive.vcproj index f1cbee5..757b60c 100644 --- a/proj/vc7ide/doc_intrusive.vcproj +++ b/proj/vc7ide/doc_intrusive.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_intrusive.cpp"> - - diff --git a/proj/vc7ide/doc_ipc_messageA.vcproj b/proj/vc7ide/doc_ipc_message.vcproj similarity index 87% rename from proj/vc7ide/doc_ipc_messageA.vcproj rename to proj/vc7ide/doc_ipc_message.vcproj index d3ee38a..5e2208a 100644 --- a/proj/vc7ide/doc_ipc_messageA.vcproj +++ b/proj/vc7ide/doc_ipc_message.vcproj @@ -2,7 +2,7 @@ @@ -13,7 +13,7 @@ @@ -67,7 +67,7 @@ + RelativePath="..\..\example\doc_ipc_message.cpp"> - - diff --git a/proj/vc7ide/doc_managed_aligned_allocation.vcproj b/proj/vc7ide/doc_managed_aligned_allocation.vcproj index 0be1539..455d93f 100644 --- a/proj/vc7ide/doc_managed_aligned_allocation.vcproj +++ b/proj/vc7ide/doc_managed_aligned_allocation.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_aligned_allocation.cpp"> - - diff --git a/proj/vc7ide/doc_managed_allocation_command.vcproj b/proj/vc7ide/doc_managed_allocation_command.vcproj index f9ff6f1..367eb81 100644 --- a/proj/vc7ide/doc_managed_allocation_command.vcproj +++ b/proj/vc7ide/doc_managed_allocation_command.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_allocation_command.cpp"> - - diff --git a/proj/vc7ide/doc_managed_construction_info.vcproj b/proj/vc7ide/doc_managed_construction_info.vcproj index 36f749f..2ff84df6 100644 --- a/proj/vc7ide/doc_managed_construction_info.vcproj +++ b/proj/vc7ide/doc_managed_construction_info.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_construction_info.cpp"> - - diff --git a/proj/vc7ide/doc_managed_grow.vcproj b/proj/vc7ide/doc_managed_grow.vcproj index 8355e3b..a516ede 100644 --- a/proj/vc7ide/doc_managed_grow.vcproj +++ b/proj/vc7ide/doc_managed_grow.vcproj @@ -128,11 +128,6 @@ RelativePath="..\..\example\doc_managed_grow.cpp"> - - diff --git a/proj/vc7ide/doc_managed_heap_memory.vcproj b/proj/vc7ide/doc_managed_heap_memory.vcproj index fb63372..046ce13 100644 --- a/proj/vc7ide/doc_managed_heap_memory.vcproj +++ b/proj/vc7ide/doc_managed_heap_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_heap_memory.cpp"> - - diff --git a/proj/vc7ide/doc_managed_mapped_file.vcproj b/proj/vc7ide/doc_managed_mapped_file.vcproj index 31a7c39..d0588af 100644 --- a/proj/vc7ide/doc_managed_mapped_file.vcproj +++ b/proj/vc7ide/doc_managed_mapped_file.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_mapped_file.cpp"> - - diff --git a/proj/vc7ide/doc_managed_multiple_allocation.vcproj b/proj/vc7ide/doc_managed_multiple_allocation.vcproj index fc35fde..69b2afc 100644 --- a/proj/vc7ide/doc_managed_multiple_allocation.vcproj +++ b/proj/vc7ide/doc_managed_multiple_allocation.vcproj @@ -128,11 +128,6 @@ RelativePath="..\..\example\doc_managed_multiple_allocation.cpp"> - - diff --git a/proj/vc7ide/doc_managed_raw_allocation.vcproj b/proj/vc7ide/doc_managed_raw_allocation.vcproj index 1269082..f537e1f 100644 --- a/proj/vc7ide/doc_managed_raw_allocation.vcproj +++ b/proj/vc7ide/doc_managed_raw_allocation.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_managed_raw_allocation.cpp"> - - diff --git a/proj/vc7ide/doc_map.vcproj b/proj/vc7ide/doc_map.vcproj index 7c49867..9ac8ca3 100644 --- a/proj/vc7ide/doc_map.vcproj +++ b/proj/vc7ide/doc_map.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_map.cpp"> - - diff --git a/proj/vc7ide/doc_message_queueA.vcproj b/proj/vc7ide/doc_message_queueA.vcproj index daf452c..f05e0fa 100644 --- a/proj/vc7ide/doc_message_queueA.vcproj +++ b/proj/vc7ide/doc_message_queueA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{42FBE7AD-C8A9-12A0-5347-72FFA25175A2}"> + RelativePath="..\..\example\comp_doc_message_queueA.cpp"> - - diff --git a/proj/vc7ide/doc_message_queueB.vcproj b/proj/vc7ide/doc_message_queueB.vcproj index 974b1a5..773af14 100644 --- a/proj/vc7ide/doc_message_queueB.vcproj +++ b/proj/vc7ide/doc_message_queueB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{412EC7F1-45A7-98CA-A012-7952A2D2AFF2}"> + RelativePath="..\..\example\comp_doc_message_queueB.cpp"> - - diff --git a/proj/vc7ide/doc_move_containers.vcproj b/proj/vc7ide/doc_move_containers.vcproj index 30c5981..5d91966 100644 --- a/proj/vc7ide/doc_move_containers.vcproj +++ b/proj/vc7ide/doc_move_containers.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_move_containers.cpp"> - - diff --git a/proj/vc7ide/doc_named_allocA.vcproj b/proj/vc7ide/doc_named_alloc.vcproj similarity index 87% rename from proj/vc7ide/doc_named_allocA.vcproj rename to proj/vc7ide/doc_named_alloc.vcproj index 3954d12..68b97f9 100644 --- a/proj/vc7ide/doc_named_allocA.vcproj +++ b/proj/vc7ide/doc_named_alloc.vcproj @@ -2,7 +2,7 @@ @@ -13,7 +13,7 @@ @@ -67,7 +67,7 @@ + RelativePath="..\..\example\doc_named_alloc.cpp"> - - diff --git a/proj/vc7ide/doc_named_conditionA.vcproj b/proj/vc7ide/doc_named_conditionA.vcproj index 73fb140..909275b 100644 --- a/proj/vc7ide/doc_named_conditionA.vcproj +++ b/proj/vc7ide/doc_named_conditionA.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{AB2F71E1-2E95-7FA3-2A10-741FA12A22F2}"> + RelativePath="..\..\example\comp_doc_named_conditionA.cpp"> - - diff --git a/proj/vc7ide/doc_named_conditionB.vcproj b/proj/vc7ide/doc_named_conditionB.vcproj index cb2bdd7..1ac14ae 100644 --- a/proj/vc7ide/doc_named_conditionB.vcproj +++ b/proj/vc7ide/doc_named_conditionB.vcproj @@ -124,14 +124,9 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{AB712FE1-92E5-7543-12A0-74522FFA12A2}"> + RelativePath="..\..\example\comp_doc_named_conditionB.cpp"> - - diff --git a/proj/vc7ide/doc_named_mutex.vcproj b/proj/vc7ide/doc_named_mutex.vcproj index 9aa0582..874a7a1 100644 --- a/proj/vc7ide/doc_named_mutex.vcproj +++ b/proj/vc7ide/doc_named_mutex.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_named_mutex.cpp"> - - diff --git a/proj/vc7ide/doc_node_allocator.vcproj b/proj/vc7ide/doc_node_allocator.vcproj index 03c0a52..269ca8a 100644 --- a/proj/vc7ide/doc_node_allocator.vcproj +++ b/proj/vc7ide/doc_node_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_node_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_offset_ptr.vcproj b/proj/vc7ide/doc_offset_ptr.vcproj index 4768fa8..58d1ffd 100644 --- a/proj/vc7ide/doc_offset_ptr.vcproj +++ b/proj/vc7ide/doc_offset_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_offset_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_private_adaptive_pool.vcproj b/proj/vc7ide/doc_private_adaptive_pool.vcproj index ad9eda0..7a50b91 100644 --- a/proj/vc7ide/doc_private_adaptive_pool.vcproj +++ b/proj/vc7ide/doc_private_adaptive_pool.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_private_adaptive_pool.cpp"> - - diff --git a/proj/vc7ide/doc_private_node_allocator.vcproj b/proj/vc7ide/doc_private_node_allocator.vcproj index b60943b..22ca032 100644 --- a/proj/vc7ide/doc_private_node_allocator.vcproj +++ b/proj/vc7ide/doc_private_node_allocator.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_private_node_allocator.cpp"> - - diff --git a/proj/vc7ide/doc_scoped_ptr.vcproj b/proj/vc7ide/doc_scoped_ptr.vcproj index ec2dc09..e6a62dd 100644 --- a/proj/vc7ide/doc_scoped_ptr.vcproj +++ b/proj/vc7ide/doc_scoped_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_scoped_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_shared_memory.vcproj b/proj/vc7ide/doc_shared_memory.vcproj index f085b5e..66a1de0 100644 --- a/proj/vc7ide/doc_shared_memory.vcproj +++ b/proj/vc7ide/doc_shared_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_shared_memory.cpp"> - - diff --git a/proj/vc7ide/doc_shared_ptr.vcproj b/proj/vc7ide/doc_shared_ptr.vcproj index bf0ecd7..160d883 100644 --- a/proj/vc7ide/doc_shared_ptr.vcproj +++ b/proj/vc7ide/doc_shared_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_shared_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_shared_ptr_explicit.vcproj b/proj/vc7ide/doc_shared_ptr_explicit.vcproj index c10bbdb..77480ad 100644 --- a/proj/vc7ide/doc_shared_ptr_explicit.vcproj +++ b/proj/vc7ide/doc_shared_ptr_explicit.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_shared_ptr_explicit.cpp"> - - diff --git a/proj/vc7ide/doc_named_allocB.vcproj b/proj/vc7ide/doc_spawn_vector.vcproj similarity index 85% rename from proj/vc7ide/doc_named_allocB.vcproj rename to proj/vc7ide/doc_spawn_vector.vcproj index 09f43f8..a6a6726 100644 --- a/proj/vc7ide/doc_named_allocB.vcproj +++ b/proj/vc7ide/doc_spawn_vector.vcproj @@ -2,8 +2,8 @@ @@ -67,7 +67,7 @@ + RelativePath="..\..\example\doc_spawn_vector.cpp"> - - diff --git a/proj/vc7ide/doc_unique_ptr.vcproj b/proj/vc7ide/doc_unique_ptr.vcproj index f2cc7b5..39dd224 100644 --- a/proj/vc7ide/doc_unique_ptr.vcproj +++ b/proj/vc7ide/doc_unique_ptr.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_unique_ptr.cpp"> - - diff --git a/proj/vc7ide/doc_vectorstream.vcproj b/proj/vc7ide/doc_vectorstream.vcproj index 9e2b8fc..9504650 100644 --- a/proj/vc7ide/doc_vectorstream.vcproj +++ b/proj/vc7ide/doc_vectorstream.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_vectorstream.cpp"> - - diff --git a/proj/vc7ide/doc_where_allocate.vcproj b/proj/vc7ide/doc_where_allocate.vcproj index 9a255f5..6bd2493 100644 --- a/proj/vc7ide/doc_where_allocate.vcproj +++ b/proj/vc7ide/doc_where_allocate.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_where_allocate.cpp"> - - diff --git a/proj/vc7ide/doc_windows_shared_memory.vcproj b/proj/vc7ide/doc_windows_shared_memory.vcproj index 990cb2c..dd6357d 100644 --- a/proj/vc7ide/doc_windows_shared_memory.vcproj +++ b/proj/vc7ide/doc_windows_shared_memory.vcproj @@ -127,11 +127,6 @@ RelativePath="..\..\example\doc_windows_shared_memory.cpp"> - - diff --git a/proj/vc7ide/doc_windows_shared_memory2.vcproj b/proj/vc7ide/doc_windows_shared_memory2.vcproj index 011cfbf..2be8642 100644 --- a/proj/vc7ide/doc_windows_shared_memory2.vcproj +++ b/proj/vc7ide/doc_windows_shared_memory2.vcproj @@ -39,7 +39,7 @@ LinkIncremental="1" AdditionalLibraryDirectories="../../../../stage/lib" GenerateDebugInformation="TRUE" - ProgramDatabaseFile="$(OutDir)/doc_windows_shared_memory2.pdb" + ProgramDatabaseFile="$(OutDir)/doc_windows_shared_memoryB.pdb" SubSystem="1" TargetMachine="1" FixedBaseAddress="1"/> @@ -86,7 +86,7 @@ + RelativePath="..\..\example\comp_doc_windows_shared_memoryB.cpp"> - - diff --git a/proj/vc7ide/interprocesslib.vcproj b/proj/vc7ide/interprocesslib.vcproj index abf9115..83dd2cf 100644 --- a/proj/vc7ide/interprocesslib.vcproj +++ b/proj/vc7ide/interprocesslib.vcproj @@ -119,25 +119,15 @@ + + - - - - - - - - + + @@ -361,18 +354,9 @@ - - - - - - @@ -385,9 +369,6 @@ - - @@ -397,9 +378,6 @@ - - @@ -418,9 +396,6 @@ - - @@ -454,6 +429,9 @@ + + @@ -463,9 +441,6 @@ - - diff --git a/proj/vc7ide/shared_memory_mappable_test.vcproj b/proj/vc7ide/shared_memory_mappable_test.vcproj index 2954e48..da82e29 100644 --- a/proj/vc7ide/shared_memory_mappable_test.vcproj +++ b/proj/vc7ide/shared_memory_mappable_test.vcproj @@ -22,9 +22,11 @@ AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" GeneratePreprocessedFile="0" + KeepComments="FALSE" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="FALSE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/doc_ipc_messageB.vcproj b/proj/vc7ide/stable_vector_test.vcproj similarity index 83% rename from proj/vc7ide/doc_ipc_messageB.vcproj rename to proj/vc7ide/stable_vector_test.vcproj index b3317e9..fdc2192 100644 --- a/proj/vc7ide/doc_ipc_messageB.vcproj +++ b/proj/vc7ide/stable_vector_test.vcproj @@ -2,8 +2,8 @@ @@ -67,7 +67,7 @@ + UniqueIdentifier="{37BC807F-2451-A306-7AC5-7A35A32A22DF}"> + RelativePath="..\..\test\stable_vector_test.cpp"> - - diff --git a/proj/vc7ide/string_test.vcproj b/proj/vc7ide/string_test.vcproj index 5bd6b2d..77f6f35 100644 --- a/proj/vc7ide/string_test.vcproj +++ b/proj/vc7ide/string_test.vcproj @@ -21,6 +21,7 @@ Optimization="0" AdditionalIncludeDirectories="../../../.." PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB" + GeneratePreprocessedFile="0" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" diff --git a/proj/vc7ide/windows_shared_memory_mapping_test.vcproj b/proj/vc7ide/windows_shared_memory_mapping_test.vcproj index 67d5880..e488012 100644 --- a/proj/vc7ide/windows_shared_memory_mapping_test.vcproj +++ b/proj/vc7ide/windows_shared_memory_mapping_test.vcproj @@ -13,7 +13,7 @@ @@ -67,7 +67,7 @@ #include "node_pool_test.hpp" #include diff --git a/test/allocator_v1.hpp b/test/allocator_v1.hpp index d52a039..3974046 100644 --- a/test/allocator_v1.hpp +++ b/test/allocator_v1.hpp @@ -18,10 +18,12 @@ #include #include +#include + #include -#include +#include #include -#include +#include #include #include #include @@ -49,10 +51,10 @@ class allocator_v1 typedef typename segment_manager::void_pointer aux_pointer_t; typedef typename - detail::pointer_to_other + boost::pointer_to_other ::type cvoid_ptr; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type alloc_ptr_t; template @@ -64,9 +66,9 @@ class allocator_v1 public: typedef T value_type; - typedef typename detail::pointer_to_other + typedef typename boost::pointer_to_other ::type pointer; - typedef typename detail:: + typedef typename boost:: pointer_to_other::type const_pointer; typedef typename detail::add_reference ::type reference; diff --git a/test/check_equal_containers.hpp b/test/check_equal_containers.hpp index dd68998..fb15530 100644 --- a/test/check_equal_containers.hpp +++ b/test/check_equal_containers.hpp @@ -32,10 +32,12 @@ bool CheckEqualContainers(MyShmCont *shmcont, MyStdCont *stdcont) typename MyShmCont::iterator itshm(shmcont->begin()), itshmend(shmcont->end()); typename MyStdCont::iterator itstd(stdcont->begin()); - if((typename MyStdCont::size_type)std::distance(itshm, itshmend) != shmcont->size()){ + typename MyStdCont::size_type dist = (typename MyStdCont::size_type)std::distance(itshm, itshmend); + if(dist != shmcont->size()){ return false; } - for(; itshm != itshmend; ++itshm, ++itstd){ + std::size_t i = 0; + for(; itshm != itshmend; ++itshm, ++itstd, ++i){ value_type val(*itstd); const value_type &v = *itshm; if(v != val) diff --git a/test/data_test.cpp b/test/data_test.cpp index 66bb0dc..5c5f15a 100644 --- a/test/data_test.cpp +++ b/test/data_test.cpp @@ -17,7 +17,6 @@ #include #include #include -#include //std::remove #include "print_container.hpp" #include "get_process_id_name.hpp" @@ -29,8 +28,6 @@ int main () std::string process_name; test::get_process_id_name(process_name); const char *const shMemName = process_name.c_str(); - std::string filename (test::get_process_id_name()); - filename += "_file"; try{ shared_memory_object::remove(shMemName); @@ -90,12 +87,9 @@ int main () res = (0 == segment.find(allocName).first); if(!res) return 1; - - std::remove(filename.c_str()); } } catch(...){ - std::remove(filename.c_str()); shared_memory_object::remove(shMemName); throw; } diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 3046d46..94e1763 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -26,7 +26,6 @@ #include #include "allocator_v1.hpp" #include -#include #include #include #include @@ -67,12 +66,12 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) { IntType move_me(1); stddeque->insert(stddeque->begin()+size/2, 50, 1); - shmdeque->insert(shmdeque->begin()+size/2, 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin()+size/2, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { IntType move_me(2); - shmdeque->assign(shmdeque->size()/2, detail::move_impl(move_me)); + shmdeque->assign(shmdeque->size()/2, boost::interprocess::move(move_me)); stddeque->assign(stddeque->size()/2, 2); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } @@ -81,13 +80,13 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) stddeque->clear(); shmdeque->clear(); stddeque->insert(stddeque->begin(), 50, 1); - shmdeque->insert(shmdeque->begin(), 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin(), 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->begin()+20, 50, 1); - shmdeque->insert(shmdeque->begin()+20, 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin()+20, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->begin()+20, 20, 1); - shmdeque->insert(shmdeque->begin()+20, 20, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin()+20, 20, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } { @@ -95,13 +94,13 @@ bool copyable_only(V1 *shmdeque, V2 *stddeque, detail::true_type) stddeque->clear(); shmdeque->clear(); stddeque->insert(stddeque->end(), 50, 1); - shmdeque->insert(shmdeque->end(), 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end(), 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->end()-20, 50, 1); - shmdeque->insert(shmdeque->end()-20, 50, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end()-20, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; stddeque->insert(stddeque->end()-20, 20, 1); - shmdeque->insert(shmdeque->end()-20, 20, detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end()-20, 20, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } @@ -127,10 +126,9 @@ bool do_test() { //Now test move semantics deque original; - deque move_ctor(detail::move_impl(original)); + deque move_ctor(boost::interprocess::move(original)); deque move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } @@ -174,7 +172,7 @@ bool do_test() int i; for(i = 0; i < max*100; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->end(), detail::move_impl(move_me)); + shmdeque->insert(shmdeque->end(), boost::interprocess::move(move_me)); stddeque->insert(stddeque->end(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -184,7 +182,7 @@ bool do_test() for(i = 0; i < max*100; ++i){ IntType move_me(i); - shmdeque->push_back(detail::move_impl(move_me)); + shmdeque->push_back(boost::interprocess::move(move_me)); stddeque->push_back(i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -194,7 +192,7 @@ bool do_test() for(i = 0; i < max*100; ++i){ IntType move_me(i); - shmdeque->push_front(detail::move_impl(move_me)); + shmdeque->push_front(boost::interprocess::move(move_me)); stddeque->push_front(i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -215,7 +213,7 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me (-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -223,8 +221,8 @@ bool do_test() } shmdeque->insert(shmdeque->end() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stddeque->insert(stddeque->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; @@ -238,21 +236,21 @@ bool do_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } shmdeque->insert(shmdeque->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stddeque->insert(stddeque->begin(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; } if(!copyable_only(shmdeque, stddeque - ,detail::bool_::value>())){ + ,detail::bool_::value>())){ return false; } @@ -263,7 +261,7 @@ bool do_test() for(i = 0; i < max; ++i){ IntType move_me(i); - shmdeque->insert(shmdeque->begin(), detail::move_impl(move_me)); + shmdeque->insert(shmdeque->begin(), boost::interprocess::move(move_me)); stddeque->insert(stddeque->begin(), i); } if(!test::CheckEqualContainers(shmdeque, stddeque)) return false; diff --git a/test/dummy_test_allocator.hpp b/test/dummy_test_allocator.hpp index e8466f0..8a7af64 100644 --- a/test/dummy_test_allocator.hpp +++ b/test/dummy_test_allocator.hpp @@ -19,10 +19,10 @@ #include #include -#include +#include #include #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ class dummy_test_allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; -// typedef detail::version_type version; +// typedef boost::interprocess::version_type version; template struct rebind @@ -111,7 +111,7 @@ class dummy_test_allocator //Experimental version 2 dummy_test_allocator functions std::pair - allocation_command(allocation_type, + allocation_command(boost::interprocess::allocation_type, size_type, size_type, size_type &, const pointer & = 0) diff --git a/test/emplace_test.hpp b/test/emplace_test.hpp index 103d8da..ba27eab 100644 --- a/test/emplace_test.hpp +++ b/test/emplace_test.hpp @@ -29,27 +29,18 @@ class EmplaceInt EmplaceInt& operator=(const EmplaceInt &o); public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(EmplaceInt) + EmplaceInt(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0) : a_(a), b_(b), c_(c), d_(d), e_(e) {} - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - EmplaceInt(EmplaceInt &&o) + EmplaceInt(BOOST_INTERPROCESS_RV_REF(EmplaceInt) o) : a_(o.a_), b_(o.b_), c_(o.c_), d_(o.d_), e_(o.e_) - #else - EmplaceInt(detail::moved_object mo) - : a_(mo.get().a_), b_(mo.get().b_), c_(mo.get().c_), d_(mo.get().d_), e_(mo.get().e_) - #endif {} - #ifdef BOOST_INTERPROCESS_RVALUE_REFERENCE - EmplaceInt& operator=(EmplaceInt &&o) + EmplaceInt& operator=(BOOST_INTERPROCESS_RV_REF(EmplaceInt) o) { - #else - EmplaceInt& operator=(detail::moved_object mo) - { - EmplaceInt &o = mo.get(); - #endif this->a_ = o.a_; this->b_ = o.b_; this->c_ = o.c_; @@ -93,12 +84,6 @@ class EmplaceInt } //namespace test { -template<> -struct is_movable -{ - static const bool value = true; -}; - namespace test { enum EmplaceOptions{ diff --git a/test/expand_bwd_test_allocator.hpp b/test/expand_bwd_test_allocator.hpp index 0a62b33..a773cee 100644 --- a/test/expand_bwd_test_allocator.hpp +++ b/test/expand_bwd_test_allocator.hpp @@ -19,10 +19,10 @@ #include #include -#include +#include #include #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ class expand_bwd_test_allocator typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - typedef detail::version_type version; + typedef boost::interprocess::version_type version; template struct rebind @@ -118,14 +118,14 @@ class expand_bwd_test_allocator //Experimental version 2 expand_bwd_test_allocator functions std::pair - allocation_command(allocation_type command, + allocation_command(boost::interprocess::allocation_type command, size_type limit_size, size_type preferred_size, size_type &received_size, const pointer &reuse = 0) { (void)preferred_size; (void)reuse; (void)command; //This allocator only expands backwards! - assert(m_allocations == 0 || (command & expand_bwd)); + assert(m_allocations == 0 || (command & boost::interprocess::expand_bwd)); received_size = limit_size; diff --git a/test/file_lock_test.cpp b/test/file_lock_test.cpp index cc0c84c..e689256 100644 --- a/test/file_lock_test.cpp +++ b/test/file_lock_test.cpp @@ -11,12 +11,13 @@ #include #include #include +#include #include #include "mutex_test_template.hpp" #include "sharable_mutex_test_template.hpp" #include "get_process_id_name.hpp" #include -#include +#include //std::remove using namespace boost::interprocess; //This wrapper is necessary to have a default constructor @@ -49,16 +50,15 @@ int main () { scoped_lock sl(flock, test::delay(1)); } - }/* + } { //Now test move semantics file_lock mapping(test::get_process_id_name()); - file_lock move_ctor(detail::move_impl(mapping)); + file_lock move_ctor(boost::interprocess::move(mapping)); file_lock move_assign; - move_assign = detail::move_impl(move_ctor); - mapping.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); mapping.swap(move_assign); - }*/ + } //test::test_all_lock(); //test::test_all_mutex(); diff --git a/test/file_mapping_test.cpp b/test/file_mapping_test.cpp index 2aa7e3f..1151fd1 100644 --- a/test/file_mapping_test.cpp +++ b/test/file_mapping_test.cpp @@ -16,12 +16,17 @@ #include #include //std::auto_ptr #include //std::exception -#include //std::remove #include //std::size_t #include "get_process_id_name.hpp" using namespace boost::interprocess; +file_mapping get_file_mapping() +{ + file_mapping f; + return file_mapping(boost::interprocess::move(f)); +} + int main () { try{ @@ -125,19 +130,19 @@ int main () { //Now test move semantics file_mapping mapping(test::get_process_id_name(), read_only); - file_mapping move_ctor(detail::move_impl(mapping)); + file_mapping move_ctor(boost::interprocess::move(mapping)); file_mapping move_assign; - move_assign = detail::move_impl(move_ctor); - mapping.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); mapping.swap(move_assign); + file_mapping ret(get_file_mapping()); } } catch(std::exception &exc){ - std::remove(test::get_process_id_name()); + file_mapping::remove(test::get_process_id_name()); std::cout << "Unhandled exception: " << exc.what() << std::endl; throw; } - std::remove(test::get_process_id_name()); + file_mapping::remove(test::get_process_id_name()); return 0; } diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp index e7ebd77..9bc3ae4 100644 --- a/test/flat_tree_test.cpp +++ b/test/flat_tree_test.cpp @@ -62,7 +62,7 @@ typedef basic_managed_shared_memory , rbtree_best_fit, - flat_map_index + iset_index > my_managed_shared_memory; //Alias allocator type @@ -132,10 +132,49 @@ public: { return a.id_ < b.id_; } }; +//Test recursive structures +class recursive_flat_multiset +{ +public: + int id_; + flat_multiset flat_set_; + friend bool operator< (const recursive_flat_multiset &a, const recursive_flat_set &b) + { return a.id_ < b.id_; } +}; + +class recursive_flat_multimap +{ +public: + int id_; + flat_map map_; + friend bool operator< (const recursive_flat_multimap &a, const recursive_flat_multimap &b) + { return a.id_ < b.id_; } +}; + +template +void test_move() +{ + //Now test move semantics + C original; + C move_ctor(boost::interprocess::move(original)); + C move_assign; + move_assign = boost::interprocess::move(move_ctor); + move_assign.swap(original); +} + int main() { using namespace boost::interprocess::test; + //Now test move semantics + { + test_move >(); + test_move >(); + test_move >(); + test_move >(); + } + + if (0 != set_test, SetOptions>()) return 1; - #endif //!defined(__GNUC__) + //#endif //!defined(__GNUC__) return 0; + } #include diff --git a/test/get_process_id_name.hpp b/test/get_process_id_name.hpp index df3bb8f..330cf58 100644 --- a/test/get_process_id_name.hpp +++ b/test/get_process_id_name.hpp @@ -23,8 +23,8 @@ namespace test{ inline void get_process_id_name(std::string &str) { std::stringstream sstr; - sstr << "process_" << boost::interprocess::detail::get_current_process_id(); - str = sstr.str(); + sstr << "process_" << boost::interprocess::detail::get_current_process_id() << std::ends; + str = sstr.str().c_str(); } inline const char *get_process_id_name() diff --git a/test/list_test.cpp b/test/list_test.cpp index d7f58dd..2e95d9d 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -54,10 +54,9 @@ int main () { //Now test move semantics list original; - list move_ctor(detail::move_impl(original)); + list move_ctor(boost::interprocess::move(original)); list move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } if(test::list_test()) diff --git a/test/list_test.hpp b/test/list_test.hpp index 390f61e..a9de4c8 100644 --- a/test/list_test.hpp +++ b/test/list_test.hpp @@ -19,7 +19,6 @@ #include #include "print_container.hpp" #include -#include #include #include "get_process_id_name.hpp" @@ -36,7 +35,7 @@ struct push_data_function typedef typename MyShmList::value_type IntType; for(int i = 0; i < max; ++i){ IntType move_me(i); - shmlist->push_back(detail::move_impl(move_me)); + shmlist->push_back(boost::interprocess::move(move_me)); stdlist->push_back(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -54,7 +53,7 @@ struct push_data_function typedef typename MyShmList::value_type IntType; for(int i = 0; i < max; ++i){ IntType move_me(i); - shmlist->push_front(detail::move_impl(move_me)); + shmlist->push_front(boost::interprocess::move(move_me)); stdlist->push_front(i); } if(!CheckEqualContainers(shmlist, stdlist)) @@ -113,6 +112,7 @@ int list_test (bool copied_allocators_equal = true) MyShmList *shmlist = segment.template construct("MyList") (segment.get_segment_manager()); + MyStdList *stdlist = new MyStdList; if(push_data_t::execute(max, shmlist, stdlist)){ @@ -135,14 +135,14 @@ int list_test (bool copied_allocators_equal = true) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } - shmlist->assign(detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(&aux_vect[50])); + shmlist->assign(boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(&aux_vect[50])); stdlist->assign(&aux_vect2[0], &aux_vect2[50]); if(!CheckEqualContainers(shmlist, stdlist)) return 1; } @@ -165,15 +165,15 @@ int list_test (bool copied_allocators_equal = true) IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } shmlist->insert(shmlist->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(&aux_vect[50])); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(&aux_vect[50])); stdlist->insert(stdlist->begin(), &aux_vect2[0], &aux_vect2[50]); } diff --git a/test/managed_mapped_file_test.cpp b/test/managed_mapped_file_test.cpp index cebbfe5..f0b3f6e 100644 --- a/test/managed_mapped_file_test.cpp +++ b/test/managed_mapped_file_test.cpp @@ -31,7 +31,7 @@ int main () { //Remove the file it is already created - std::remove(FileName); + file_mapping::remove(FileName); const int max = 100; void *array[max]; @@ -52,7 +52,7 @@ int main () { //Remove the file it is already created - std::remove(FileName); + file_mapping::remove(FileName); //Named allocate capable memory mapped file managed memory class managed_mapped_file mfile(create_only, FileName, FileSize); @@ -203,15 +203,14 @@ int main () { //Now test move semantics managed_mapped_file original(open_only, FileName); - managed_mapped_file move_ctor(detail::move_impl(original)); + managed_mapped_file move_ctor(boost::interprocess::move(original)); managed_mapped_file move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } } - std::remove(FileName); + file_mapping::remove(FileName); return 0; } diff --git a/test/managed_shared_memory_test.cpp b/test/managed_shared_memory_test.cpp index 1314038..f19fabe 100644 --- a/test/managed_shared_memory_test.cpp +++ b/test/managed_shared_memory_test.cpp @@ -199,10 +199,9 @@ int main () { //Now test move semantics managed_shared_memory original(open_only, ShmemName); - managed_shared_memory move_ctor(detail::move_impl(original)); + managed_shared_memory move_ctor(boost::interprocess::move(original)); managed_shared_memory move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } } diff --git a/test/managed_windows_shared_memory_test.cpp b/test/managed_windows_shared_memory_test.cpp index f02868f..cdb1d68 100644 --- a/test/managed_windows_shared_memory_test.cpp +++ b/test/managed_windows_shared_memory_test.cpp @@ -9,8 +9,9 @@ ////////////////////////////////////////////////////////////////////////////// #include +#include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS #include #include @@ -130,9 +131,9 @@ int main () //Now test move semantics managed_windows_shared_memory original(open_only, MemName); - managed_windows_shared_memory move_ctor(detail::move_impl(original)); + managed_windows_shared_memory move_ctor(boost::interprocess::move(original)); managed_windows_shared_memory move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); } } diff --git a/test/map_test.hpp b/test/map_test.hpp index 13363bf..c4e88f7 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -17,9 +17,8 @@ #include #include #include "print_container.hpp" -#include #include -#include +#include #include #include "get_process_id_name.hpp" @@ -41,7 +40,7 @@ template IntPairType; + typedef boost::interprocess::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; const int memsize = 65536; const char *const shMemName = test::get_process_id_name(); @@ -73,7 +72,9 @@ int map_test () //This is really nasty, but we have no other simple choice IntPairType aux_vect[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect[i])IntPairType(IntType(i/2), IntType(i/2)); + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } typedef typename MyStdMap::value_type StdValueType; @@ -86,21 +87,23 @@ int map_test () IntPairType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect3[i])IntPairType(IntType(i/2), IntType(i/2)); + IntType i1(i/2); + IntType i2(i/2); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } MyShmMap *shmmap2 = segment.template construct("MyShmMap2") - (detail::make_move_iterator(&aux_vect[0]) - , detail::make_move_iterator(aux_vect + 50) + (boost::interprocess::make_move_iterator(&aux_vect[0]) + , boost::interprocess::make_move_iterator(aux_vect + 50) , std::less(), segment.get_segment_manager()); MyStdMap *stdmap2 = new MyStdMap(aux_vect2, aux_vect2 + 50); MyShmMultiMap *shmmultimap2 = segment.template construct("MyShmMultiMap2") - (detail::make_move_iterator(&aux_vect3[0]) - , detail::make_move_iterator(aux_vect3 + 50) + (boost::interprocess::make_move_iterator(&aux_vect3[0]) + , boost::interprocess::make_move_iterator(aux_vect3 + 50) , std::less(), segment.get_segment_manager()); MyStdMultiMap *stdmultimap2 = new MyStdMultiMap(aux_vect2, aux_vect2 + 50); @@ -112,71 +115,89 @@ int map_test () delete stdmap2; delete stdmultimap2; } + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + IntPairType aux_vect3[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } - int i, j; - for(i = 0; i < max; ++i){ - shmmap->insert(detail::move_impl(IntPairType (detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(StdPairType(i, i)); + for(int i = 0; i < max; ++i){ + shmmap->insert(boost::interprocess::move(aux_vect[i])); + stdmap->insert(StdPairType(i, i)); + shmmultimap->insert(boost::interprocess::move(aux_vect3[i])); + stdmultimap->insert(StdPairType(i, i)); + } + + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + typename MyShmMap::iterator it; + typename MyShmMap::const_iterator cit = it; + + shmmap->erase(shmmap->begin()++); + stdmap->erase(stdmap->begin()++); + shmmultimap->erase(shmmultimap->begin()++); + stdmultimap->erase(stdmultimap->begin()++); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + shmmap->erase(shmmap->begin()); + stdmap->erase(stdmap->begin()); + shmmultimap->erase(shmmultimap->begin()); + stdmultimap->erase(stdmultimap->begin()); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; + + //Swapping test + std::less lessfunc; + MyShmMap tmpshmemap2 (lessfunc, segment.get_segment_manager()); + MyStdMap tmpstdmap2; + MyShmMultiMap tmpshmemultimap2(lessfunc, segment.get_segment_manager()); + MyStdMultiMap tmpstdmultimap2; + shmmap->swap(tmpshmemap2); + stdmap->swap(tmpstdmap2); + shmmultimap->swap(tmpshmemultimap2); + stdmultimap->swap(tmpstdmultimap2); + shmmap->swap(tmpshmemap2); + stdmap->swap(tmpstdmap2); + shmmultimap->swap(tmpshmemultimap2); + stdmultimap->swap(tmpstdmultimap2); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; } - - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - typename MyShmMap::iterator it; - typename MyShmMap::const_iterator cit = it; - - shmmap->erase(shmmap->begin()++); - stdmap->erase(stdmap->begin()++); - shmmultimap->erase(shmmultimap->begin()++); - stdmultimap->erase(stdmultimap->begin()++); - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - shmmap->erase(shmmap->begin()); - stdmap->erase(stdmap->begin()); - shmmultimap->erase(shmmultimap->begin()); - stdmultimap->erase(stdmultimap->begin()); - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - //Swapping test - std::less lessfunc; - MyShmMap tmpshmemap2 (lessfunc, segment.get_segment_manager()); - MyStdMap tmpstdmap2; - MyShmMultiMap tmpshmemultimap2(lessfunc, segment.get_segment_manager()); - MyStdMultiMap tmpstdmultimap2; - shmmap->swap(tmpshmemap2); - stdmap->swap(tmpstdmap2); - shmmultimap->swap(tmpshmemultimap2); - stdmultimap->swap(tmpstdmultimap2); - shmmap->swap(tmpshmemap2); - stdmap->swap(tmpstdmap2); - shmmultimap->swap(tmpshmemultimap2); - stdmultimap->swap(tmpstdmultimap2); - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - //Insertion from other container //Initialize values { //This is really nasty, but we have no other simple choice IntPairType aux_vect[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect3[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } - shmmap->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); - StdPairType stdpairtype(-1, -1); - constant_iterator constant_beg(stdpairtype, 50), constant_end; - stdmap->insert(constant_beg, constant_end); - shmmultimap->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); - stdmultimap->insert(constant_beg, constant_end); + shmmap->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); + shmmultimap->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); + for(std::size_t i = 0; i != 50; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + } if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; @@ -192,34 +213,44 @@ int map_test () { IntPairType aux_vect[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect3[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect3[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect4[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect4[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect4[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } IntPairType aux_vect5[50]; for(int i = 0; i < 50; ++i){ - new(&aux_vect5[i])IntPairType(IntType(-1), IntType(-1)); + IntType i1(-1); + IntType i2(-1); + new(&aux_vect5[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } - shmmap->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); - shmmap->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); - StdPairType stdpairtype(-1, -1); - constant_iterator constant_beg(stdpairtype, 50), constant_end; - stdmap->insert(constant_beg, constant_end); - stdmap->insert(constant_beg, constant_end); - shmmultimap->insert(detail::make_move_iterator(&aux_vect4[0]), detail::make_move_iterator(aux_vect4 + 50)); - shmmultimap->insert(detail::make_move_iterator(&aux_vect5[0]), detail::make_move_iterator(aux_vect5 + 50)); - stdmultimap->insert(constant_beg, constant_end); - stdmultimap->insert(constant_beg, constant_end); + shmmap->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); + shmmap->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); + shmmultimap->insert(boost::interprocess::make_move_iterator(&aux_vect4[0]), boost::interprocess::make_move_iterator(aux_vect4 + 50)); + shmmultimap->insert(boost::interprocess::make_move_iterator(&aux_vect5[0]), boost::interprocess::make_move_iterator(aux_vect5 + 50)); + + for(std::size_t i = 0; i != 50; ++i){ + StdPairType stdpairtype(-1, -1); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + stdmap->insert(stdpairtype); + stdmultimap->insert(stdpairtype); + } if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; @@ -231,84 +262,158 @@ int map_test () if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; } - for(i = 0; i < max; ++i){ - shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(StdPairType(i, i)); - } - - if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - - for(i = 0; i < max; ++i){ - shmmap->insert(shmmap->begin(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(stdmap->begin(), StdPairType(i, i)); - //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->begin(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(stdmultimap->begin(), StdPairType(i, i)); - //PrintContainers(shmmultimap, stdmultimap); - if(!CheckEqualPairContainers(shmmap, stdmap)) - return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) - return 1; - - shmmap->insert(shmmap->end(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(stdmap->end(), StdPairType(i, i)); - shmmultimap->insert(shmmultimap->end(), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(stdmultimap->end(), StdPairType(i, i)); - if(!CheckEqualPairContainers(shmmap, stdmap)) - return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) - return 1; - - shmmap->insert(shmmap->lower_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(stdmap->lower_bound(i), StdPairType(i, i)); - //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->lower_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(stdmultimap->lower_bound(i), StdPairType(i, i)); - //PrintContainers(shmmultimap, stdmultimap); - if(!CheckEqualPairContainers(shmmap, stdmap)) - return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) - return 1; - shmmap->insert(shmmap->upper_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmap->insert(stdmap->upper_bound(i), StdPairType(i, i)); - //PrintContainers(shmmap, stdmap); - shmmultimap->insert(shmmultimap->upper_bound(IntType(i)), detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - stdmultimap->insert(stdmultimap->upper_bound(i), StdPairType(i, i)); - //PrintContainers(shmmultimap, stdmultimap); - if(!CheckEqualPairContainers(shmmap, stdmap)) - return 1; - if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) - return 1; - } - - //Compare count with std containers - for(i = 0; i < max; ++i){ - if(shmmap->count(IntType(i)) != stdmap->count(i)){ - return -1; + { + //This is really nasty, but we have no other simple choice + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + IntPairType aux_vect3[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect3[i])IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); } - if(shmmultimap->count(IntType(i)) != stdmultimap->count(i)){ - return -1; + for(int i = 0; i < max; ++i){ + shmmap->insert(boost::interprocess::move(aux_vect[i])); + stdmap->insert(StdPairType(i, i)); + shmmultimap->insert(boost::interprocess::move(aux_vect3[i])); + stdmultimap->insert(StdPairType(i, i)); } - } - //Now do count exercise - shmmap->erase(shmmap->begin(), shmmap->end()); - shmmultimap->erase(shmmultimap->begin(), shmmultimap->end()); - shmmap->clear(); - shmmultimap->clear(); + if(!CheckEqualPairContainers(shmmap, stdmap)) return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) return 1; - for(j = 0; j < 3; ++j) - for(i = 0; i < 100; ++i){ - shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); - if(shmmap->count(IntType(i)) != typename MyShmMultiMap::size_type(1)) - return 1; - if(shmmultimap->count(IntType(i)) != typename MyShmMultiMap::size_type(j+1)) - return 1; + for(int i = 0; i < max; ++i){ + IntPairType intpair; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(shmmap->begin(), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->begin(), StdPairType(i, i)); + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmultimap->insert(shmmultimap->begin(), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->begin(), StdPairType(i, i)); + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(shmmap->end(), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->end(), StdPairType(i, i)); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmultimap->insert(shmmultimap->end(), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->end(), StdPairType(i, i)); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(shmmap->lower_bound(IntType(i)), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->lower_bound(i), StdPairType(i, i)); + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + { + IntType i1(i); + shmmultimap->insert(shmmultimap->lower_bound(boost::interprocess::move(i1)), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->lower_bound(i), StdPairType(i, i)); + } + + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + { + IntType i1(i); + shmmap->insert(shmmap->upper_bound(boost::interprocess::move(i1)), boost::interprocess::move(intpair)); + stdmap->insert(stdmap->upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(shmmap, stdmap); + { + IntType i1(i); + IntType i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + { + IntType i1(i); + shmmultimap->insert(shmmultimap->upper_bound(boost::interprocess::move(i1)), boost::interprocess::move(intpair)); + stdmultimap->insert(stdmultimap->upper_bound(i), StdPairType(i, i)); + } + //PrintContainers(shmmultimap, stdmultimap); + if(!CheckEqualPairContainers(shmmap, stdmap)) + return 1; + if(!CheckEqualPairContainers(shmmultimap, stdmultimap)) + return 1; + } + + //Compare count with std containers + for(int i = 0; i < max; ++i){ + if(shmmap->count(IntType(i)) != stdmap->count(i)){ + return -1; + } + + if(shmmultimap->count(IntType(i)) != stdmultimap->count(i)){ + return -1; + } + } + + //Now do count exercise + shmmap->erase(shmmap->begin(), shmmap->end()); + shmmultimap->erase(shmmultimap->begin(), shmmultimap->end()); + shmmap->clear(); + shmmultimap->clear(); + + for(int j = 0; j < 3; ++j) + for(int i = 0; i < 100; ++i){ + IntPairType intpair; + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmap->insert(boost::interprocess::move(intpair)); + { + IntType i1(i), i2(i); + new(&intpair)IntPairType(boost::interprocess::move(i1), boost::interprocess::move(i2)); + } + shmmultimap->insert(boost::interprocess::move(intpair)); + if(shmmap->count(IntType(i)) != typename MyShmMultiMap::size_type(1)) + return 1; + if(shmmultimap->count(IntType(i)) != typename MyShmMultiMap::size_type(j+1)) + return 1; + } } segment.template destroy("MyShmMap"); @@ -337,7 +442,7 @@ template IntPairType; + typedef boost::interprocess::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; const int memsize = 65536; @@ -367,10 +472,18 @@ int map_test_copyable () int i; for(i = 0; i < max; ++i){ - shmmap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); + { + IntType i1(i), i2(i); + IntPairType intpair1(boost::interprocess::move(i1), boost::interprocess::move(i2)); + shmmap->insert(boost::interprocess::move(intpair1)); stdmap->insert(StdPairType(i, i)); - shmmultimap->insert(detail::move_impl(IntPairType(detail::move_impl(IntType(i)), detail::move_impl(IntType(i))))); + } + { + IntType i1(i), i2(i); + IntPairType intpair2(boost::interprocess::move(i1), boost::interprocess::move(i2)); + shmmultimap->insert(boost::interprocess::move(intpair2)); stdmultimap->insert(StdPairType(i, i)); + } } if(!CheckEqualContainers(shmmap, stdmap)) return 1; if(!CheckEqualContainers(shmmultimap, stdmultimap)) return 1; diff --git a/test/mapped_file_test.cpp b/test/mapped_file_test.cpp index 75bb9eb..d2f6aba 100644 --- a/test/mapped_file_test.cpp +++ b/test/mapped_file_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "named_creation_template.hpp" #include @@ -29,7 +30,7 @@ struct file_destroyer ~file_destroyer() { //The last destructor will destroy the file - std::remove(FileName); + file_mapping::remove(FileName); } }; @@ -60,7 +61,7 @@ int main () { typedef boost::interprocess::detail::managed_open_or_create_impl mapped_file; - std::remove(FileName); + file_mapping::remove(FileName); test::test_named_creation(); //Create and get name, size and address @@ -76,11 +77,11 @@ int main () std::memset(file1.get_user_address(), 0, file1.get_user_size()); //Now test move semantics - mapped_file move_ctor(detail::move_impl(file1)); + mapped_file move_ctor(boost::interprocess::move(file1)); mapped_file move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); } - std::remove(FileName); + file_mapping::remove(FileName); return 0; } diff --git a/test/memory_algorithm_test_template.hpp b/test/memory_algorithm_test_template.hpp index f7216d4..08436af 100644 --- a/test/memory_algorithm_test_template.hpp +++ b/test/memory_algorithm_test_template.hpp @@ -17,7 +17,7 @@ #include #include #include //std::memset -#include //std::remove +#include namespace boost { namespace interprocess { namespace test { @@ -107,7 +107,7 @@ bool test_allocation_shrink(Allocator &a) ; ++i){ std::size_t received_size; if(a.template allocation_command - ( shrink_in_place | nothrow_allocation, i*2 + ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, i*2 , i, received_size, static_cast(buffers[i])).first){ if(received_size > std::size_t(i*2)){ return false; @@ -159,7 +159,7 @@ bool test_allocation_expand(Allocator &a) preferred_size = min_size > preferred_size ? min_size : preferred_size; while(a.template allocation_command - ( expand_fwd | nothrow_allocation, min_size + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size , preferred_size, received_size, static_cast(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ @@ -197,10 +197,10 @@ bool test_allocation_shrink_and_expand(Allocator &a) for(int i = 0; true; ++i){ std::size_t received_size; void *ptr = a.template allocation_command - ( allocate_new | nothrow_allocation, i, i*2, received_size).first; + ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, i, i*2, received_size).first; if(!ptr){ ptr = a.template allocation_command - ( allocate_new | nothrow_allocation, 1, i*2, received_size).first; + ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, 1, i*2, received_size).first; if(!ptr) break; } @@ -214,7 +214,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) ; ++i){ std::size_t received_size; if(a.template allocation_command - ( shrink_in_place | nothrow_allocation, received_sizes[i] + ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_sizes[i] , i, received_size, static_cast(buffers[i])).first){ if(received_size > std::size_t(received_sizes[i])){ return false; @@ -233,7 +233,7 @@ bool test_allocation_shrink_and_expand(Allocator &a) std::size_t received_size; std::size_t request_size = received_sizes[i]; if(a.template allocation_command - ( expand_fwd | nothrow_allocation, request_size + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, request_size , request_size, received_size, static_cast(buffers[i])).first){ if(received_size != received_sizes[i]){ return false; @@ -298,7 +298,7 @@ bool test_allocation_deallocation_expand(Allocator &a) preferred_size = min_size > preferred_size ? min_size : preferred_size; while(a.template allocation_command - ( expand_fwd | nothrow_allocation, min_size + ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size , preferred_size, received_size, static_cast(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ @@ -368,7 +368,7 @@ bool test_allocation_with_reuse(Allocator &a) std::size_t min_size = (received_size + 1); std::size_t prf_size = (received_size + (i+1)*2); std::pair ret = a.raw_allocation_command - ( expand_bwd | nothrow_allocation, min_size + ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size , prf_size, received_size, static_cast(ptr), sizeof_object); if(!ret.first) break; @@ -631,7 +631,6 @@ bool test_grow_shrink_to_fit(Allocator &a) template bool test_many_equal_allocation(Allocator &a) { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; for( deallocation_type t = DirectDeallocation ; t != EndDeallocationType ; t = (deallocation_type)((int)t + 1)){ @@ -665,16 +664,17 @@ bool test_many_equal_allocation(Allocator &a) if(!a.check_sanity()) return false; + typedef typename Allocator::multiallocation_chain multiallocation_chain; std::vector buffers; for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(i+1, (i+1)*2, std::nothrow); - if(!it) + multiallocation_chain chain(a.allocate_many(i+1, (i+1)*2, std::nothrow)); + if(chain.empty()) break; - multiallocation_iterator itend; - std::size_t n = 0; - for(; it != itend; ++n){ - buffers.push_back(&*it++); + std::size_t n = chain.size(); + while(!chain.empty()){ + buffers.push_back(detail::get_pointer(chain.front())); + chain.pop_front(); } if(n != std::size_t((i+1)*2)) return false; @@ -740,7 +740,7 @@ bool test_many_equal_allocation(Allocator &a) template bool test_many_different_allocation(Allocator &a) { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + typedef typename Allocator::multiallocation_chain multiallocation_chain; const std::size_t ArraySize = 11; std::size_t requested_sizes[ArraySize]; for(std::size_t i = 0; i < ArraySize; ++i){ @@ -777,13 +777,13 @@ bool test_many_different_allocation(Allocator &a) std::vector buffers; for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); - if(!it) + multiallocation_chain chain(a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow)); + if(chain.empty()) break; - multiallocation_iterator itend; - std::size_t n = 0; - for(; it != itend; ++n){ - buffers.push_back(&*it++); + std::size_t n = chain.size(); + while(!chain.empty()){ + buffers.push_back(detail::get_pointer(chain.front())); + chain.pop_front(); } if(n != ArraySize) return false; @@ -846,9 +846,9 @@ bool test_many_different_allocation(Allocator &a) template bool test_many_deallocation(Allocator &a) { - typedef typename Allocator::multiallocation_iterator multiallocation_iterator; + typedef typename Allocator::multiallocation_chain multiallocation_chain; const std::size_t ArraySize = 11; - std::vector buffers; + vector buffers; std::size_t requested_sizes[ArraySize]; for(std::size_t i = 0; i < ArraySize; ++i){ requested_sizes[i] = 4*i; @@ -857,13 +857,13 @@ bool test_many_deallocation(Allocator &a) { for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); - if(!it) + multiallocation_chain chain = a.allocate_many(requested_sizes, ArraySize, 1, std::nothrow); + if(chain.empty()) break; - buffers.push_back(it); + buffers.push_back(boost::interprocess::move(chain)); } for(int i = 0, max = (int)buffers.size(); i != max; ++i){ - a.deallocate_many(buffers[i]); + a.deallocate_many(boost::interprocess::move(buffers[i])); } buffers.clear(); bool ok = free_memory == a.get_free_memory() && @@ -873,13 +873,13 @@ bool test_many_deallocation(Allocator &a) { for(int i = 0; true; ++i){ - multiallocation_iterator it = a.allocate_many(i*4, ArraySize, std::nothrow); - if(!it) + multiallocation_chain chain(a.allocate_many(i*4, ArraySize, std::nothrow)); + if(chain.empty()) break; - buffers.push_back(it); + buffers.push_back(boost::interprocess::move(chain)); } for(int i = 0, max = (int)buffers.size(); i != max; ++i){ - a.deallocate_many(buffers[i]); + a.deallocate_many(boost::interprocess::move(buffers[i])); } buffers.clear(); diff --git a/test/movable_int.hpp b/test/movable_int.hpp index 2ac7fb8..ee62582 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -21,10 +21,11 @@ namespace test { class movable_int { - movable_int(const movable_int&); - movable_int &operator= (const movable_int&); + movable_int(movable_int&); + movable_int &operator= (movable_int&); public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(movable_int) movable_int() : m_int(0) @@ -34,23 +35,12 @@ class movable_int : m_int(a) {} - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_int(detail::moved_object mmi) - : m_int(mmi.get().m_int) - { mmi.get().m_int = 0; } - #else - movable_int(movable_int &&mmi) + movable_int(BOOST_INTERPROCESS_RV_REF(movable_int) mmi) : m_int(mmi.m_int) { mmi.m_int = 0; } - #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_int & operator= (detail::moved_object mmi) - { this->m_int = mmi.get().m_int; mmi.get().m_int = 0; return *this; } - #else - movable_int & operator= (movable_int &&mmi) + movable_int & operator= (BOOST_INTERPROCESS_RV_REF(movable_int) mmi) { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } - #endif movable_int & operator= (int i) { this->m_int = i; return *this; } @@ -92,6 +82,7 @@ std::basic_ostream & operator<< class movable_and_copyable_int { public: + BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(movable_and_copyable_int) movable_and_copyable_int() : m_int(0) @@ -108,23 +99,12 @@ class movable_and_copyable_int movable_and_copyable_int &operator= (const movable_and_copyable_int& mi) { this->m_int = mi.m_int; return *this; } - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_and_copyable_int(detail::moved_object mmi) - : m_int(mmi.get().m_int) - { mmi.get().m_int = 0; } - #else - movable_and_copyable_int(movable_and_copyable_int &&mmi) + movable_and_copyable_int(BOOST_INTERPROCESS_RV_REF(movable_and_copyable_int) mmi) : m_int(mmi.m_int) { mmi.m_int = 0; } - #endif - #ifndef BOOST_INTERPROCESS_RVALUE_REFERENCE - movable_and_copyable_int & operator= (detail::moved_object mmi) - { this->m_int = mmi.get().m_int; mmi.get().m_int = 0; return *this; } - #else - movable_and_copyable_int & operator= (movable_and_copyable_int &&mmi) + movable_and_copyable_int & operator= (BOOST_INTERPROCESS_RV_REF(movable_and_copyable_int) mmi) { this->m_int = mmi.m_int; mmi.m_int = 0; return *this; } - #endif movable_and_copyable_int & operator= (int i) { this->m_int = i; return *this; } @@ -167,26 +147,6 @@ std::basic_ostream & operator<< } //namespace interprocess { } //namespace boost { -namespace boost{ -namespace interprocess{ - -template<> -struct is_movable -{ - public: - enum { value = true }; -}; - -template<> -struct is_movable -{ - public: - enum { value = true }; -}; - -} //namespace interprocess{ -} //namespace boost{ - #include #endif //#ifndef BOOST_INTERPROCESS_TEST_MOVABLE_INT_HEADER diff --git a/test/multi_index_test.cpp b/test/multi_index_test.cpp index 40ce912..ad3e75b 100644 --- a/test/multi_index_test.cpp +++ b/test/multi_index_test.cpp @@ -28,8 +28,8 @@ using namespace boost::interprocess; namespace bmi = boost::multi_index; -typedef managed_shared_memory::allocator::type char_allocator; -typedef basic_string, char_allocator>shm_string; +typedef managed_shared_memory::allocator::type char_allocator; +typedef basic_string, char_allocator> shm_string; //Data to insert in shared memory struct employee @@ -75,33 +75,7 @@ template class bmi::multi_index_container< , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, adaptive_pool >; -/* -// Explicit instantiations to catch compile-time errors -template class bmi::multi_index_container< - employee, - bmi::indexed_by< - bmi::ordered_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, - bmi::ordered_non_unique< - bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, - bmi::ordered_non_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, - cached_adaptive_pool ->; -// Explicit instantiations to catch compile-time errors -template class bmi::multi_index_container< - employee, - bmi::indexed_by< - bmi::ordered_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, - bmi::ordered_non_unique< - bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, - bmi::ordered_non_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, - private_adaptive_pool ->; -*/ // Explicit instantiations to catch compile-time errors template class bmi::multi_index_container< employee, @@ -114,33 +88,7 @@ template class bmi::multi_index_container< , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, node_allocator >; -/* -// Explicit instantiations to catch compile-time errors -template class bmi::multi_index_container< - employee, - bmi::indexed_by< - bmi::ordered_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, - bmi::ordered_non_unique< - bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, - bmi::ordered_non_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, - cached_node_allocator ->; -// Explicit instantiations to catch compile-time errors -template class bmi::multi_index_container< - employee, - bmi::indexed_by< - bmi::ordered_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,id)>, - bmi::ordered_non_unique< - bmi::tag,BOOST_MULTI_INDEX_MEMBER(employee,shm_string,name)>, - bmi::ordered_non_unique - , BOOST_MULTI_INDEX_MEMBER(employee,int,age)> >, - private_node_allocator ->; -*/ int main () { return 0; diff --git a/test/set_test.hpp b/test/set_test.hpp index db8766f..00c1d2f 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -17,7 +17,7 @@ #include #include #include "print_container.hpp" -#include +#include #include #include "get_process_id_name.hpp" @@ -63,7 +63,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -72,21 +72,21 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(i/2); - aux_vect3[i] = detail::move_impl(move_me); + aux_vect3[i] = boost::interprocess::move(move_me); } MyShmSet *shmset2 = segment.template construct("MyShmSet2") - (detail::make_move_iterator(&aux_vect[0]) - , detail::make_move_iterator(aux_vect + 50) + (boost::interprocess::make_move_iterator(&aux_vect[0]) + , boost::interprocess::make_move_iterator(aux_vect + 50) , std::less(), segment.get_segment_manager()); MyStdSet *stdset2 = new MyStdSet(aux_vect2, aux_vect2 + 50); MyShmMultiSet *shmmultiset2 = segment.template construct("MyShmMultiSet2") - (detail::make_move_iterator(&aux_vect3[0]) - , detail::make_move_iterator(aux_vect3 + 50) + (boost::interprocess::make_move_iterator(&aux_vect3[0]) + , boost::interprocess::make_move_iterator(aux_vect3 + 50) , std::less(), segment.get_segment_manager()); MyStdMultiSet *stdmultiset2 = new MyStdMultiSet(aux_vect2, aux_vect2 + 50); @@ -108,20 +108,20 @@ int set_test () int i, j; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::move_impl(move_me)" << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::move(move_me)" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me)" << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::move(move_me)" << std::endl; return 1; } @@ -183,7 +183,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -192,19 +192,19 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = detail::move_impl(move_me); + aux_vect3[i] = boost::interprocess::move(move_me); } - shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); + shmset->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); stdset->insert(aux_vect2, aux_vect2 + 50); - shmmultiset->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); + shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); stdmultiset->insert(aux_vect2, aux_vect2 + 50); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::make_move_iterator(&aux_vect[0])..." << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::make_move_iterator(&aux_vect[0])..." << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::make_move_iterator(&aux_vect3[0]), ..." << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), ..." << std::endl; return 1; } @@ -228,7 +228,7 @@ int set_test () IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect[i] = detail::move_impl(move_me); + aux_vect[i] = boost::interprocess::move(move_me); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -237,35 +237,35 @@ int set_test () IntType aux_vect3[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect3[i] = detail::move_impl(move_me); + aux_vect3[i] = boost::interprocess::move(move_me); } IntType aux_vect4[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect4[i] = detail::move_impl(move_me); + aux_vect4[i] = boost::interprocess::move(move_me); } IntType aux_vect5[50]; for(int i = 0; i < 50; ++i){ IntType move_me(-1); - aux_vect5[i] = detail::move_impl(move_me); + aux_vect5[i] = boost::interprocess::move(move_me); } - shmset->insert(detail::make_move_iterator(&aux_vect[0]), detail::make_move_iterator(aux_vect + 50)); - shmset->insert(detail::make_move_iterator(&aux_vect3[0]), detail::make_move_iterator(aux_vect3 + 50)); + shmset->insert(boost::interprocess::make_move_iterator(&aux_vect[0]), boost::interprocess::make_move_iterator(aux_vect + 50)); + shmset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0]), boost::interprocess::make_move_iterator(aux_vect3 + 50)); stdset->insert(aux_vect2, aux_vect2 + 50); stdset->insert(aux_vect2, aux_vect2 + 50); - shmmultiset->insert(detail::make_move_iterator(&aux_vect4[0]), detail::make_move_iterator(aux_vect4 + 50)); - shmmultiset->insert(detail::make_move_iterator(&aux_vect5[0]), detail::make_move_iterator(aux_vect5 + 50)); + shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect4[0]), boost::interprocess::make_move_iterator(aux_vect4 + 50)); + shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect5[0]), boost::interprocess::make_move_iterator(aux_vect5 + 50)); stdmultiset->insert(aux_vect2, aux_vect2 + 50); stdmultiset->insert(aux_vect2, aux_vect2 + 50); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::make_move_iterator(&aux_vect3[0])..." << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::make_move_iterator(&aux_vect3[0])..." << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::make_move_iterator(&aux_vect5[0])..." << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::make_move_iterator(&aux_vect5[0])..." << std::endl; return 1; } @@ -285,88 +285,88 @@ int set_test () for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(detail::move_impl(move_me)) try 2" << std::endl; + std::cout << "Error in shmset->insert(boost::interprocess::move(move_me)) try 2" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(detail::move_impl(move_me2)) try 2" << std::endl; + std::cout << "Error in shmmultiset->insert(boost::interprocess::move(move_me2)) try 2" << std::endl; return 1; } for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(shmset->begin(), detail::move_impl(move_me)); + shmset->insert(shmset->begin(), boost::interprocess::move(move_me)); stdset->insert(stdset->begin(), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2)); + shmmultiset->insert(shmmultiset->begin(), boost::interprocess::move(move_me2)); stdmultiset->insert(stdmultiset->begin(), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->begin(), detail::move_impl(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->begin(), boost::interprocess::move(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->begin(), boost::interprocess::move(move_me2))" << std::endl; return 1; } IntType move_me3(i); - shmset->insert(shmset->end(), detail::move_impl(move_me3)); + shmset->insert(shmset->end(), boost::interprocess::move(move_me3)); stdset->insert(stdset->end(), i); IntType move_me4(i); - shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4)); + shmmultiset->insert(shmmultiset->end(), boost::interprocess::move(move_me4)); stdmultiset->insert(stdmultiset->end(), i); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->end(), detail::move_impl(move_me3))" << std::endl; + std::cout << "Error in shmset->insert(shmset->end(), boost::interprocess::move(move_me3))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->end(), detail::move_impl(move_me4))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->end(), boost::interprocess::move(move_me4))" << std::endl; return 1; } { IntType move_me(i); - shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me)); + shmset->insert(shmset->upper_bound(move_me), boost::interprocess::move(move_me)); stdset->insert(stdset->upper_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2)); + shmmultiset->insert(shmmultiset->upper_bound(move_me2), boost::interprocess::move(move_me2)); stdmultiset->insert(stdmultiset->upper_bound(i), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), detail::move_impl(move_me))" << std::endl; + std::cout << "Error in shmset->insert(shmset->upper_bound(move_me), boost::interprocess::move(move_me))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->upper_bound(move_me2), boost::interprocess::move(move_me2))" << std::endl; return 1; } } { IntType move_me(i); - shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2)); + shmset->insert(shmset->lower_bound(move_me), boost::interprocess::move(move_me2)); stdset->insert(stdset->lower_bound(i), i); //PrintContainers(shmset, stdset); IntType move_me2(i); - shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2)); + shmmultiset->insert(shmmultiset->lower_bound(move_me2), boost::interprocess::move(move_me2)); stdmultiset->insert(stdmultiset->lower_bound(i), i); //PrintContainers(shmmultiset, stdmultiset); if(!CheckEqualContainers(shmset, stdset)){ - std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmset->insert(shmset->lower_bound(move_me), boost::interprocess::move(move_me2))" << std::endl; return 1; } if(!CheckEqualContainers(shmmultiset, stdmultiset)){ - std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), detail::move_impl(move_me2))" << std::endl; + std::cout << "Error in shmmultiset->insert(shmmultiset->lower_bound(move_me2), boost::interprocess::move(move_me2))" << std::endl; return 1; } } @@ -392,9 +392,9 @@ int set_test () for(j = 0; j < 3; ++j) for(i = 0; i < 100; ++i){ IntType move_me(i); - shmset->insert(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(move_me2)); IntType count_me(i); if(shmset->count(count_me) != typename MyShmMultiSet::size_type(1)){ std::cout << "Error in shmset->count(count_me)" << std::endl; @@ -461,10 +461,10 @@ int set_test_copyable () int i; for(i = 0; i < max; ++i){ IntType move_me(i); - shmset->insert(detail::move_impl(move_me)); + shmset->insert(boost::interprocess::move(move_me)); stdset->insert(i); IntType move_me2(i); - shmmultiset->insert(detail::move_impl(move_me2)); + shmmultiset->insert(boost::interprocess::move(move_me2)); stdmultiset->insert(i); } if(!CheckEqualContainers(shmset, stdset)) return 1; diff --git a/test/shared_memory_mapping_test.cpp b/test/shared_memory_mapping_test.cpp index 6f363f3..d424017 100644 --- a/test/shared_memory_mapping_test.cpp +++ b/test/shared_memory_mapping_test.cpp @@ -19,6 +19,12 @@ using namespace boost::interprocess; +shared_memory_object get_shared_memory_mapping() +{ + shared_memory_object sh; + return shared_memory_object(boost::interprocess::move(sh)); +} + int main () { try{ @@ -139,9 +145,10 @@ int main () { //Now test move semantics shared_memory_object mapping(open_only, test::get_process_id_name(), read_write); - shared_memory_object move_ctor(detail::move_impl(mapping)); + shared_memory_object move_ctor(boost::interprocess::move(mapping)); shared_memory_object move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); + shared_memory_object ret(get_shared_memory_mapping()); } } catch(std::exception &exc){ @@ -152,5 +159,3 @@ int main () shared_memory_object::remove(test::get_process_id_name()); return 0; } - -#include diff --git a/test/shared_memory_test.cpp b/test/shared_memory_test.cpp index 976a4a2..8f99380 100644 --- a/test/shared_memory_test.cpp +++ b/test/shared_memory_test.cpp @@ -31,13 +31,14 @@ struct eraser } }; +typedef detail::managed_open_or_create_impl shared_memory; + //This wrapper is necessary to have a common constructor //in generic named_creation_template functions class shared_memory_creation_test_wrapper : public eraser - , public detail::managed_open_or_create_impl + , public shared_memory { - typedef detail::managed_open_or_create_impl shared_memory; public: shared_memory_creation_test_wrapper(create_only_t) @@ -56,8 +57,6 @@ class shared_memory_creation_test_wrapper int main () { - typedef detail::managed_open_or_create_impl shared_memory; - try{ shared_memory_object::remove(ShmName); test::test_named_creation(); @@ -76,9 +75,9 @@ int main () std::memset(shm1.get_user_address(), 0, shm1.get_user_size()); //Now test move semantics - shared_memory move_ctor(detail::move_impl(shm1)); + shared_memory move_ctor(boost::interprocess::move(shm1)); shared_memory move_assign; - move_assign = detail::move_impl(move_ctor); + move_assign = boost::interprocess::move(move_ctor); } } catch(std::exception &ex){ diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index 38c08d1..877a00e 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -25,6 +25,10 @@ #include #include "get_process_id_name.hpp" + +#include +#include + using namespace boost::interprocess; class base_class @@ -613,7 +617,6 @@ void test_alias() shared_memory_object::remove(process_name.c_str()); } - int main() { if(0 != simple_test()) @@ -626,8 +629,7 @@ int main() return 1; test_alias(); - - return 0; } #include + diff --git a/test/slist_test.cpp b/test/slist_test.cpp index 5944f35..a184eba 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include @@ -54,10 +53,9 @@ int main () { //Now test move semantics slist original; - slist move_ctor(detail::move_impl(original)); + slist move_ctor(boost::interprocess::move(original)); slist move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } @@ -79,8 +77,7 @@ int main () if(!boost::interprocess::test::test_emplace < slist, Options>()) return 1; - - return 0; } #include + diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp new file mode 100644 index 0000000..5df1ef3 --- /dev/null +++ b/test/stable_vector_test.cpp @@ -0,0 +1,90 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-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. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "allocator_v1.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" +#include "expand_bwd_test_allocator.hpp" +#include "expand_bwd_test_template.hpp" +#include "dummy_test_allocator.hpp" +#include "vector_test.hpp" + +using namespace boost::interprocess; + +//Explicit instantiation to detect compilation errors +//template class stable_vector >; + +class recursive_vector +{ + public: + int id_; + stable_vector vector_; +}; + +void recursive_vector_test()//Test for recursive types +{ + stable_vector recursive_vector_vector; +} + +int main() +{ + recursive_vector_test(); + { + //Now test move semantics + stable_vector original; + stable_vector move_ctor(boost::interprocess::move(original)); + stable_vector move_assign; + move_assign = boost::interprocess::move(move_ctor); + move_assign.swap(original); + } + typedef allocator ShmemAllocator; + typedef stable_vector MyVector; + + typedef test::allocator_v1 ShmemV1Allocator; + typedef stable_vector MyV1Vector; + + typedef allocator ShmemMoveAllocator; + typedef stable_vector MyMoveVector; + + typedef allocator ShmemCopyMoveAllocator; + typedef stable_vector MyCopyMoveVector; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + + if(test::vector_test()) + return 1; + + const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE); + if(!boost::interprocess::test::test_emplace + < stable_vector, Options>()) + return 1; + + return 0; +} + +#include diff --git a/test/string_test.cpp b/test/string_test.cpp index 62318bb..747900b 100644 --- a/test/string_test.cpp +++ b/test/string_test.cpp @@ -127,7 +127,7 @@ int string_test() std::sprintf(buffer, "%i", i); auxShmString += buffer; auxStdString += buffer; - shmStringVect->push_back(detail::move_impl(auxShmString)); + shmStringVect->push_back(boost::interprocess::move(auxShmString)); stdStringVect->push_back(auxStdString); } @@ -157,7 +157,7 @@ int string_test() std::sprintf(buffer, "%i", i); auxShmString += buffer; auxStdString += buffer; - shmStringVect->insert(shmStringVect->begin(), detail::move_impl(auxShmString)); + shmStringVect->insert(shmStringVect->begin(), boost::interprocess::move(auxShmString)); stdStringVect->insert(stdStringVect->begin(), auxStdString); } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index 21b4668..ff60dce 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -7,7 +7,6 @@ // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// - #include #include #include @@ -33,32 +32,7 @@ /////////////////////////////////////////////////////////////////// using namespace boost::interprocess; -/* -//Explicit instantiation to detect compilation errors -template class boost::interprocess::set - - ,test::dummy_test_allocator >; -template class boost::interprocess::map - - ,test::dummy_test_allocator > >; - -template class boost::interprocess::multiset - - ,test::dummy_test_allocator >; - -template class boost::interprocess::multimap - - ,test::dummy_test_allocator > >; -*/ //Customize managed_shared_memory class typedef basic_managed_shared_memory -void test_move_semantics() +void test_move() { //Now test move semantics C original; - C move_ctor(detail::move_impl(original)); + C move_ctor(boost::interprocess::move(original)); C move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } @@ -181,10 +154,10 @@ int main () } //Now test move semantics { - test_move_semantics >(); - test_move_semantics >(); - test_move_semantics >(); - test_move_semantics >(); + test_move >(); + test_move >(); + test_move >(); + test_move >(); } using namespace boost::interprocess::detail; @@ -221,6 +194,7 @@ int main () return 1; } + if (0 != test::map_test, MapOptions>()) return 1; + return 0; } diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp index be43789..35d63bb 100644 --- a/test/unique_ptr_test.cpp +++ b/test/unique_ptr_test.cpp @@ -70,14 +70,14 @@ int main() //Test some copy constructors my_unique_ptr_class my_ptr3(0, segment.get_deleter()); - my_unique_ptr_class my_ptr4(detail::move_impl(my_ptr3)); + my_unique_ptr_class my_ptr4(boost::interprocess::move(my_ptr3)); //Construct a list and fill MyList list(segment.get_segment_manager()); //Insert from my_unique_ptr_class - list.push_front(detail::move_impl(my_ptr)); - list.push_back(detail::move_impl(my_ptr2)); + list.push_front(boost::interprocess::move(my_ptr)); + list.push_back(boost::interprocess::move(my_ptr2)); //Check pointers assert(my_ptr.get() == 0); @@ -85,20 +85,13 @@ int main() assert(list.begin()->get() == ptr1); assert(list.rbegin()->get() == ptr2); - //MyList list2(detail::move_impl(list)); - //list2.swap(detail::move_impl(MyList(segment.get_segment_manager()))); - //list.swap(detail::move_impl(MyList(segment.get_segment_manager()))); - - assert(list.begin()->get() == ptr1); - assert(list.rbegin()->get() == ptr2); - //Construct a set and fill typedef std::less set_less_t; MySet set(set_less_t(), segment.get_segment_manager()); //Insert in set from list passing ownership - set.insert(detail::move_impl(*list.begin())); - set.insert(detail::move_impl(*list.rbegin())); + set.insert(boost::interprocess::move(*list.begin())); + set.insert(boost::interprocess::move(*list.rbegin())); //Check pointers assert(list.begin()->get() == 0); @@ -120,12 +113,12 @@ int main() //Insert from my_unique_ptr_class if(ptr1 < ptr2){ - vector.insert(vector.begin(), detail::move_impl(*set.begin())); - vector.insert(vector.end(), detail::move_impl(*set.rbegin())); + vector.insert(vector.begin(), boost::interprocess::move(*set.begin())); + vector.insert(vector.end(), boost::interprocess::move(*set.rbegin())); } else{ - vector.insert(vector.begin(), detail::move_impl(*set.rbegin())); - vector.insert(vector.end(), detail::move_impl(*set.begin())); + vector.insert(vector.begin(), boost::interprocess::move(*set.rbegin())); + vector.insert(vector.end(), boost::interprocess::move(*set.begin())); } //Check pointers @@ -134,14 +127,14 @@ int main() assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); - MyVector vector2(detail::move_impl(vector)); + MyVector vector2(boost::interprocess::move(vector)); vector2.swap(vector); assert(vector.begin()->get() == ptr1); assert(vector.rbegin()->get() == ptr2); my_unique_ptr_class a(0, segment.get_deleter()), b(0, segment.get_deleter()); - a = detail::move_impl(b); + a = boost::interprocess::move(b); } shared_memory_object::remove(process_name.c_str()); return 0; diff --git a/test/upgradable_mutex_test.cpp b/test/upgradable_mutex_test.cpp index 846743a..238196b 100644 --- a/test/upgradable_mutex_test.cpp +++ b/test/upgradable_mutex_test.cpp @@ -35,135 +35,135 @@ int main () //Conversions to scoped_lock { scoped_lock lock(mut); - scoped_lock e_lock(detail::move_impl(lock)); - lock.swap(detail::move_impl(e_lock)); + scoped_lock e_lock(boost::interprocess::move(lock)); + lock.swap(e_lock); } { scoped_lock lock(mut); scoped_lock e_lock(mut2); - e_lock = detail::move_impl(lock); + e_lock = boost::interprocess::move(lock); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() - scoped_lock e_lock(detail::move_impl(u_lock)); + scoped_lock e_lock(boost::interprocess::move(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(detail::move_impl(u_lock)); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(u_lock)); + e_lock = boost::interprocess::move(moved); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() - scoped_lock e_lock(detail::move_impl(u_lock), try_to_lock); + scoped_lock e_lock(boost::interprocess::move(u_lock), try_to_lock); } { upgradable_lock u_lock(mut); //This calls try_unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(detail::move_impl(u_lock), try_to_lock); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(u_lock), try_to_lock); + e_lock = boost::interprocess::move(moved); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock u_lock(mut); //This calls timed_unlock_upgradable_and_lock() - scoped_lock e_lock(detail::move_impl(u_lock), t); + scoped_lock e_lock(boost::interprocess::move(u_lock), t); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock u_lock(mut); //This calls timed_unlock_upgradable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(detail::move_impl(u_lock), t); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(u_lock), t); + e_lock = boost::interprocess::move(moved); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() - scoped_lock e_lock(detail::move_impl(s_lock), try_to_lock); + scoped_lock e_lock(boost::interprocess::move(s_lock), try_to_lock); } { sharable_lock s_lock(mut); //This calls try_unlock_sharable_and_lock() scoped_lock e_lock(mut2); - scoped_lock moved(detail::move_impl(s_lock), try_to_lock); - e_lock = detail::move_impl(moved); + scoped_lock moved(boost::interprocess::move(s_lock), try_to_lock); + e_lock = boost::interprocess::move(moved); } //Conversions to upgradable_lock { upgradable_lock lock(mut); - upgradable_lock u_lock(detail::move_impl(lock)); - lock.swap(detail::move_impl(u_lock)); + upgradable_lock u_lock(boost::interprocess::move(lock)); + lock.swap(u_lock); } { upgradable_lock lock(mut); upgradable_lock u_lock(mut2); - upgradable_lock moved(detail::move_impl(lock)); - u_lock = detail::move_impl(moved); + upgradable_lock moved(boost::interprocess::move(lock)); + u_lock = boost::interprocess::move(moved); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() - upgradable_lock u_lock(detail::move_impl(s_lock), try_to_lock); + upgradable_lock u_lock(boost::interprocess::move(s_lock), try_to_lock); } { sharable_lock s_lock(mut); //This calls unlock_sharable_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(detail::move_impl(s_lock), try_to_lock); - u_lock = detail::move_impl(moved); + upgradable_lock moved(boost::interprocess::move(s_lock), try_to_lock); + u_lock = boost::interprocess::move(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() - upgradable_lock u_lock(detail::move_impl(e_lock)); + upgradable_lock u_lock(boost::interprocess::move(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_upgradable() upgradable_lock u_lock(mut2); - upgradable_lock moved(detail::move_impl(e_lock)); - u_lock = detail::move_impl(moved); + upgradable_lock moved(boost::interprocess::move(e_lock)); + u_lock = boost::interprocess::move(moved); } //Conversions to sharable_lock { sharable_lock lock(mut); - sharable_lock s_lock(detail::move_impl(lock)); - lock.swap(detail::move_impl(s_lock)); + sharable_lock s_lock(boost::interprocess::move(lock)); + lock.swap(s_lock); } { sharable_lock lock(mut); sharable_lock s_lock(mut2); - sharable_lock moved(detail::move_impl(lock)); - s_lock = detail::move_impl(moved); + sharable_lock moved(boost::interprocess::move(lock)); + s_lock = boost::interprocess::move(moved); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() - sharable_lock s_lock(detail::move_impl(u_lock)); + sharable_lock s_lock(boost::interprocess::move(u_lock)); } { upgradable_lock u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(detail::move_impl(u_lock)); - s_lock = detail::move_impl(moved); + sharable_lock moved(boost::interprocess::move(u_lock)); + s_lock = boost::interprocess::move(moved); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() - sharable_lock s_lock(detail::move_impl(e_lock)); + sharable_lock s_lock(boost::interprocess::move(e_lock)); } { scoped_lock e_lock(mut); //This calls unlock_and_lock_sharable() sharable_lock s_lock(mut2); - sharable_lock moved(detail::move_impl(e_lock)); - s_lock = detail::move_impl(moved); + sharable_lock moved(boost::interprocess::move(e_lock)); + s_lock = boost::interprocess::move(moved); } } diff --git a/test/user_buffer_test.cpp b/test/user_buffer_test.cpp index fdcab2d..13e7b0a 100644 --- a/test/user_buffer_test.cpp +++ b/test/user_buffer_test.cpp @@ -59,19 +59,17 @@ int main () { //Now test move semantics managed_heap_memory original(memsize); - managed_heap_memory move_ctor(detail::move_impl(original)); + managed_heap_memory move_ctor(boost::interprocess::move(original)); managed_heap_memory move_assign; - move_assign = detail::move_impl(move_ctor); - original.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); original.swap(move_assign); } { //Now test move semantics managed_external_buffer original(create_only, static_buffer, memsize); - managed_external_buffer move_ctor(detail::move_impl(original)); + managed_external_buffer move_ctor(boost::interprocess::move(original)); managed_external_buffer move_assign; - move_assign = detail::move_impl(move_ctor); - original.swap(detail::move_impl(move_assign)); + move_assign = boost::interprocess::move(move_ctor); original.swap(move_assign); } @@ -84,13 +82,13 @@ int main () //Test move semantics { wmanaged_external_buffer user_default; - wmanaged_external_buffer temp_external(detail::move_impl(user_buffer)); - user_default = detail::move_impl(temp_external); - user_buffer = detail::move_impl(user_default); + wmanaged_external_buffer temp_external(boost::interprocess::move(user_buffer)); + user_default = boost::interprocess::move(temp_external); + user_buffer = boost::interprocess::move(user_default); wmanaged_heap_memory heap_default; - wmanaged_heap_memory temp_heap(detail::move_impl(heap_buffer)); - heap_default = detail::move_impl(temp_heap); - heap_buffer = detail::move_impl(heap_default); + wmanaged_heap_memory temp_heap(boost::interprocess::move(heap_buffer)); + heap_default = boost::interprocess::move(temp_heap); + heap_buffer = boost::interprocess::move(heap_default); } //Initialize memory diff --git a/test/vector_test.cpp b/test/vector_test.cpp index afb1e12..d78974f 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -44,16 +44,7 @@ int test_expand_bwd() if(!test::test_all_expand_bwd()) return 1; -/* - //First raw volatile ints - typedef test::expand_bwd_test_allocator - volatile_int_allocator_type; - typedef vector - volatile_int_vector; - if(!test::test_all_expand_bwd()) - return 1; -*/ //Now user defined wrapped int typedef test::expand_bwd_test_allocator int_holder_allocator_type; @@ -94,17 +85,16 @@ int main() { //Now test move semantics vector original; - vector move_ctor(detail::move_impl(original)); + vector move_ctor(boost::interprocess::move(original)); vector move_assign; - move_assign = detail::move_impl(move_ctor); - move_assign.swap(detail::move_impl(original)); + move_assign = boost::interprocess::move(move_ctor); move_assign.swap(original); } typedef allocator ShmemAllocator; typedef vector MyVector; - //typedef allocator ShmemVolatileAllocator; - //typedef vector MyVolatileVector; + typedef test::allocator_v1 ShmemV1Allocator; + typedef vector MyV1Vector; typedef allocator ShmemMoveAllocator; typedef vector MyMoveVector; @@ -115,8 +105,8 @@ int main() if(test::vector_test()) return 1; - //if(test::vector_test()) - //return 1; + if(test::vector_test()) + return 1; if(test::vector_test()) return 1; diff --git a/test/vector_test.hpp b/test/vector_test.hpp index dd3e46f..e4c891d 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -17,8 +17,8 @@ #include #include -#include #include +#include #include "print_container.hpp" #include "check_equal_containers.hpp" #include "movable_int.hpp" @@ -32,14 +32,14 @@ namespace interprocess{ namespace test{ template -bool copyable_only(V1 *, V2 *, detail::false_type) +bool copyable_only(V1 *, V2 *, boost::interprocess::detail::false_type) { return true; } //Function to check if both sets are equal template -bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) +bool copyable_only(V1 *shmvector, V2 *stdvector, boost::interprocess::detail::true_type) { typedef typename V1::value_type IntType; std::size_t size = shmvector->size(); @@ -50,18 +50,18 @@ bool copyable_only(V1 *shmvector, V2 *stdvector, detail::true_type) { IntType move_me(1); stdvector->insert(stdvector->begin()+size/2, 50, 1); - shmvector->insert(shmvector->begin()+size/2, 50, detail::move_impl(move_me)); + shmvector->insert(shmvector->begin()+size/2, 50, boost::interprocess::move(move_me)); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(2); - shmvector->assign(shmvector->size()/2, detail::move_impl(move_me)); + shmvector->assign(shmvector->size()/2, boost::interprocess::move(move_me)); stdvector->assign(stdvector->size()/2, 2); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } { IntType move_me(3); - shmvector->assign(shmvector->size()*3-1, detail::move_impl(move_me)); + shmvector->assign(shmvector->size()*3-1, boost::interprocess::move(move_me)); stdvector->assign(stdvector->size()*3-1, 3); if(!test::CheckEqualContainers(shmvector, stdvector)) return false; } @@ -111,8 +111,9 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType new_int(i); - shmvector->insert(shmvector->end(), detail::move_impl(new_int)); + shmvector->insert(shmvector->end(), boost::interprocess::move(new_int)); stdvector->insert(stdvector->end(), i); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -133,7 +134,8 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = detail::move_impl(new_int); + BOOST_STATIC_ASSERT((boost::interprocess::is_movable::value == true)); + aux_vect[i] = boost::interprocess::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ @@ -141,8 +143,8 @@ int vector_test() } shmvector->insert(shmvector->end() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stdvector->insert(stdvector->end(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -156,15 +158,15 @@ int vector_test() IntType aux_vect[50]; for(int i = 0; i < 50; ++i){ IntType new_int(-1); - aux_vect[i] = detail::move_impl(new_int); + aux_vect[i] = boost::interprocess::move(new_int); } int aux_vect2[50]; for(int i = 0; i < 50; ++i){ aux_vect2[i] = -1; } shmvector->insert(shmvector->begin() - ,detail::make_move_iterator(&aux_vect[0]) - ,detail::make_move_iterator(aux_vect + 50)); + ,boost::interprocess::make_move_iterator(&aux_vect[0]) + ,boost::interprocess::make_move_iterator(aux_vect + 50)); stdvector->insert(stdvector->begin(), aux_vect2, aux_vect2 + 50); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; } @@ -174,7 +176,7 @@ int vector_test() if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; IntType push_back_this(1); - shmvector->push_back(detail::move_impl(push_back_this)); + shmvector->push_back(boost::interprocess::move(push_back_this)); stdvector->push_back(int(1)); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -189,7 +191,7 @@ int vector_test() for(int i = 0; i < max; ++i){ IntType insert_this(i); - shmvector->insert(shmvector->begin(), detail::move_impl(insert_this)); + shmvector->insert(shmvector->begin(), boost::interprocess::move(insert_this)); stdvector->insert(stdvector->begin(), i); } if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; @@ -204,6 +206,18 @@ int vector_test() stdvector->assign(l.begin(), l.end()); if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; } +/* + std::size_t cap = shmvector->capacity(); + shmvector->reserve(cap*2); + stdvector->reserve(cap*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->resize(0); + stdvector->resize(0); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; + shmvector->resize(cap*2); + stdvector->resize(cap*2); + if(!test::CheckEqualContainers(shmvector, stdvector)) return 1; +*/ delete stdvector; segment.template destroy("MyShmVector"); diff --git a/test/windows_shared_memory_mapping_test.cpp b/test/windows_shared_memory_mapping_test.cpp index 8bd4f10..0135367 100644 --- a/test/windows_shared_memory_mapping_test.cpp +++ b/test/windows_shared_memory_mapping_test.cpp @@ -10,7 +10,7 @@ #include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS #include #include diff --git a/test/windows_shared_memory_test.cpp b/test/windows_shared_memory_test.cpp index 2f8512e..ae5ac7f 100644 --- a/test/windows_shared_memory_test.cpp +++ b/test/windows_shared_memory_test.cpp @@ -11,7 +11,7 @@ #include #include -#ifdef BOOST_WINDOWS +#ifdef BOOST_INTERPROCESS_WINDOWS #include #include @@ -32,16 +32,14 @@ static const char *name_initialization_routine() } static const std::size_t ShmSize = 1000; +typedef detail::managed_open_or_create_impl + windows_shared_memory_t; //This wrapper is necessary to have a common constructor //in generic named_creation_template functions class shared_memory_creation_test_wrapper - : public detail::managed_open_or_create_impl - + : public windows_shared_memory_t { - typedef detail::managed_open_or_create_impl - windows_shared_memory_t; - public: shared_memory_creation_test_wrapper(create_only_t) : windows_shared_memory_t(create_only, name_initialization_routine(), ShmSize) @@ -59,8 +57,6 @@ class shared_memory_creation_test_wrapper int main () { - typedef detail::managed_open_or_create_impl windows_shared_memory_t; - try{ test::test_named_creation(); } @@ -79,6 +75,6 @@ int main() return 0; } -#endif //#ifdef BOOST_WINDOWS +#endif //#ifdef BOOST_INTERPROCESS_WINDOWS #include From 4a9ce29e69b810ec8d6027759cd0a7d1d857eb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 25 Mar 2009 17:26:33 +0000 Subject: [PATCH 72/77] Changes for Boost.1.39 [SVN r51969] --- .../interprocess/containers/container/detail/algorithms.hpp | 4 ++-- .../boost/interprocess/containers/container/stable_vector.hpp | 1 + include/boost/interprocess/detail/move.hpp | 2 -- include/boost/interprocess/sync/named_condition.hpp | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/boost/interprocess/containers/container/detail/algorithms.hpp b/include/boost/interprocess/containers/container/detail/algorithms.hpp index d3baff3..100ffff 100644 --- a/include/boost/interprocess/containers/container/detail/algorithms.hpp +++ b/include/boost/interprocess/containers/container/detail/algorithms.hpp @@ -68,13 +68,13 @@ inline void construct_in_place(T* dest, InpIt source) #else template inline void construct_in_place(T* dest, InpIt source) -{ new((void*)dest)T(*source); } +{ ::new((void*)dest)T(*source); } #endif template inline void construct_in_place(T *dest, default_construct_iterator) { - new((void*)dest)T(); + ::new((void*)dest)T(); } template diff --git a/include/boost/interprocess/containers/container/stable_vector.hpp b/include/boost/interprocess/containers/container/stable_vector.hpp index 3182dcd..c530226 100644 --- a/include/boost/interprocess/containers/container/stable_vector.hpp +++ b/include/boost/interprocess/containers/container/stable_vector.hpp @@ -213,6 +213,7 @@ struct node_type #ifndef BOOST_CONTAINERS_PERFECT_FORWARDING node_type() + : value() {} #define BOOST_PP_LOCAL_MACRO(n) \ diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index 7fcead5..a17637d 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -185,8 +185,6 @@ typename disable_if, const T &>::type #define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ operator boost::interprocess::rv&() \ { return static_cast& >(*this); }\ - operator const boost::interprocess::rv&() \ - { return static_cast& >(*this); }\ // diff --git a/include/boost/interprocess/sync/named_condition.hpp b/include/boost/interprocess/sync/named_condition.hpp index 417bee0..96047ca 100644 --- a/include/boost/interprocess/sync/named_condition.hpp +++ b/include/boost/interprocess/sync/named_condition.hpp @@ -153,7 +153,7 @@ class named_condition void do_wait(Lock& lock) { //named_condition only works with named_mutex - BOOST_STATIC_ASSERT((detail::is_same::value == true)); + BOOST_STATIC_ASSERT((detail::is_convertible::value == true)); //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex()); @@ -170,7 +170,7 @@ class named_condition 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::value == true)); + BOOST_STATIC_ASSERT((detail::is_convertible::value == true)); //lock internal before unlocking external to avoid race with a notifier scoped_lock internal_lock(*this->mutex(), abs_time); if(!internal_lock) return false; From cc1f7f771ac926626b205221ff11e2378886d776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 25 Mar 2009 17:27:03 +0000 Subject: [PATCH 73/77] Changes for Boost.1.39 [SVN r51970] --- proj/conceptgcc/MakeAll | 35 ----------------------------------- proj/cygwin/MakeAll | 33 --------------------------------- proj/linux/MakeAll | 32 -------------------------------- proj/mingw/MakeAll | 35 ----------------------------------- proj/qnx/MakeAll | 33 --------------------------------- 5 files changed, 168 deletions(-) delete mode 100644 proj/conceptgcc/MakeAll delete mode 100644 proj/cygwin/MakeAll delete mode 100644 proj/linux/MakeAll delete mode 100644 proj/mingw/MakeAll delete mode 100644 proj/qnx/MakeAll diff --git a/proj/conceptgcc/MakeAll b/proj/conceptgcc/MakeAll deleted file mode 100644 index 1770e5e..0000000 --- a/proj/conceptgcc/MakeAll +++ /dev/null @@ -1,35 +0,0 @@ - -#ifndef CC -CC=i686-pc-cygwin-conceptg++.exe -#endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/conceptgcc/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSDOC_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSDOC_OUT := $(patsubst ../../example/%.cpp, ../../bin/conceptgcc/ex_%.out, $(INTERPROCESSDOC_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSDOC_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/conceptgcc - -../../bin/conceptgcc/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -../../bin/conceptgcc/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -clean: - rm -f *.o - rm -f ../../bin/conceptgcc/* diff --git a/proj/cygwin/MakeAll b/proj/cygwin/MakeAll deleted file mode 100644 index 72e7b80..0000000 --- a/proj/cygwin/MakeAll +++ /dev/null @@ -1,33 +0,0 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/cygwin/test_%.out, $(INTERPROCESSTEST_CPP)) - -#INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -#INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/cygwin/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSEXAMPLE_OUT) $(INTERPROCESSTEST_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/cygwin - -../../bin/cygwin/test_%.out: ../../test/%.cpp - $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -#../../bin/cygwin/ex_%.out: ../../example/%.cpp -# $(CC) -g $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-gcc-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - - -clean: - rm -f *.o - rm -f ../../bin/cygwin/* diff --git a/proj/linux/MakeAll b/proj/linux/MakeAll deleted file mode 100644 index 9f0962f..0000000 --- a/proj/linux/MakeAll +++ /dev/null @@ -1,32 +0,0 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. -BOOST_LIBS=/usr/local/lib - - -INTERPROCESS_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESS_OUT := $(patsubst ../../test/%.cpp, ../../bin/linux/test_%.out, $(INTERPROCESS_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/linux/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -.PHONY: createdir clean - -all: createdir $(INTERPROCESS_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/linux - -../../bin/linux/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ - -../../bin/linux/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -pedantic -g -pthread -DBOOST_DATE_TIME_NO_LIB -lstdc++ -lrt -lboost_thread-gcc-mt -I$(BOOST_ROOT) -L$(BOOST_LIBS) -o $@ - -clean: - rm -f *.o - rm -f ../../bin/linux/* diff --git a/proj/mingw/MakeAll b/proj/mingw/MakeAll deleted file mode 100644 index 0b23825..0000000 --- a/proj/mingw/MakeAll +++ /dev/null @@ -1,35 +0,0 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/mingw/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/mingw/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -LIBDIR:= ../../../../stage/lib - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/mingw - -../../bin/mingw/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR) -lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -../../bin/mingw/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -L$(LIBDIR)-lboost_thread-mgw-mt -I$(BOOST_ROOT) -lstdc++ -o $@ - -clean: - rm -f *.o - rm -f ../../bin/mingw/* diff --git a/proj/qnx/MakeAll b/proj/qnx/MakeAll deleted file mode 100644 index b98dc49..0000000 --- a/proj/qnx/MakeAll +++ /dev/null @@ -1,33 +0,0 @@ - -ifndef CC -CC=g++ -endif - -BOOST_ROOT=../../../.. - -INTERPROCESS_CPP := $(wildcard ../../src/*.cpp) -INTERPROCESS_OBJ := $(patsubst ../../src/%.cpp, lib_%.o, $(INTERPROCESS_CPP)) - -INTERPROCESSTEST_CPP := $(wildcard ../../test/*.cpp) -INTERPROCESSTEST_OUT := $(patsubst ../../test/%.cpp, ../../bin/qnx/test_%.out, $(INTERPROCESSTEST_CPP)) - -INTERPROCESSEXAMPLE_CPP := $(wildcard ../../example/*.cpp) -INTERPROCESSEXAMPLE_OUT := $(patsubst ../../example/%.cpp, ../../bin/qnx/ex_%.out, $(INTERPROCESSEXAMPLE_CPP)) - -.PHONY: createdir clean - -all: createdir $(INTERPROCESSTEST_OUT) $(INTERPROCESSEXAMPLE_OUT) - @cd . - -createdir: - @mkdir -p ../../bin/qnx - -../../bin/qnx/test_%.out: ../../test/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ - -../../bin/qnx/ex_%.out: ../../example/%.cpp - $(CC) $< -Wall -DBOOST_DATE_TIME_NO_LIB -lboost_thread-gcc-mt-s -I$(BOOST_ROOT) -o $@ - -clean: - rm -f *.o - rm -f ../../bin/qnx/* From 96350307aca75374b179f4aaf2ada38dda1277df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 25 Mar 2009 17:28:06 +0000 Subject: [PATCH 74/77] Changes for Boost.1.39 [SVN r51971] --- proj/vc7ide/doc_contA.vcproj | 138 ---------------------- proj/vc7ide/doc_shared_memory2.vcproj | 138 ---------------------- test/heap_allocator_v1.hpp | 159 ++++++++++++++++++++++++++ test/stable_vector_test.cpp | 7 ++ 4 files changed, 166 insertions(+), 276 deletions(-) delete mode 100644 proj/vc7ide/doc_contA.vcproj delete mode 100644 proj/vc7ide/doc_shared_memory2.vcproj create mode 100644 test/heap_allocator_v1.hpp diff --git a/proj/vc7ide/doc_contA.vcproj b/proj/vc7ide/doc_contA.vcproj deleted file mode 100644 index 7891af8..0000000 --- a/proj/vc7ide/doc_contA.vcproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/proj/vc7ide/doc_shared_memory2.vcproj b/proj/vc7ide/doc_shared_memory2.vcproj deleted file mode 100644 index 4c454cd..0000000 --- a/proj/vc7ide/doc_shared_memory2.vcproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/heap_allocator_v1.hpp b/test/heap_allocator_v1.hpp new file mode 100644 index 0000000..3e83045 --- /dev/null +++ b/test/heap_allocator_v1.hpp @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (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_HEAP_ALLOCATOR_V1_HPP +#define BOOST_INTERPROCESS_HEAP_ALLOCATOR_V1_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file +//!Describes an heap_allocator_v1 that allocates portions of fixed size +//!memory buffer (shared memory, mapped file...) + +namespace boost { +namespace interprocess { +namespace test { + +//!An STL compatible heap_allocator_v1 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 heap_allocator_v1 in shared memory, memory mapped-files, etc...*/ +template +class heap_allocator_v1 +{ + private: + typedef heap_allocator_v1 self_t; + typedef SegmentManager segment_manager; + typedef typename segment_manager::void_pointer aux_pointer_t; + + typedef typename + boost::pointer_to_other + ::type cvoid_ptr; + + typedef typename boost::pointer_to_other + ::type alloc_ptr_t; + + template + heap_allocator_v1& operator=(const heap_allocator_v1&); + + heap_allocator_v1& operator=(const heap_allocator_v1&); + + alloc_ptr_t mp_mngr; + + public: + typedef T value_type; + typedef typename boost::pointer_to_other + ::type pointer; + typedef typename boost:: + pointer_to_other::type const_pointer; + typedef typename detail::add_reference + ::type reference; + typedef typename detail::add_reference + ::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + //!Obtains an heap_allocator_v1 of other type + template + struct rebind + { + typedef heap_allocator_v1 other; + }; + + //!Returns the segment manager. Never throws + segment_manager* get_segment_manager()const + { return detail::get_pointer(mp_mngr); } +/* + //!Returns address of mutable object. Never throws + pointer address(reference value) const + { return pointer(addressof(value)); } + + //!Returns address of non mutable object. Never throws + const_pointer address(const_reference value) const + { return const_pointer(addressof(value)); } +*/ + //!Constructor from the segment manager. Never throws + heap_allocator_v1(segment_manager *segment_mngr) + : mp_mngr(segment_mngr) { } + + //!Constructor from other heap_allocator_v1. Never throws + heap_allocator_v1(const heap_allocator_v1 &other) + : mp_mngr(other.get_segment_manager()){ } + + //!Constructor from related heap_allocator_v1. Never throws + template + heap_allocator_v1(const heap_allocator_v1 &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; return ::new value_type[count]; } + + //!Deallocates memory previously allocated. Never throws + void deallocate(const pointer &ptr, size_type) + { return ::delete[] detail::get_pointer(ptr) ; } + + //!Construct object, calling constructor. + //!Throws if T(const T&) throws + void construct(const pointer &ptr, const_reference value) + { new((void*)detail::get_pointer(ptr)) value_type(value); } + + //!Destroys object. Throws if object's destructor throws + void destroy(const pointer &ptr) + { BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); } + + //!Returns the number of elements that could be allocated. Never throws + size_type max_size() const + { return mp_mngr->get_size(); } + + //!Swap segment manager. Does not throw. If each heap_allocator_v1 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); } +}; + +//!Equality test for same type of heap_allocator_v1 +template inline +bool operator==(const heap_allocator_v1 &alloc1, + const heap_allocator_v1 &alloc2) + { return alloc1.get_segment_manager() == alloc2.get_segment_manager(); } + +//!Inequality test for same type of heap_allocator_v1 +template inline +bool operator!=(const heap_allocator_v1 &alloc1, + const heap_allocator_v1 &alloc2) + { return alloc1.get_segment_manager() != alloc2.get_segment_manager(); } + +} //namespace test { +} //namespace interprocess { +} //namespace boost { + +#include + +#endif //BOOST_INTERPROCESS_HEAP_ALLOCATOR_V1_HPP + diff --git a/test/stable_vector_test.cpp b/test/stable_vector_test.cpp index 5df1ef3..5af0bcf 100644 --- a/test/stable_vector_test.cpp +++ b/test/stable_vector_test.cpp @@ -19,6 +19,7 @@ #include #include #include "allocator_v1.hpp" +#include "heap_allocator_v1.hpp" #include "check_equal_containers.hpp" #include "movable_int.hpp" #include "expand_bwd_test_allocator.hpp" @@ -61,6 +62,9 @@ int main() typedef test::allocator_v1 ShmemV1Allocator; typedef stable_vector MyV1Vector; + typedef test::heap_allocator_v1 ShmemHeapV1Allocator; + typedef stable_vector MyHeapV1Vector; + typedef allocator ShmemMoveAllocator; typedef stable_vector MyMoveVector; @@ -73,6 +77,9 @@ int main() if(test::vector_test()) return 1; + if(test::vector_test()) + return 1; + if(test::vector_test()) return 1; From eceee3234ee0f574706ad0b60df0309606a8ef83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 25 Mar 2009 18:18:04 +0000 Subject: [PATCH 75/77] Changes for Boost.1.39 [SVN r51973] --- doc/interprocess.qbk | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index dc0d29d..fce5e85 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -6525,6 +6525,12 @@ warranty. * Shared memory in windows has now kernel lifetime instead of filesystem lifetime: shared memory will disappear when the system reboots. * Updated move semantics. +* Fixed bugs + [@https://svn.boost.org/trac/boost/ticket/2722 #2722], + [@https://svn.boost.org/trac/boost/ticket/2729 #2729], + [@https://svn.boost.org/trac/boost/ticket/2766 #2766], + [@https://svn.boost.org/trac/boost/ticket/1390 #1390], + [@https://svn.boost.org/trac/boost/ticket/2589 #2589], [endsect] @@ -6534,7 +6540,12 @@ warranty. * More non-copyable classes are now movable. * Move-constructor and assignments now leave moved object in default-constructed state instead of just swapping contents. -* Several bugfixes (#2391, #2431, #1390, #2570, #2528). +* Several bugfixes ( + [@https://svn.boost.org/trac/boost/ticket/2391 #2391], + [@https://svn.boost.org/trac/boost/ticket/2431 #2431], + [@https://svn.boost.org/trac/boost/ticket/1390 #1390], + [@https://svn.boost.org/trac/boost/ticket/2570 #2570], + [@https://svn.boost.org/trac/boost/ticket/2528 #2528]. [endsect] From 12ace1eb5412d3e68d801f618d0ee4fbd7277ab9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 27 Mar 2009 07:36:42 +0000 Subject: [PATCH 76/77] Workaround a doxygen crash. Macports Doxygen 1.5.8 is crashing for me without this change, Ubuntu doxygen 1.5.6 is fine so I assume this is a bug in recent versions. [SVN r52006] --- doc/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index fdae0b2..b6c00e5 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -31,7 +31,7 @@ doxygen autodoc "PREDEFINED=\"BOOST_INTERPROCESS_DOXYGEN_INVOKED\" \\ \"BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(a)= \" \\ \"BOOST_INTERPROCESS_RV_REF(a)=a &&\" \\ - \"BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(a)=a &&\" \\ + \"BOOST_INTERPROCESS_RV_REF_2_TEMPL_ARGS(a,b,c)=a &&\" \\ \"BOOST_INTERPROCESS_RV_REF_3_TEMPL_ARGS(a)=a &&\" \\ \"BOOST_INTERPROCESS_FWD_REF(a)=a &&\"" "boost.doxygen.reftitle=Boost.Interprocess Reference" From 9117f958a4af6f6260a49c63be5864ac25b8cde3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 27 Mar 2009 08:49:56 +0000 Subject: [PATCH 77/77] Change static_cast with reinterpret_cast since in some compilers (Intel, and surely other EDG based ones) this kicks the conversion operator recursively and provokes an stack overflow. [SVN r52007] --- include/boost/interprocess/detail/move.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/interprocess/detail/move.hpp b/include/boost/interprocess/detail/move.hpp index a17637d..9ecd69f 100644 --- a/include/boost/interprocess/detail/move.hpp +++ b/include/boost/interprocess/detail/move.hpp @@ -133,7 +133,7 @@ typename boost::disable_if, T&>::type move(T& x) template typename enable_if, rv&>::type move(T& x) { - return static_cast& >(x); + return reinterpret_cast& >(x); } template @@ -184,7 +184,7 @@ typename disable_if, const T &>::type ////////////////////////////////////////////////////////////////////////////// #define BOOST_INTERPROCESS_ENABLE_MOVE_EMULATION(TYPE)\ operator boost::interprocess::rv&() \ - { return static_cast& >(*this); }\ + { return reinterpret_cast& >(*this); }\ //