mirror of
https://github.com/boostorg/container.git
synced 2025-08-02 14:04:26 +02:00
Fix node_handle bugs:
-> Bad allocator destruction in swap -> Wrong assertion in operator= -> Make dangerous functions private Added full testsuite.
This commit is contained in:
55
include/boost/container/detail/pair_key_mapped_of_value.hpp
Normal file
55
include/boost/container/detail/pair_key_mapped_of_value.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost
|
||||
// Software License, Version 1.0. (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_CONTAINER_PAIR_KEY_MAPPED_OF_VALUE_HPP
|
||||
#define BOOST_CONTAINER_PAIR_KEY_MAPPED_OF_VALUE_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/container/detail/config_begin.hpp>
|
||||
#include <boost/container/detail/workaround.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace container {
|
||||
|
||||
template<class Key, class Mapped>
|
||||
struct pair_key_mapped_of_value
|
||||
{
|
||||
typedef Key key_type;
|
||||
typedef Mapped mapped_type;
|
||||
|
||||
template<class Pair>
|
||||
const key_type & key_of_value(const Pair &p) const
|
||||
{ return p.first; }
|
||||
|
||||
template<class Pair>
|
||||
const mapped_type & mapped_of_value(const Pair &p) const
|
||||
{ return p.second; }
|
||||
|
||||
template<class Pair>
|
||||
key_type & key_of_value(Pair &p) const
|
||||
{ return const_cast<key_type&>(p.first); }
|
||||
|
||||
template<class Pair>
|
||||
mapped_type & mapped_of_value(Pair &p) const
|
||||
{ return p.second; }
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#include <boost/container/detail/config_end.hpp>
|
||||
|
||||
#endif // BOOST_CONTAINER_PAIR_KEY_MAPPED_OF_VALUE_HPP
|
@@ -493,7 +493,7 @@ class tree
|
||||
typedef boost::container::reverse_iterator
|
||||
<const_iterator> const_reverse_iterator;
|
||||
typedef node_handle
|
||||
< Node, value_type, allocator_type, void> node_type;
|
||||
< NodeAlloc, void> node_type;
|
||||
typedef insert_return_type_base
|
||||
<iterator, node_type> insert_return_type;
|
||||
|
||||
@@ -1142,7 +1142,7 @@ class tree
|
||||
this->insert_unique_check(hint, KeyOfValue()(nh.value()), data);
|
||||
if(ret.second){
|
||||
irt.inserted = true;
|
||||
irt.position = iterator(this->icont().insert_unique_commit(*nh.get_node_pointer(), data));
|
||||
irt.position = iterator(this->icont().insert_unique_commit(*nh.get(), data));
|
||||
nh.release();
|
||||
}
|
||||
else{
|
||||
|
@@ -31,6 +31,8 @@
|
||||
#include <boost/container/detail/type_traits.hpp>
|
||||
#include <boost/container/detail/value_init.hpp>
|
||||
#include <boost/container/detail/pair.hpp>
|
||||
#include <boost/container/detail/pair_key_mapped_of_value.hpp>
|
||||
|
||||
// move
|
||||
#include <boost/move/traits.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
@@ -53,34 +55,6 @@
|
||||
namespace boost {
|
||||
namespace container {
|
||||
|
||||
///@cond
|
||||
|
||||
template<class Key, class Mapped>
|
||||
struct pair_key_mapped_of_value
|
||||
{
|
||||
typedef Key key_type;
|
||||
typedef Mapped mapped_type;
|
||||
|
||||
template<class Pair>
|
||||
const key_type & key_of_value(const Pair &p) const
|
||||
{ return p.first; }
|
||||
|
||||
template<class Pair>
|
||||
const mapped_type & mapped_of_value(const Pair &p) const
|
||||
{ return p.second; }
|
||||
|
||||
template<class Pair>
|
||||
key_type & key_of_value(Pair &p) const
|
||||
{ return const_cast<key_type&>(p.first); }
|
||||
|
||||
template<class Pair>
|
||||
mapped_type & mapped_of_value(Pair &p) const
|
||||
{ return p.second; }
|
||||
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
//! A map is a kind of associative container that supports unique keys (contains at
|
||||
@@ -150,9 +124,7 @@ class map
|
||||
typedef std::pair<key_type, mapped_type> nonconst_value_type;
|
||||
typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type;
|
||||
typedef BOOST_CONTAINER_IMPDEF(node_handle<
|
||||
typename base_t::node_type::container_node_type
|
||||
BOOST_MOVE_I value_type
|
||||
BOOST_MOVE_I allocator_type
|
||||
typename base_t::stored_allocator_type
|
||||
BOOST_MOVE_I pair_key_mapped_of_value
|
||||
<key_type BOOST_MOVE_I mapped_type> >) node_type;
|
||||
typedef BOOST_CONTAINER_IMPDEF
|
||||
@@ -1243,9 +1215,7 @@ class multimap
|
||||
typedef std::pair<key_type, mapped_type> nonconst_value_type;
|
||||
typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type;
|
||||
typedef BOOST_CONTAINER_IMPDEF(node_handle<
|
||||
typename base_t::node_type::container_node_type
|
||||
BOOST_MOVE_I value_type
|
||||
BOOST_MOVE_I allocator_type
|
||||
typename base_t::stored_allocator_type
|
||||
BOOST_MOVE_I pair_key_mapped_of_value
|
||||
<key_type BOOST_MOVE_I mapped_type> >) node_type;
|
||||
|
||||
|
@@ -40,20 +40,34 @@ namespace container {
|
||||
|
||||
///@cond
|
||||
|
||||
template<class Value, class KeyMapped, bool keymapped_is_void = container_detail::is_same<KeyMapped, void>::value>
|
||||
template<class Value, class KeyMapped>
|
||||
struct node_handle_keymapped_traits
|
||||
{
|
||||
typedef typename KeyMapped::key_type key_type;
|
||||
typedef typename KeyMapped::mapped_type mapped_type;
|
||||
};
|
||||
|
||||
template<class Value>
|
||||
struct node_handle_keymapped_traits<Value, void>
|
||||
{
|
||||
typedef Value key_type;
|
||||
typedef Value mapped_type;
|
||||
};
|
||||
|
||||
template<class Value, class KeyMapped>
|
||||
struct node_handle_keymapped_traits<Value, KeyMapped, false>
|
||||
class node_handle_friend
|
||||
{
|
||||
typedef typename KeyMapped::key_type key_type;
|
||||
typedef typename KeyMapped::mapped_type mapped_type;
|
||||
public:
|
||||
|
||||
template<class NH>
|
||||
BOOST_CONTAINER_FORCEINLINE static void destroy_alloc(NH &nh) BOOST_NOEXCEPT
|
||||
{ nh.destroy_alloc(); }
|
||||
|
||||
template<class NH>
|
||||
BOOST_CONTAINER_FORCEINLINE static typename NH::node_pointer &get_node_pointer(NH &nh) BOOST_NOEXCEPT
|
||||
{ return nh.get_node_pointer(); }
|
||||
};
|
||||
|
||||
|
||||
///@endcond
|
||||
|
||||
//! A node_handle is an object that accepts ownership of a single element from an associative container.
|
||||
@@ -73,76 +87,63 @@ struct node_handle_keymapped_traits<Value, KeyMapped, false>
|
||||
//!
|
||||
//! If a node handle is not empty, then it contains an allocator that is equal to the allocator of the container
|
||||
//! when the element was extracted. If a node handle is empty, it contains no allocator.
|
||||
template <class NodeType, class Value, class Allocator, class KeyMapped = void>
|
||||
template <class NodeAllocator, class KeyMapped = void>
|
||||
class node_handle
|
||||
{
|
||||
typedef node_handle_keymapped_traits<Value, KeyMapped> keymapped_t;
|
||||
typedef NodeAllocator nallocator_type;
|
||||
typedef allocator_traits<NodeAllocator> nator_traits;
|
||||
typedef typename nator_traits::value_type priv_node_t;
|
||||
typedef typename priv_node_t::value_type priv_value_t;
|
||||
typedef node_handle_keymapped_traits<priv_value_t, KeyMapped> keymapped_t;
|
||||
|
||||
public:
|
||||
typedef Value value_type;
|
||||
typedef priv_value_t value_type;
|
||||
typedef typename keymapped_t::key_type key_type;
|
||||
typedef typename keymapped_t::mapped_type mapped_type;
|
||||
typedef Allocator allocator_type;
|
||||
typedef NodeType container_node_type;
|
||||
typedef typename nator_traits::template portable_rebind_alloc
|
||||
<value_type>::type allocator_type;
|
||||
|
||||
typedef priv_node_t container_node_type;
|
||||
friend class node_handle_friend;
|
||||
|
||||
///@cond
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle)
|
||||
|
||||
typedef allocator_traits<allocator_type> ator_traits;
|
||||
typedef typename ator_traits::template portable_rebind_alloc
|
||||
<container_node_type>::type nallocator_type;
|
||||
typedef allocator_traits<nallocator_type> node_ator_traits;
|
||||
typedef typename node_ator_traits::pointer node_pointer;
|
||||
typedef typename nator_traits::pointer node_pointer;
|
||||
typedef ::boost::aligned_storage
|
||||
<sizeof(allocator_type), boost::alignment_of<nallocator_type>::value> nalloc_storage_t;
|
||||
< sizeof(nallocator_type)
|
||||
, boost::alignment_of<nallocator_type>::value> nalloc_storage_t;
|
||||
|
||||
node_pointer m_ptr;
|
||||
nalloc_storage_t m_nalloc_storage;
|
||||
|
||||
void move_construct_alloc(nallocator_type &al)
|
||||
{ ::new(m_nalloc_storage.address(), boost_container_new_t()) allocator_type(::boost::move(al)); }
|
||||
{ ::new(m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(::boost::move(al)); }
|
||||
|
||||
void destroy_node()
|
||||
void destroy_deallocate_node()
|
||||
{
|
||||
node_ator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(m_ptr));
|
||||
node_ator_traits::deallocate(this->node_alloc(), m_ptr, 1u);
|
||||
nator_traits::destroy(this->node_alloc(), container_detail::to_raw_pointer(m_ptr));
|
||||
nator_traits::deallocate(this->node_alloc(), m_ptr, 1u);
|
||||
}
|
||||
|
||||
template<class OtherNodeHandle>
|
||||
void move_construct_end(OtherNodeHandle &nh)
|
||||
{
|
||||
if(m_ptr){
|
||||
::new (m_nalloc_storage.address(), boost_container_new_t()) allocator_type(::boost::move(nh.node_alloc()));
|
||||
nh.destroy_alloc();
|
||||
nh.get_node_pointer() = node_pointer();
|
||||
::new (m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(::boost::move(nh.node_alloc()));
|
||||
node_handle_friend::destroy_alloc(nh);
|
||||
node_handle_friend::get_node_pointer(nh) = node_pointer();
|
||||
}
|
||||
BOOST_ASSERT(nh.empty());
|
||||
}
|
||||
|
||||
public:
|
||||
void destroy_alloc() BOOST_NOEXCEPT
|
||||
{ static_cast<nallocator_type*>(m_nalloc_storage.address())->~nallocator_type(); }
|
||||
|
||||
void destroy_alloc()
|
||||
{ static_cast<allocator_type*>(m_nalloc_storage.address())->~allocator_type(); }
|
||||
|
||||
node_pointer &get_node_pointer()
|
||||
node_pointer &get_node_pointer() BOOST_NOEXCEPT
|
||||
{ return m_ptr; }
|
||||
|
||||
nallocator_type &node_alloc()
|
||||
{ return *static_cast<nallocator_type*>(m_nalloc_storage.address()); }
|
||||
|
||||
const nallocator_type &node_alloc() const
|
||||
{ return *static_cast<const nallocator_type*>(m_nalloc_storage.address()); }
|
||||
|
||||
node_pointer release()
|
||||
{
|
||||
node_pointer p(m_ptr);
|
||||
m_ptr = node_pointer();
|
||||
if(p)
|
||||
this->destroy_alloc();
|
||||
return p;
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
public:
|
||||
@@ -150,13 +151,13 @@ class node_handle
|
||||
//!
|
||||
//! <b>Postcondition</b>: this->empty()
|
||||
BOOST_CXX14_CONSTEXPR node_handle() BOOST_NOEXCEPT
|
||||
: m_ptr(), m_nalloc_storage()
|
||||
{ BOOST_ASSERT(this->empty()); }
|
||||
: m_ptr()
|
||||
{ }
|
||||
|
||||
//! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with p.
|
||||
//! If p != nullptr copy constructs internal allocator al.
|
||||
//! If p != nullptr copy constructs internal allocator from al.
|
||||
node_handle(node_pointer p, const nallocator_type &al) BOOST_NOEXCEPT
|
||||
: m_ptr(p), m_nalloc_storage()
|
||||
: m_ptr(p)
|
||||
{
|
||||
if(m_ptr){
|
||||
::new (m_nalloc_storage.address(), boost_container_new_t()) nallocator_type(al);
|
||||
@@ -172,12 +173,12 @@ class node_handle
|
||||
//! <b>Note</b>: Two node_handle's are related if only one of KeyMapped template parameter
|
||||
//! of a node handle is void.
|
||||
template<class KeyMapped2>
|
||||
node_handle( BOOST_RV_REF_BEG node_handle<NodeType, Value, Allocator, KeyMapped2> BOOST_RV_REF_END nh
|
||||
node_handle( BOOST_RV_REF_BEG node_handle<NodeAllocator, KeyMapped2> BOOST_RV_REF_END nh
|
||||
, typename container_detail::enable_if_c
|
||||
< ((unsigned)container_detail::is_same<KeyMapped, void>::value +
|
||||
(unsigned)container_detail::is_same<KeyMapped2, void>::value) == 1u
|
||||
>::type* = 0)
|
||||
: m_ptr(nh.get_node_pointer()), m_nalloc_storage()
|
||||
>::type* = 0) BOOST_NOEXCEPT
|
||||
: m_ptr(nh.get())
|
||||
{ this->move_construct_end(nh); }
|
||||
|
||||
//! <b>Effects</b>: Constructs a node_handle object initializing internal pointer with nh's internal pointer
|
||||
@@ -186,43 +187,44 @@ class node_handle
|
||||
//!
|
||||
//! <b>Postcondition</b>: nh.empty()
|
||||
node_handle (BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT
|
||||
: m_ptr(nh.m_ptr), m_nalloc_storage()
|
||||
: m_ptr(nh.m_ptr)
|
||||
{ this->move_construct_end(nh); }
|
||||
|
||||
//! <b>Effects</b>: If !this->empty(), destroys the value_type subobject in the container_node_type object
|
||||
//! pointed to by c by calling allocator_traits<impl_defined>::destroy, then deallocates m_ptr by calling
|
||||
//! ator_traits::rebind_traits<container_node_type>::deallocate.
|
||||
//! nator_traits::rebind_traits<container_node_type>::deallocate.
|
||||
~node_handle() BOOST_NOEXCEPT
|
||||
{
|
||||
if(!this->empty()){
|
||||
this->destroy_node();
|
||||
this->destroy_deallocate_node();
|
||||
this->destroy_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
//! <b>Requires</b>: Either this->empty(), or ator_traits::propagate_on_container_move_assignment is true, or
|
||||
//! <b>Requires</b>: Either this->empty(), or nator_traits::propagate_on_container_move_assignment is true, or
|
||||
//! node_alloc() == nh.node_alloc().
|
||||
//!
|
||||
//! <b>Effects</b>: If m_ptr != nullptr, destroys the value_type subobject in the container_node_type object
|
||||
//! pointed to by m_ptr by calling ator_traits::destroy, then deallocates m_ptr by calling ator_-
|
||||
//! traits::rebind_traits<container_node_type>::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty()
|
||||
//! or ator_traits::propagate_on_container_move_assignment is true, move assigns nh.node_alloc() to
|
||||
//! pointed to by m_ptr by calling nator_traits::destroy, then deallocates m_ptr by calling
|
||||
//! nator_traits::deallocate. Assigns nh.m_ptr to m_ptr. If this->empty()
|
||||
//! or nator_traits::propagate_on_container_move_assignment is true, move assigns nh.node_alloc() to
|
||||
//! node_alloc(). Assigns nullptr to nh.m_ptr and assigns nullopt to nh.node_alloc().
|
||||
//!
|
||||
//! <b>Returns</b>: *this.
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
node_handle & operator=(BOOST_RV_REF(node_handle) nh)
|
||||
node_handle & operator=(BOOST_RV_REF(node_handle) nh) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(this->empty() || nh.empty() || ator_traits::propagate_on_container_move_assignment::value
|
||||
|| ator_traits::equal(node_alloc(), nh.node_alloc()));
|
||||
BOOST_ASSERT(this->empty() || nator_traits::propagate_on_container_move_assignment::value
|
||||
|| nator_traits::equal(node_alloc(), nh.node_alloc()));
|
||||
|
||||
bool const was_this_non_null = !this->empty();
|
||||
bool const was_nh_non_null = !nh.empty();
|
||||
|
||||
if(was_nh_non_null){
|
||||
if(was_this_non_null){
|
||||
this->destroy_node();
|
||||
if(ator_traits::propagate_on_container_move_assignment::value){
|
||||
this->destroy_deallocate_node();
|
||||
if(nator_traits::propagate_on_container_move_assignment::value){
|
||||
this->node_alloc() = ::boost::move(nh.node_alloc());
|
||||
}
|
||||
}
|
||||
@@ -234,7 +236,7 @@ class node_handle
|
||||
nh.destroy_alloc();
|
||||
}
|
||||
else if(was_this_non_null){
|
||||
this->destroy_node();
|
||||
this->destroy_deallocate_node();
|
||||
this->destroy_alloc();
|
||||
m_ptr = node_pointer();
|
||||
}
|
||||
@@ -310,23 +312,23 @@ class node_handle
|
||||
return !this->m_ptr;
|
||||
}
|
||||
|
||||
//! <b>Requires</b>: this->empty(), or nh.empty(), or ator_traits::propagate_on_container_swap is true, or
|
||||
//! <b>Requires</b>: this->empty(), or nh.empty(), or nator_traits::propagate_on_container_swap is true, or
|
||||
//! node_alloc() == nh.node_alloc().
|
||||
//!
|
||||
//! <b>Effects</b>: Calls swap(m_ptr, nh.m_ptr). If this->empty(), or nh.empty(), or ator_traits::propagate_on_-
|
||||
//! <b>Effects</b>: Calls swap(m_ptr, nh.m_ptr). If this->empty(), or nh.empty(), or nator_traits::propagate_on_-
|
||||
//! container_swap is true calls swap(node_alloc(), nh.node_alloc()).
|
||||
void swap(node_handle &nh)
|
||||
BOOST_NOEXCEPT_IF(ator_traits::propagate_on_container_swap::value || ator_traits::is_always_equal::value)
|
||||
BOOST_NOEXCEPT_IF(nator_traits::propagate_on_container_swap::value || nator_traits::is_always_equal::value)
|
||||
{
|
||||
BOOST_ASSERT(this->empty() || nh.empty() || ator_traits::propagate_on_container_swap::value
|
||||
|| ator_traits::equal(node_alloc(), nh.node_alloc()));
|
||||
BOOST_ASSERT(this->empty() || nh.empty() || nator_traits::propagate_on_container_swap::value
|
||||
|| nator_traits::equal(node_alloc(), nh.node_alloc()));
|
||||
|
||||
bool const was_this_non_null = !this->empty();
|
||||
bool const was_nh_non_null = !nh.empty();
|
||||
|
||||
if(was_nh_non_null){
|
||||
if(was_this_non_null){
|
||||
if(ator_traits::propagate_on_container_swap::value){
|
||||
if(nator_traits::propagate_on_container_swap::value){
|
||||
::boost::adl_move_swap(this->node_alloc(), nh.node_alloc());
|
||||
}
|
||||
}
|
||||
@@ -337,11 +339,53 @@ class node_handle
|
||||
}
|
||||
else if(was_this_non_null){
|
||||
nh.move_construct_alloc(this->node_alloc());
|
||||
nh.destroy_alloc();
|
||||
this->destroy_alloc();
|
||||
}
|
||||
::boost::adl_move_swap(m_ptr, nh.m_ptr);
|
||||
}
|
||||
|
||||
//! <b>Effects</b>: If this->empty() returns nullptr, otherwise returns m_ptr
|
||||
//! resets m_ptr to nullptr and destroys the internal allocator.
|
||||
//!
|
||||
//! <b>Postcondition</b>: this->empty()
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extensions
|
||||
node_pointer release() BOOST_NOEXCEPT
|
||||
{
|
||||
node_pointer p(m_ptr);
|
||||
m_ptr = node_pointer();
|
||||
if(p)
|
||||
this->destroy_alloc();
|
||||
return p;
|
||||
}
|
||||
|
||||
//! <b>Effects</b>: Returns m_ptr.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extensions
|
||||
node_pointer get() const BOOST_NOEXCEPT
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
//! <b>Effects</b>: Returns a reference to the internal node allocator.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extensions
|
||||
nallocator_type &node_alloc() BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *static_cast<nallocator_type*>(m_nalloc_storage.address());
|
||||
}
|
||||
|
||||
|
||||
//! <b>Effects</b>: Returns a reference to the internal node allocator.
|
||||
//!
|
||||
//! <b>Note</b>: Non-standard extensions
|
||||
const nallocator_type &node_alloc() const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *static_cast<const nallocator_type*>(m_nalloc_storage.address());
|
||||
}
|
||||
|
||||
//! <b>Effects</b>: x.swap(y).
|
||||
//!
|
||||
friend void swap(node_handle & x, node_handle & y) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y)))
|
||||
|
@@ -38,13 +38,6 @@ template class map
|
||||
, test::simple_allocator< pair_t >
|
||||
>;
|
||||
|
||||
template class map
|
||||
< test::movable_and_copyable_int
|
||||
, test::movable_and_copyable_int
|
||||
, std::less<test::movable_and_copyable_int>
|
||||
, std::allocator< pair_t >
|
||||
>;
|
||||
|
||||
template class map
|
||||
< test::movable_and_copyable_int
|
||||
, test::movable_and_copyable_int
|
||||
|
@@ -8,11 +8,626 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/container/node_handle.hpp>
|
||||
#include <boost/container/new_allocator.hpp>
|
||||
#include <boost/move/utility_core.hpp>
|
||||
#include <boost/move/adl_move_swap.hpp>
|
||||
#include <boost/container/detail/pair_key_mapped_of_value.hpp>
|
||||
|
||||
using namespace ::boost::container;
|
||||
|
||||
enum EAllocState
|
||||
{
|
||||
DefaultConstructed,
|
||||
MoveConstructed,
|
||||
MoveAssigned,
|
||||
CopyConstructed,
|
||||
CopyAssigned,
|
||||
Swapped,
|
||||
Destructed
|
||||
};
|
||||
|
||||
template<class Node>
|
||||
class trace_allocator
|
||||
: public new_allocator<Node>
|
||||
{
|
||||
BOOST_COPYABLE_AND_MOVABLE(trace_allocator)
|
||||
|
||||
typedef new_allocator<Node> base_t;
|
||||
|
||||
public:
|
||||
|
||||
struct propagate_on_container_move_assignment
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
struct propagate_on_container_swap
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
//!Obtains an new_allocator that allocates
|
||||
//!objects of type T2
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef trace_allocator<T2> other;
|
||||
};
|
||||
|
||||
explicit trace_allocator(unsigned value = 999)
|
||||
: m_state(DefaultConstructed), m_value(value)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
trace_allocator(BOOST_RV_REF(trace_allocator) other)
|
||||
: base_t(boost::move(BOOST_MOVE_BASE(base_t, other))), m_state(MoveConstructed), m_value(other.m_value)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
trace_allocator(const trace_allocator &other)
|
||||
: base_t(other), m_state(CopyConstructed), m_value(other.m_value)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
trace_allocator & operator=(BOOST_RV_REF(trace_allocator) other)
|
||||
{
|
||||
m_value = other.m_value;
|
||||
m_state = MoveAssigned;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class OtherNode>
|
||||
trace_allocator(const trace_allocator<OtherNode> &other)
|
||||
: m_state(CopyConstructed), m_value(other.m_value)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
template<class OtherNode>
|
||||
trace_allocator & operator=(BOOST_COPY_ASSIGN_REF(trace_allocator<OtherNode>) other)
|
||||
{
|
||||
m_value = other.m_value;
|
||||
m_state = CopyAssigned;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~trace_allocator()
|
||||
{
|
||||
m_value = 0u-1u;
|
||||
m_state = Destructed;
|
||||
--count;
|
||||
}
|
||||
|
||||
void swap(trace_allocator &other)
|
||||
{
|
||||
boost::adl_move_swap(m_value, other.m_value);
|
||||
m_state = other.m_state = Swapped;
|
||||
}
|
||||
|
||||
friend void swap(trace_allocator &left, trace_allocator &right)
|
||||
{
|
||||
left.swap(right);
|
||||
}
|
||||
|
||||
EAllocState m_state;
|
||||
unsigned m_value;
|
||||
|
||||
static unsigned int count;
|
||||
|
||||
static void reset_count()
|
||||
{ count = 0; }
|
||||
};
|
||||
|
||||
template<class Node>
|
||||
unsigned int trace_allocator<Node>::count = 0;
|
||||
|
||||
template<class T>
|
||||
struct node
|
||||
{
|
||||
typedef T value_type;
|
||||
value_type value;
|
||||
|
||||
value_type &get_data() { return value; }
|
||||
const value_type &get_data() const { return value; }
|
||||
|
||||
node()
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
~node()
|
||||
{
|
||||
--count;
|
||||
}
|
||||
|
||||
static unsigned int count;
|
||||
|
||||
static void reset_count()
|
||||
{ count = 0; }
|
||||
};
|
||||
|
||||
template<class T1, class T2>
|
||||
struct value
|
||||
{
|
||||
T1 first;
|
||||
T2 second;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
unsigned int node<T>::count = 0;
|
||||
|
||||
|
||||
//Common types
|
||||
typedef value<int, unsigned> test_pair;
|
||||
typedef pair_key_mapped_of_value<int, unsigned> key_mapped_t;
|
||||
typedef node<test_pair> node_t;
|
||||
typedef trace_allocator< node_t > node_alloc_t;
|
||||
typedef node_handle<node_alloc_t, void> node_handle_set_t;
|
||||
typedef node_handle<node_alloc_t, key_mapped_t> node_handle_map_t;
|
||||
typedef allocator_traits<node_alloc_t>::portable_rebind_alloc<test_pair>::type value_allocator_type;
|
||||
|
||||
void test_types()
|
||||
{
|
||||
//set
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_set_t::value_type, test_pair>::value ));
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_set_t::key_type, test_pair>::value ));
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_set_t::mapped_type, test_pair>::value ));
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_set_t::allocator_type, value_allocator_type>::value ));
|
||||
|
||||
//map
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_map_t::value_type, test_pair>::value ));
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_map_t::key_type, int>::value ));
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_map_t::mapped_type, unsigned>::value ));
|
||||
BOOST_STATIC_ASSERT(( container_detail::is_same<node_handle_map_t::allocator_type, value_allocator_type>::value ));
|
||||
}
|
||||
|
||||
void test_default_constructor()
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
{
|
||||
node_handle_set_t nh;
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
void test_arg_constructor()
|
||||
{
|
||||
//With non-null pointer
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
{
|
||||
const node_alloc_t al;
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
{
|
||||
node_handle_set_t nh(new node_t, al);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
//With null pointer
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
{
|
||||
const node_alloc_t al;
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
{
|
||||
node_handle_set_t nh(0, al);
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
void test_move_constructor()
|
||||
{
|
||||
//With non-null pointer
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
{
|
||||
const node_alloc_t al;
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
{
|
||||
node_t *const from_ptr = new node_t;
|
||||
node_handle_set_t nh(from_ptr, al);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
{
|
||||
node_handle_set_t nh2(boost::move(nh));
|
||||
BOOST_TEST(nh.empty());
|
||||
BOOST_TEST(!nh2.empty());
|
||||
BOOST_TEST(nh2.get() == from_ptr);
|
||||
BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
//With null pointer
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
{
|
||||
const node_alloc_t al;
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
{
|
||||
node_handle_set_t nh;
|
||||
{
|
||||
node_handle_set_t nh2(boost::move(nh));
|
||||
BOOST_TEST(nh.empty());
|
||||
BOOST_TEST(nh2.empty());
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
void test_related_constructor()
|
||||
{
|
||||
//With non-null pointer
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
{
|
||||
const node_alloc_t al;
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
{
|
||||
node_t *const from_ptr = new node_t;
|
||||
node_handle_map_t nh(from_ptr, al);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
{
|
||||
node_handle_set_t nh2(boost::move(nh));
|
||||
BOOST_TEST(nh.empty());
|
||||
BOOST_TEST(!nh2.empty());
|
||||
BOOST_TEST(nh2.get() == from_ptr);
|
||||
BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
//With null pointer
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
{
|
||||
const node_alloc_t al;
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
{
|
||||
node_handle_set_t nh;
|
||||
{
|
||||
node_handle_map_t nh2(boost::move(nh));
|
||||
BOOST_TEST(nh.empty());
|
||||
BOOST_TEST(nh2.empty());
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
void test_move_assignment()
|
||||
{
|
||||
//empty = full
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
node_t *const from_ptr = new node_t;
|
||||
node_handle_set_t nh_from(from_ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
node_handle_set_t nh_to;
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
nh_to = boost::move(nh_from);
|
||||
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(!nh_to.empty());
|
||||
BOOST_TEST(nh_to.get() == from_ptr);
|
||||
BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
|
||||
//empty = empty
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_handle_set_t nh_from;
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
node_handle_set_t nh_to;
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
nh_to = boost::move(nh_from);
|
||||
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
//full = empty
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_handle_set_t nh_from;
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
node_handle_set_t nh_to(new node_t, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
nh_to = boost::move(nh_from);
|
||||
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
//full = full
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_t *const from_ptr = new node_t;
|
||||
node_handle_set_t nh_from(from_ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
node_handle_set_t nh_to(new node_t, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 2);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
|
||||
nh_to = boost::move(nh_from);
|
||||
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(!nh_to.empty());
|
||||
BOOST_TEST(nh_to.get() == from_ptr);
|
||||
BOOST_TEST(nh_to.node_alloc().m_state == MoveAssigned);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void test_value_key_mapped()
|
||||
{
|
||||
//value()
|
||||
{
|
||||
node_t *from_ptr = new node_t;
|
||||
const node_handle_set_t nh_from(from_ptr, node_alloc_t());
|
||||
from_ptr->value.first = -99;
|
||||
from_ptr->value.second = 99;
|
||||
BOOST_TEST(nh_from.value().first == -99);
|
||||
BOOST_TEST(nh_from.value().second == 99);
|
||||
}
|
||||
//key()/mapped()
|
||||
{
|
||||
node_t *from_ptr = new node_t;
|
||||
const node_handle_map_t nh_from(from_ptr, node_alloc_t());
|
||||
from_ptr->value.first = -98;
|
||||
from_ptr->value.second = 98;
|
||||
BOOST_TEST(nh_from.key() == -98);
|
||||
BOOST_TEST(nh_from.mapped() == 98);
|
||||
}
|
||||
}
|
||||
|
||||
void test_get_allocator()
|
||||
{
|
||||
const node_handle_set_t nh(new node_t, node_alloc_t(888));
|
||||
allocator_traits<node_alloc_t>::portable_rebind_alloc<test_pair>::type a = nh.get_allocator();
|
||||
BOOST_TEST(a.m_value == 888);
|
||||
}
|
||||
|
||||
void test_bool_conversion_empty()
|
||||
{
|
||||
const node_handle_set_t nh(new node_t, node_alloc_t(777));
|
||||
const node_handle_set_t nh_null;
|
||||
BOOST_TEST(nh && !nh_null);
|
||||
BOOST_TEST(!(!nh || nh_null));
|
||||
BOOST_TEST(!nh.empty() && nh_null.empty());
|
||||
BOOST_TEST(!(nh.empty() || !nh_null.empty()));
|
||||
}
|
||||
|
||||
void test_swap()
|
||||
{
|
||||
//empty.swap(full)
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
node_t *const from_ptr = new node_t;
|
||||
node_handle_set_t nh_from(from_ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
node_handle_set_t nh_to;
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
nh_to.swap(nh_from);
|
||||
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(!nh_to.empty());
|
||||
BOOST_TEST(nh_to.get() == from_ptr);
|
||||
BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed);
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
|
||||
//empty.swap(empty)
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_handle_set_t nh_from;
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
node_handle_set_t nh_to;
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
nh_to.swap(nh_from);
|
||||
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(nh_to.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
}
|
||||
|
||||
//full.swap(empty)
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_handle_set_t nh_from;
|
||||
BOOST_TEST(nh_from.empty());
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
node_t *const to_ptr = new node_t;
|
||||
node_handle_set_t nh_to(to_ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
nh_to.swap(nh_from);
|
||||
|
||||
BOOST_TEST(!nh_from.empty());
|
||||
BOOST_TEST(nh_from.node_alloc().m_state == MoveConstructed);
|
||||
BOOST_TEST(nh_from.get() == to_ptr);
|
||||
BOOST_TEST(nh_to.empty());
|
||||
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
|
||||
//full.swap(full)
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_t *const from_ptr = new node_t;
|
||||
node_handle_set_t nh_from(from_ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
node_t *const to_ptr = new node_t;
|
||||
node_handle_set_t nh_to(to_ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 2);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
|
||||
nh_to.swap(nh_from);
|
||||
|
||||
BOOST_TEST(!nh_from.empty());
|
||||
BOOST_TEST(nh_from.get() == to_ptr);
|
||||
BOOST_TEST(nh_from.node_alloc().m_state == Swapped);
|
||||
|
||||
BOOST_TEST(!nh_to.empty());
|
||||
BOOST_TEST(nh_to.get() == from_ptr);
|
||||
BOOST_TEST(nh_to.node_alloc().m_state == Swapped);
|
||||
|
||||
BOOST_TEST(node_t::count == 2);
|
||||
BOOST_TEST(node_alloc_t::count == 2);
|
||||
}
|
||||
}
|
||||
|
||||
void test_get_release()
|
||||
{
|
||||
//get()
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_t *const ptr = new node_t;
|
||||
const node_handle_set_t nh(ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
BOOST_TEST(nh.get() == ptr);
|
||||
BOOST_TEST(!nh.empty());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
|
||||
//release()
|
||||
{
|
||||
node_alloc_t::reset_count();
|
||||
node_t::reset_count();
|
||||
|
||||
node_t *const ptr = new node_t;
|
||||
node_handle_set_t nh(ptr, node_alloc_t());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 1);
|
||||
|
||||
BOOST_TEST(nh.release() == ptr);
|
||||
BOOST_TEST(nh.empty());
|
||||
BOOST_TEST(node_t::count == 1);
|
||||
BOOST_TEST(node_alloc_t::count == 0);
|
||||
delete ptr;
|
||||
}
|
||||
BOOST_TEST(node_t::count == 0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_types();
|
||||
test_default_constructor();
|
||||
test_arg_constructor();
|
||||
test_move_constructor();
|
||||
test_related_constructor();
|
||||
test_move_assignment();
|
||||
test_value_key_mapped();
|
||||
test_get_allocator();
|
||||
test_bool_conversion_empty();
|
||||
test_swap();
|
||||
test_get_release();
|
||||
return ::boost::report_errors();
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ template class set
|
||||
template class set
|
||||
< test::movable_and_copyable_int
|
||||
, std::less<test::movable_and_copyable_int>
|
||||
, adaptive_pool<test::movable_and_copyable_int>
|
||||
, new_allocator<test::movable_and_copyable_int>
|
||||
>;
|
||||
|
||||
//multiset
|
||||
|
Reference in New Issue
Block a user