diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 5060ca7..75993e0 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -6751,6 +6751,7 @@ thank them: * [@https://svn.boost.org/trac/boost/ticket/9835 Trac #9835 (['"Boost Interprocess fails to compile with Android NDK GCC 4.8, -Werror=unused-variable"])]. * [@https://svn.boost.org/trac/boost/ticket/9911 Trac #9911 (['"get_tmp_base_dir(...) failure"])]. * [@https://svn.boost.org/trac/boost/ticket/9946 Trac #9946 (['"ret_ptr uninitialized in init_atomic_func, fini_atomic_func"])]. + * [@https://svn.boost.org/trac/boost/ticket/10011 Trac #10011 (['"segment_manager::find( unique_instance_t* ) fails to compile"])]. * [@https://svn.boost.org/trac/boost/ticket/10021 Trac #10021 (['"Interprocess and BOOST_USE_WINDOWS_H"])]. * [@https://github.com/boostorg/interprocess/pull/2 GitHub #2] (['"Provide support for the Cray C++ compiler. The Cray compiler defines __GNUC__"]]). * [@https://github.com/boostorg/interprocess/pull/3 GitHub #3] (['"Fix/mingw interprocess_exception throw in file_wrapper::priv_open_or_create"]]). diff --git a/include/boost/interprocess/detail/managed_memory_impl.hpp b/include/boost/interprocess/detail/managed_memory_impl.hpp index 5dd4093..919e535 100644 --- a/include/boost/interprocess/detail/managed_memory_impl.hpp +++ b/include/boost/interprocess/detail/managed_memory_impl.hpp @@ -609,7 +609,7 @@ class basic_managed_memory_impl { mp_header->template destroy_ptr(ptr); } //!Returns the name of an object created with construct/find_or_construct - //!functions. Does not throw + //!functions. If ptr points to an unique instance typeid(T).name() is returned. template static const char_type *get_instance_name(const T *ptr) { return segment_manager::get_instance_name(ptr); } diff --git a/include/boost/interprocess/detail/segment_manager_helper.hpp b/include/boost/interprocess/detail/segment_manager_helper.hpp index 426c2d3..47edbd6 100644 --- a/include/boost/interprocess/detail/segment_manager_helper.hpp +++ b/include/boost/interprocess/detail/segment_manager_helper.hpp @@ -32,6 +32,7 @@ #include //char_traits #include //std::nothrow #include //std::pair +#include //std::iterator_traits #include //BOOST_ASSERT #include //unary_function #ifndef BOOST_NO_EXCEPTIONS @@ -323,6 +324,15 @@ class char_ptr_holder operator const CharType *() { return m_name; } + const CharType *get() const + { return m_name; } + + bool is_unique() const + { return m_name == reinterpret_cast(-1); } + + bool is_anonymous() const + { return m_name == static_cast(0); } + private: const CharType *m_name; }; @@ -472,12 +482,12 @@ class segment_manager_iterator_value_adaptor template struct segment_manager_iterator_transform - : std::unary_function< typename Iterator::value_type + : std::unary_function< typename std::iterator_traits::value_type , segment_manager_iterator_value_adaptor > { typedef segment_manager_iterator_value_adaptor result_type; - result_type operator()(const typename Iterator::value_type &arg) const + result_type operator()(const typename std::iterator_traits::value_type &arg) const { return result_type(arg); } }; diff --git a/include/boost/interprocess/detail/transform_iterator.hpp b/include/boost/interprocess/detail/transform_iterator.hpp index 7db85e5..5496d19 100644 --- a/include/boost/interprocess/detail/transform_iterator.hpp +++ b/include/boost/interprocess/detail/transform_iterator.hpp @@ -61,9 +61,9 @@ template class transform_iterator : public UnaryFunction , public std::iterator - < typename Iterator::iterator_category + < typename std::iterator_traits::iterator_category , typename ipcdetail::remove_reference::type - , typename Iterator::difference_type + , typename std::iterator_traits::difference_type , operator_arrow_proxy , typename UnaryFunction::result_type> { @@ -115,33 +115,33 @@ class transform_iterator 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) + friend typename std::iterator_traits::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) + transform_iterator& operator+=(typename std::iterator_traits::difference_type off) { this->advance(off); return *this; } - transform_iterator operator+(typename Iterator::difference_type off) const + transform_iterator operator+(typename std::iterator_traits::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) + friend transform_iterator operator+(typename std::iterator_traits::difference_type off, const transform_iterator& right) { return right + off; } - transform_iterator& operator-=(typename Iterator::difference_type off) + transform_iterator& operator-=(typename std::iterator_traits::difference_type off) { this->advance(-off); return *this; } - transform_iterator operator-(typename Iterator::difference_type off) const + transform_iterator operator-(typename std::iterator_traits::difference_type off) const { return *this + (-off); } typename UnaryFunction::result_type operator*() const { return dereference(); } - typename UnaryFunction::result_type operator[](typename Iterator::difference_type off) const + typename UnaryFunction::result_type operator[](typename std::iterator_traits::difference_type off) const { return UnaryFunction::operator()(m_it[off]); } operator_arrow_proxy @@ -172,10 +172,10 @@ class transform_iterator typename UnaryFunction::result_type dereference() const { return UnaryFunction::operator()(*m_it); } - void advance(typename Iterator::difference_type n) + void advance(typename std::iterator_traits::difference_type n) { std::advance(m_it, n); } - typename Iterator::difference_type distance_to(const transform_iterator &other)const + typename std::iterator_traits::difference_type distance_to(const transform_iterator &other)const { return std::distance(other.m_it, m_it); } }; diff --git a/include/boost/interprocess/indexes/null_index.hpp b/include/boost/interprocess/indexes/null_index.hpp index 1e1d670..20fa536 100644 --- a/include/boost/interprocess/indexes/null_index.hpp +++ b/include/boost/interprocess/indexes/null_index.hpp @@ -34,8 +34,8 @@ class null_index /// @endcond public: - typedef void * iterator; - typedef const void * const_iterator; + typedef int * iterator; + typedef const int * const_iterator; //!begin() is equal //!to end() diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index ca3d8ba..381edaf 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -188,6 +188,8 @@ class segment_manager_base return ret; } + /// @cond + template std::pair allocation_command (boost::interprocess::allocation_type command, size_type limit_size, @@ -215,6 +217,8 @@ class segment_manager_base return ret; } + /// @endcond + //!Deallocates the bytes allocated with allocate/allocate_many() //!pointed by addr void deallocate (void *addr) @@ -343,19 +347,19 @@ class segment_manager segment_manager(); segment_manager(const segment_manager &); segment_manager &operator=(const segment_manager &); - typedef segment_manager_base Base; + typedef segment_manager_base segment_manager_base_t; /// @endcond public: - typedef MemoryAlgorithm memory_algorithm; - typedef typename Base::void_pointer void_pointer; - typedef typename Base::size_type size_type; - typedef typename Base::difference_type difference_type; - typedef CharType char_type; + typedef MemoryAlgorithm memory_algorithm; + typedef typename segment_manager_base_t::void_pointer void_pointer; + typedef typename segment_manager_base_t::size_type size_type; + typedef typename segment_manager_base_t::difference_type difference_type; + typedef CharType char_type; typedef segment_manager_base segment_manager_base_type; - static const size_type PayloadPerAllocation = Base::PayloadPerAllocation; + static const size_type PayloadPerAllocation = segment_manager_base_t::PayloadPerAllocation; /// @cond private: @@ -379,7 +383,7 @@ class segment_manager ,is_intrusive_index::value> unique_transform; /// @endcond - typedef typename Base::mutex_family mutex_family; + typedef typename segment_manager_base_t::mutex_family mutex_family; typedef transform_iterator const_named_iterator; @@ -409,39 +413,31 @@ class segment_manager //!the segment manager is being constructed. //!Can throw explicit segment_manager(size_type segment_size) - : Base(segment_size, priv_get_reserved_bytes()) - , m_header(static_cast(get_this_pointer())) + : segment_manager_base_t(segment_size, priv_get_reserved_bytes()) + , m_header(static_cast(get_this_pointer())) { (void) anonymous_instance; (void) unique_instance; - BOOST_ASSERT(static_cast(this) == static_cast(static_cast(this))); + //Check EBO is applied, it's required + const void * const this_addr = this; + const void *const segm_addr = static_cast(this); + (void)this_addr; (void)segm_addr; + BOOST_ASSERT( this_addr == segm_addr); } - //!Tries to find a previous named allocation. Returns the address + //!Tries to find a previous named/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 CharType* name) + std::pair find (char_ptr_holder_t name) { 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 ipcdetail::unique_instance_t* name) - { return this->priv_find_impl(name, true); } - - //!Tries to find a previous named allocation. Returns the address + //!Tries to find a previous named/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! + //!Use it only inside atomic_func() calls, where the internal mutex + //!is guaranteed to be locked. 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 ipcdetail::unique_instance_t* name) + std::pair find_no_lock (char_ptr_holder_t name) { return this->priv_find_impl(name, false); } //!Returns throwing "construct" proxy @@ -500,7 +496,7 @@ class segment_manager //!Calls object function blocking recursive interprocess_mutex and guarantees that //!no new named_alloc or destroy will be executed by any process while - //!executing the object function call*/ + //!executing the object function call template void atomic_func(Func &f) { scoped_lock guard(m_header); f(); } @@ -523,28 +519,26 @@ class segment_manager } } - //!Destroys a previously created unique instance. + //!Destroys a previously created named/unique instance. //!Returns false if the object was not present. template - bool destroy(const ipcdetail::unique_instance_t *) + bool destroy(char_ptr_holder_t name) { + BOOST_ASSERT(!name.is_anonymous()); ipcdetail::placement_destroy dtor; - return this->priv_generic_named_destroy - (typeid(T).name(), m_header.m_unique_index, dtor, is_intrusive_t()); - } - //!Destroys the named object with - //!the given name. Returns false if that object can't be found. - template - bool destroy(const CharType *name) - { - ipcdetail::placement_destroy dtor; - return this->priv_generic_named_destroy - (name, m_header.m_named_index, dtor, is_intrusive_t()); + if(name.is_unique()){ + return this->priv_generic_named_destroy + ( typeid(T).name(), m_header.m_unique_index , dtor, is_intrusive_t()); + } + else{ + return this->priv_generic_named_destroy + ( name.get(), m_header.m_named_index, dtor, is_intrusive_t()); + } } //!Destroys an anonymous, unique or named object - //!using it's address + //!using its address template void destroy_ptr(const T *p) { @@ -628,7 +622,7 @@ class segment_manager //!Obtains the minimum size needed by the //!segment manager static size_type get_min_size() - { return Base::get_min_size(priv_get_reserved_bytes()); } + { return segment_manager_base_t::get_min_size(priv_get_reserved_bytes()); } //!Returns a constant iterator to the beginning of the information about //!the named allocations performed in this segment manager @@ -685,8 +679,8 @@ class segment_manager typedef boost::interprocess::deleter type; }; - //!Returns an instance of the default allocator for type T - //!initialized that allocates memory from this segment manager. + //!Returns an instance of the default deleter for type T + //!that will delete an object constructed in this segment manager. template typename deleter::type get_deleter() @@ -742,11 +736,8 @@ class segment_manager return std::pair(static_cast(ret), size); } - void *priv_generic_construct(const CharType *name, - size_type num, - bool try2find, - bool dothrow, - ipcdetail::in_place_interface &table) + void *priv_generic_construct + (const CharType *name, size_type num, bool try2find, bool dothrow, ipcdetail::in_place_interface &table) { void *ret; //Security overflow check @@ -800,7 +791,7 @@ class segment_manager static const CharType *priv_get_instance_name(block_header_t *ctrl_data) { boost::interprocess::allocation_type type = ctrl_data->alloc_type(); - if(type != named_type){ + if(type == anonymous_type){ BOOST_ASSERT((type == anonymous_type && ctrl_data->m_num_char == 0) || (type == unique_type && ctrl_data->m_num_char != 0) ); return 0; @@ -832,8 +823,8 @@ class segment_manager static size_type priv_get_reserved_bytes() { //Get the number of bytes until the end of (*this) - //beginning in the end of the Base base. - return sizeof(segment_manager) - sizeof(Base); + //beginning in the end of the segment_manager_base_t base. + return sizeof(segment_manager) - sizeof(segment_manager_base_t); } template @@ -841,9 +832,7 @@ class segment_manager (const CharT* name, IndexType > &index, ipcdetail::in_place_interface &table, - size_type &length, - ipcdetail::true_ is_intrusive, - bool use_lock) + size_type &length, ipcdetail::true_ is_intrusive, bool use_lock) { (void)is_intrusive; typedef IndexType > index_type; @@ -880,9 +869,7 @@ class segment_manager (const CharT* name, IndexType > &index, ipcdetail::in_place_interface &table, - size_type &length, - ipcdetail::false_ is_intrusive, - bool use_lock) + size_type &length, ipcdetail::false_ is_intrusive, bool use_lock) { (void)is_intrusive; typedef IndexType > index_type; @@ -918,8 +905,7 @@ class segment_manager bool priv_generic_named_destroy (block_header_t *block_header, IndexType > &index, - ipcdetail::in_place_interface &table, - ipcdetail::true_ is_node_index) + ipcdetail::in_place_interface &table, ipcdetail::true_ is_node_index) { (void)is_node_index; typedef typename IndexType >::iterator index_it; @@ -943,8 +929,7 @@ class segment_manager template bool priv_generic_named_destroy(const CharT *name, IndexType > &index, - ipcdetail::in_place_interface &table, - ipcdetail::true_ is_intrusive_index) + ipcdetail::in_place_interface &table, ipcdetail::true_ is_intrusive_index) { (void)is_intrusive_index; typedef IndexType > index_type; @@ -1060,21 +1045,17 @@ class segment_manager } //Call destructors and free memory - std::size_t destroyed; + std::size_t destroyed; table.destroy_n(values, num, destroyed); this->deallocate(memory); return true; } template - void * priv_generic_named_construct(unsigned char type, - const CharT *name, - size_type num, - bool try2find, - bool dothrow, - ipcdetail::in_place_interface &table, - IndexType > &index, - ipcdetail::true_ is_intrusive) + void * priv_generic_named_construct + (unsigned char type, const CharT *name, size_type num, bool try2find, + bool dothrow, ipcdetail::in_place_interface &table, + IndexType > &index, ipcdetail::true_ is_intrusive) { (void)is_intrusive; std::size_t namelen = std::char_traits::length(name); @@ -1196,14 +1177,10 @@ class segment_manager //!Generic named new function for //!named functions template - void * priv_generic_named_construct(unsigned char type, - const CharT *name, - size_type num, - bool try2find, - bool dothrow, - ipcdetail::in_place_interface &table, - IndexType > &index, - ipcdetail::false_ is_intrusive) + void * priv_generic_named_construct + (unsigned char type, const CharT *name, size_type num, bool try2find, bool dothrow, + ipcdetail::in_place_interface &table, + IndexType > &index, ipcdetail::false_ is_intrusive) { (void)is_intrusive; std::size_t namelen = std::char_traits::length(name); @@ -1346,9 +1323,9 @@ class segment_manager named_index_t m_named_index; unique_index_t m_unique_index; - header_t(Base *restricted_segment_mngr) - : m_named_index (restricted_segment_mngr) - , m_unique_index(restricted_segment_mngr) + header_t(segment_manager_base_t *segment_mngr_base) + : m_named_index (segment_mngr_base) + , m_unique_index(segment_mngr_base) {} } m_header; diff --git a/proj/vc7ide/Interprocess.sln b/proj/vc7ide/Interprocess.sln index 758d3d5..6b570a4 100644 --- a/proj/vc7ide/Interprocess.sln +++ b/proj/vc7ide/Interprocess.sln @@ -483,6 +483,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boost_use_windows_h", "boos ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segment_manager_test", "segment_manager_test.vcproj", "{56CE18C9-0000-0000-0000-000000000000}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -975,6 +979,10 @@ Global {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 + {56CE18C9-0000-0000-0000-000000000000}.Debug.ActiveCfg = Debug|Win32 + {56CE18C9-0000-0000-0000-000000000000}.Debug.Build.0 = Debug|Win32 + {56CE18C9-0000-0000-0000-000000000000}.Release.ActiveCfg = Release|Win32 + {56CE18C9-0000-0000-0000-000000000000}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/segment_manager_test.vcproj b/proj/vc7ide/segment_manager_test.vcproj new file mode 100644 index 0000000..cfdcdc9 --- /dev/null +++ b/proj/vc7ide/segment_manager_test.vcproj @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/segment_manager_test.cpp b/test/segment_manager_test.cpp new file mode 100644 index 0000000..cc8ba7a --- /dev/null +++ b/test/segment_manager_test.cpp @@ -0,0 +1,457 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "get_process_id_name.hpp" +#include +#include +#include + +using namespace boost::interprocess; + +template +struct atomic_func_test +{ + SegmentManager &rsm; + int *object; + + atomic_func_test(SegmentManager &sm) + : rsm(sm), object() + {} + + void operator()() + { + object = rsm.template find("atomic_func_find_object").first; + } +}; + +template +bool test_segment_manager() +{ + typedef typename SegmentManager::size_type size_type; + const unsigned int ShmSizeSize = 1024*64u; + std::string shmname(test::get_process_id_name()); + + shared_memory_object::remove(shmname.c_str()); + shared_memory_object sh_mem( create_only, shmname.c_str(), read_write ); + sh_mem.truncate( ShmSizeSize ); + mapped_region mapping( sh_mem, read_write ); + + SegmentManager* seg_mgr = new( mapping.get_address() ) SegmentManager( ShmSizeSize ); + std::size_t free_mem_before = seg_mgr->get_free_memory(); + std::size_t size_before = seg_mgr->get_size(); + + if(size_before != ShmSizeSize) + return false; + if(!seg_mgr->all_memory_deallocated()) + return false; + if(seg_mgr->get_min_size() >= ShmSizeSize) + return false; + + {//test get_free_memory() / allocate()/deallocate() + const size_type Size = ShmSizeSize/2; + void *mem = seg_mgr->allocate(Size+1); + const size_type free_mem = seg_mgr->get_free_memory(); + if(free_mem >= Size) + return false; + if(seg_mgr->all_memory_deallocated()) + return false; + const size_type Size2 = free_mem/2; + void *mem2 = seg_mgr->allocate(size_type(Size2+1), std::nothrow); + if(seg_mgr->get_free_memory() >= Size2) + return false; + if(seg_mgr->size(mem) < (Size+1)) + return false; + if(seg_mgr->size(mem2) < (Size2+1)) + return false; + seg_mgr->deallocate(mem); + seg_mgr->deallocate(mem2); + if(!seg_mgr->all_memory_deallocated()) + return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + try{ seg_mgr->allocate(ShmSizeSize*2); }catch(interprocess_exception&){} + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(seg_mgr->allocate(ShmSizeSize*2, std::nothrow)) + return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + } + {//test allocate_aligned + const std::size_t Alignment = 128u; + void *mem = seg_mgr->allocate_aligned(ShmSizeSize/4, Alignment); + if(seg_mgr->all_memory_deallocated()) + return false; + std::size_t offset = static_cast + (static_cast(mem) - static_cast(mapping.get_address())); + if(offset & (Alignment-1)) + return false; + void *mem2 = seg_mgr->allocate_aligned(ShmSizeSize/4, Alignment, std::nothrow); + std::size_t offset2 = static_cast + (static_cast(mem2) - static_cast(mapping.get_address())); + if(offset2 & (Alignment-1)) + return false; + seg_mgr->deallocate(mem); + seg_mgr->deallocate(mem2); + if(!seg_mgr->all_memory_deallocated()) + return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + try{ seg_mgr->allocate_aligned(ShmSizeSize*2, Alignment); }catch(interprocess_exception&){} + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(seg_mgr->allocate_aligned(ShmSizeSize*2, Alignment, std::nothrow)) + return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + } + {//test shrink_to_fit + + seg_mgr->shrink_to_fit(); + if(!seg_mgr->all_memory_deallocated()) + return false; + std::size_t empty_shrunk_size = seg_mgr->get_size(); + std::size_t empty_shrunk_free_mem = seg_mgr->get_free_memory(); + if(empty_shrunk_size >= size_before) + return false; + if(empty_shrunk_free_mem >= size_before) + return false; + seg_mgr->grow(size_type(size_before - empty_shrunk_size)); + if(seg_mgr->get_size() != size_before) + return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(!seg_mgr->all_memory_deallocated()) + return false; + } + {//test zero_free_memory + const size_type Size(ShmSizeSize/2+1), Size2(ShmSizeSize/8); + void *mem = seg_mgr->allocate(Size); + void *mem2 = seg_mgr->allocate(Size2); + //Mark memory to non-zero + std::memset(mem, 0xFF, Size); + std::memset(mem2, 0xFF, Size2); + static unsigned char zerobuf[Size]; + //Deallocate and check still non-zero + seg_mgr->deallocate(mem); + seg_mgr->deallocate(mem2); + if(!std::memcmp(mem, zerobuf, Size)) + return false; + if(!std::memcmp(mem2, zerobuf, Size2)) + return false; + //zero_free_memory and check it's zeroed + seg_mgr->zero_free_memory(); + //TODO: some parts are not zeroed because they are used + //as internal metadata, find a way to test this + //if(std::memcmp(mem, zerobuf, Size)) + //return false; + //if(std::memcmp(mem2, zerobuf, Size2)) + //return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(!seg_mgr->all_memory_deallocated()) + return false; + } + + {//test anonymous object + int *int_object = seg_mgr->template construct(anonymous_instance)(); + if(1 != seg_mgr->get_instance_length(int_object)) + return false; + if(anonymous_type != seg_mgr->get_instance_type(int_object)) + return false; + if(seg_mgr->get_instance_name(int_object)) + return false; + seg_mgr->destroy_ptr(int_object); + int const int_array_values[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + int *int_array = seg_mgr->template construct_it(anonymous_instance, std::nothrow)[10](&int_array_values[0]); + if(10 != seg_mgr->get_instance_length(int_object)) + return false; + if(anonymous_type != seg_mgr->get_instance_type(int_array)) + return false; + if(seg_mgr->get_instance_name(int_array)) + return false; + seg_mgr->destroy_ptr(int_array); + try{ seg_mgr->template construct(anonymous_instance)[ShmSizeSize](); }catch(interprocess_exception&){} + if(seg_mgr->template construct(anonymous_instance, std::nothrow)[ShmSizeSize]()) + try{ seg_mgr->template construct_it(anonymous_instance)[ShmSizeSize](&int_array_values[0]); }catch(interprocess_exception&){} + if(seg_mgr->template construct_it(anonymous_instance, std::nothrow)[ShmSizeSize](&int_array_values[0])) + return false; + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(!seg_mgr->all_memory_deallocated()) + return false; + } + + {//test named object + const char *const object1_name = "object1"; + const char *const object2_name = "object2"; + int const int_array_values[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + for(std::size_t i = 0; i != 4; ++i){ + if(seg_mgr->template find(object1_name).first) + return false; + //Single element construction + unsigned int *uint_object = 0; + switch(i){ + case 0: + uint_object = seg_mgr->template construct(object1_name)(); + break; + case 1: + uint_object = seg_mgr->template construct(object1_name, std::nothrow)(); + break; + case 2: + uint_object = seg_mgr->template find_or_construct(object1_name)(); + break; + case 3: + uint_object = seg_mgr->template find_or_construct(object1_name, std::nothrow)(); + break; + } + std::pair find_ret = seg_mgr->template find(object1_name); + if(uint_object != find_ret.first) + return false; + if(1 != find_ret.second) + return false; + if(1 != seg_mgr->get_instance_length(uint_object)) + return false; + if(named_type != seg_mgr->get_instance_type(uint_object)) + return false; + if(std::strcmp(object1_name, seg_mgr->get_instance_name(uint_object))) + return false; + //Array construction + if(seg_mgr->template find(object2_name).first) + return false; + int *int_array = 0; + switch(i){ + case 0: + int_array = seg_mgr->template construct_it(object2_name)[10](&int_array_values[0]); + break; + case 1: + int_array = seg_mgr->template construct_it(object2_name, std::nothrow)[10](&int_array_values[0]); + break; + case 2: + int_array = seg_mgr->template find_or_construct_it(object2_name)[10](&int_array_values[0]); + break; + case 3: + int_array = seg_mgr->template find_or_construct_it(object2_name, std::nothrow)[10](&int_array_values[0]); + break; + } + std::pair find_ret2 = seg_mgr->template find(object2_name); + if(int_array != find_ret2.first) + return false; + if(10 != find_ret2.second) + return false; + if(10 != seg_mgr->get_instance_length(int_array)) + return false; + if(named_type != seg_mgr->get_instance_type(int_array)) + return false; + if(std::strcmp(object2_name, seg_mgr->get_instance_name(int_array))) + return false; + if(seg_mgr->get_num_named_objects() != 2) + return false; + typename SegmentManager::const_named_iterator nb(seg_mgr->named_begin()); + typename SegmentManager::const_named_iterator ne(seg_mgr->named_end()); + for(std::size_t i = 0, imax = seg_mgr->get_num_named_objects(); i != imax; ++i){ ++nb; } + if(nb != ne) + return false; + seg_mgr->destroy_ptr(uint_object); + seg_mgr->template destroy(object2_name); + } + try{ seg_mgr->template construct(object1_name)[ShmSizeSize](); }catch(interprocess_exception&){} + if(seg_mgr->template construct(object2_name, std::nothrow)[ShmSizeSize]()) + try{ seg_mgr->template construct_it(object1_name)[ShmSizeSize](&int_array_values[0]); }catch(interprocess_exception&){} + if(seg_mgr->template construct_it(object2_name, std::nothrow)[ShmSizeSize](&int_array_values[0])) + return false; + seg_mgr->shrink_to_fit_indexes(); + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(!seg_mgr->all_memory_deallocated()) + return false; + seg_mgr->reserve_named_objects(1); + //In indexes with no capacity() memory won't be allocated so don't check anything was allocated. + //if(seg_mgr->all_memory_deallocated()) return false; + seg_mgr->shrink_to_fit_indexes(); + if(!seg_mgr->all_memory_deallocated()) + return false; + } + + {//test unique object + int const int_array_values[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + for(std::size_t i = 0; i != 4; ++i){ + if(seg_mgr->template find(unique_instance).first) + return false; + //Single element construction + unsigned int *uint_object = 0; + switch(i){ + case 0: + uint_object = seg_mgr->template construct(unique_instance)(); + break; + case 1: + uint_object = seg_mgr->template construct(unique_instance, std::nothrow)(); + break; + case 2: + uint_object = seg_mgr->template find_or_construct(unique_instance)(); + break; + case 3: + uint_object = seg_mgr->template find_or_construct(unique_instance, std::nothrow)(); + break; + } + std::pair find_ret = seg_mgr->template find(unique_instance); + if(uint_object != find_ret.first) + return false; + if(1 != find_ret.second) + return false; + if(1 != seg_mgr->get_instance_length(uint_object)) + return false; + if(unique_type != seg_mgr->get_instance_type(uint_object)) + return false; + if(std::strcmp(typeid(unsigned int).name(), seg_mgr->get_instance_name(uint_object))) + return false; + //Array construction + if(seg_mgr->template find(unique_instance).first) + return false; + int *int_array = 0; + switch(i){ + case 0: + int_array = seg_mgr->template construct_it(unique_instance)[10](&int_array_values[0]); + break; + case 1: + int_array = seg_mgr->template construct_it(unique_instance, std::nothrow)[10](&int_array_values[0]); + break; + case 2: + int_array = seg_mgr->template find_or_construct_it(unique_instance)[10](&int_array_values[0]); + break; + case 3: + int_array = seg_mgr->template find_or_construct_it(unique_instance, std::nothrow)[10](&int_array_values[0]); + break; + } + std::pair find_ret2 = seg_mgr->template find(unique_instance); + if(int_array != find_ret2.first) + return false; + if(10 != find_ret2.second) + return false; + if(10 != seg_mgr->get_instance_length(int_array)) + return false; + if(unique_type != seg_mgr->get_instance_type(int_array)) + return false; + if(std::strcmp(typeid(int).name(), seg_mgr->get_instance_name(int_array))) + return false; + if(seg_mgr->get_num_unique_objects() != 2) + return false; + typename SegmentManager::const_unique_iterator nb(seg_mgr->unique_begin()); + typename SegmentManager::const_unique_iterator ne(seg_mgr->unique_end()); + for(std::size_t i = 0, imax = seg_mgr->get_num_unique_objects(); i != imax; ++i){ ++nb; } + if(nb != ne) + return false; + seg_mgr->destroy_ptr(uint_object); + seg_mgr->template destroy(unique_instance); + } + try{ seg_mgr->template construct(unique_instance)[ShmSizeSize](); }catch(interprocess_exception&){} + if(seg_mgr->template construct(unique_instance, std::nothrow)[ShmSizeSize]()) + try{ seg_mgr->template construct_it(unique_instance)[ShmSizeSize](&int_array_values[0]); }catch(interprocess_exception&){} + if(seg_mgr->template construct_it(unique_instance, std::nothrow)[ShmSizeSize](&int_array_values[0])) + return false; + seg_mgr->shrink_to_fit_indexes(); + if(seg_mgr->get_free_memory() != free_mem_before) + return false; + if(!seg_mgr->all_memory_deallocated()) + return false; + seg_mgr->reserve_unique_objects(1); + //In indexes with no capacity() memory won't be allocated so don't check anything was allocated. + //if(seg_mgr->all_memory_deallocated()) return false; + seg_mgr->shrink_to_fit_indexes(); + if(!seg_mgr->all_memory_deallocated()) + return false; + } + {//test allocator/deleter + if(!seg_mgr->all_memory_deallocated()) + return false; + typedef typename SegmentManager::template allocator::type allocator_t; + typedef typename SegmentManager::template deleter::type deleter_t; + + allocator_t alloc(seg_mgr->template get_allocator()); + deleter_t delet(seg_mgr->template get_deleter()); + + if(!seg_mgr->all_memory_deallocated()) + return false; + offset_ptr f = alloc.allocate(50); + if(seg_mgr->all_memory_deallocated()) + return false; + alloc.deallocate(f, 50); + if(!seg_mgr->all_memory_deallocated()) + return false; + } + {//test allocator/deleter + if(!seg_mgr->all_memory_deallocated()) + return false; + int *int_object = seg_mgr->template construct("atomic_func_find_object")(); + atomic_func_test func(*seg_mgr); + seg_mgr->atomic_func(func); + if(int_object != func.object) + return 1; + seg_mgr->destroy_ptr(int_object); + seg_mgr->shrink_to_fit_indexes(); + if(!seg_mgr->all_memory_deallocated()) + return false; + } + return true; +} + +template +bool test_each_algo() +{ + { + typedef segment_manager< char, MemoryAlgorithm, flat_map_index > segment_manager_t; + if(!test_segment_manager()) + return false; + } + { + typedef segment_manager< char, MemoryAlgorithm, map_index > segment_manager_t; + if(!test_segment_manager()) + return false; + } + /* + { + typedef segment_manager< char, MemoryAlgorithm, null_index > segment_manager_t; + if(!test_segment_manager()) + return false; + }*/ + /* + { + typedef segment_manager< char, MemoryAlgorithm, unordered_map_index > segment_manager_t; + if(!test_segment_manager()) + return false; + }*/ + { + typedef segment_manager< char, MemoryAlgorithm, iset_index > segment_manager_t; + if(!test_segment_manager()) + return false; + } + { + typedef segment_manager< char, MemoryAlgorithm, iunordered_set_index > segment_manager_t; + if(!test_segment_manager()) + return false; + } + return true; +} + +int main() +{ + if(!test_each_algo< simple_seq_fit< null_mutex_family > >()) + return 1; + if(!test_each_algo< rbtree_best_fit< null_mutex_family > >()) + return 1; + + return 0; +}