blob: 5685a162e77f7f2cb54855f9ba150ea434521626 [file] [log] [blame]
//
// Boost.Pointer Container
//
// Copyright Thorsten Ottosen 2008. 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)
//
// For more information, see http://www.boost.org/libs/ptr_container/
//
#include "test_data.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/ptr_container/exception.hpp>
#include <boost/range/sub_range.hpp>
#include <boost/cast.hpp>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
//
// abstract base class definition
//
struct abstract_base
{
virtual ~abstract_base() {}
virtual void foo() = 0;
virtual abstract_base* clone() const = 0;
};
struct implementation : abstract_base
{
implementation()
{ }
implementation( const implementation& )
{ }
implementation( int, std::string, int, std::string )
{ }
virtual void foo() {}
virtual abstract_base* clone() const
{
return new implementation( *this );
}
};
inline std::ostream& operator<<( std::ostream& out, const abstract_base& r )
{
return out;
}
inline abstract_base* new_clone( const abstract_base& r )
{
return r.clone();
}
inline std::size_t hash_value( const abstract_base& b )
{
return boost::hash_value( &b );
}
//
// ptr_map test
//
template< typename C, typename B, typename T >
void ptr_map_test();
template< class Key >
Key get_next_key( const Key& k );
template<>
int get_next_key<int>( const int& )
{
return rand();
}
template<>
std::string get_next_key<std::string>( const std::string& )
{
return boost::lexical_cast<std::string>( rand() );
}
template< typename C, typename B, typename T >
void ptr_map_test()
{
using namespace boost;
BOOST_MESSAGE( "starting associative container test" );
enum { max_cnt = 10, size = 100 };
C c;
BOOST_CHECK( c.size() == 0 );
const C c2( c.begin(), c.end() );
BOOST_CHECK( c.size() == c2.size() );
C c3;
BOOST_MESSAGE( "finished construction test" );
BOOST_DEDUCED_TYPENAME C::allocator_type alloc = c.get_allocator();
BOOST_DEDUCED_TYPENAME C::iterator i = c.begin();
BOOST_DEDUCED_TYPENAME C::const_iterator ci = c2.begin();
BOOST_DEDUCED_TYPENAME C::iterator i2 = c.end();
BOOST_DEDUCED_TYPENAME C::const_iterator ci2 = c2.begin();
ci = c.cbegin();
ci = c.cend();
BOOST_DEDUCED_TYPENAME C::key_type a_key;
BOOST_MESSAGE( "finished iterator test" );
BOOST_DEDUCED_TYPENAME C::size_type s = c.size();
BOOST_DEDUCED_TYPENAME C::size_type s2 = c.max_size();
hide_warning(s2);
BOOST_CHECK_EQUAL( c.size(), s );
bool b = c.empty();
hide_warning(b);
BOOST_MESSAGE( "finished accessors test" );
a_key = get_next_key( a_key );
c.insert( a_key, new T );
a_key = get_next_key( a_key );
c.insert( a_key, new T );
c3.insert( c.begin(), c.end() );
c.insert( c3 );
c.erase( c.begin() );
BOOST_CHECK( c3.end() == c3.erase( boost::make_iterator_range(c3) ) );
c3.erase( a_key );
BOOST_CHECK( c3.empty() );
c.swap( c3 );
swap(c,c3);
swap(c3,c);
BOOST_CHECK( !c3.empty() );
c3.clear();
BOOST_CHECK( c3.empty() );
BOOST_MESSAGE( "finished modifiers test" );
a_key = get_next_key( a_key );
c.insert( a_key, new T );
a_key = get_next_key( a_key );
c.insert( a_key, std::auto_ptr<T>( new T ) );
typename C::auto_type ptr2 = c.release( c.begin() );
std::auto_ptr<C> ap = c.release();
c = c2.clone();
BOOST_MESSAGE( "finished release/clone test" );
a_key = get_next_key( a_key );
c3.insert( a_key, new T );
a_key = get_next_key( a_key );
c3.insert( a_key, new T );
c. BOOST_NESTED_TEMPLATE transfer<C>( c3.begin(), c3 );
c. BOOST_NESTED_TEMPLATE transfer<C>( c3.begin(), c3.end(), c3 );
BOOST_CHECK( c3.empty() );
BOOST_CHECK( !c.empty() );
c3. BOOST_NESTED_TEMPLATE transfer<C>( c );
BOOST_CHECK( !c3.empty() );
BOOST_CHECK( c.empty() );
#ifdef BOOST_NO_SFINAE
#else
c. BOOST_NESTED_TEMPLATE transfer<C>( make_iterator_range(c3), c3 );
BOOST_CHECK( !c.empty() );
BOOST_CHECK( c3.empty() );
c3. BOOST_NESTED_TEMPLATE transfer<C>(c);
#endif
BOOST_MESSAGE( "finished transfer test" );
BOOST_CHECK( !c3.empty() );
c3.replace( c3.begin(), new T );
c3.replace( c3.begin(), std::auto_ptr<T>( new T ) );
BOOST_MESSAGE( "finished set/map interface test" );
// @todo: make macro with algorithms so that the right erase() is called.
// c.unique();
// c.unique( std::not_equal_to<T>() );
// c.remove( T() );
// c.remove_if( std::binder1st< std::equal_to<T> >( T() ) );
sub_range<C> sub;
sub_range<const C> csub;
i = c.find( get_next_key( a_key ) );
ci = c2.find( get_next_key( a_key ) );
c2.count( get_next_key( a_key ) );
sub = c.equal_range( get_next_key( a_key ) );
csub = c2.equal_range( get_next_key( a_key ) );
try
{
c.at( get_next_key( a_key ) );
}
catch( const bad_ptr_container_operation& )
{ }
try
{
c2.at( get_next_key( a_key ) );
}
catch( const bad_ptr_container_operation& )
{ }
BOOST_MESSAGE( "finished algorithms interface test" );
typename C::iterator it = c.begin(), e = c.end();
for( ; it != e; ++it )
{
std::cout << "\n mapped value = " << *it->second << " key = " << it->first;
//std::cout << "\n mapped value = " << it.value() << " key = " << it.key();
}
BOOST_MESSAGE( "finished iterator test" );
a_key = get_next_key( a_key );
c.insert( a_key, new T );
c.erase( a_key );
c.erase( a_key );
}
template< class CDerived, class CBase, class T >
void test_transfer()
{
CDerived from;
CBase to;
int key = get_next_key( key );
from.insert( key, new T );
key = get_next_key( key );
from.insert( key, new T );
transfer_test( from, to );
}
template< class BaseContainer, class DerivedContainer, class Derived >
void map_container_assignment_test()
{
DerivedContainer derived;
std::string foo( "foo" );
std::string bar( "foo" );
derived.insert( foo, new Derived );
derived.insert( bar, new Derived );
BaseContainer base_container( derived );
BOOST_CHECK_EQUAL( derived.size(), base_container.size() );
base_container.clear();
base_container = derived;
BOOST_CHECK_EQUAL( derived.size(), base_container.size() );
BaseContainer base2( base_container );
BOOST_CHECK_EQUAL( base2.size(), base_container.size() );
base2 = base_container;
BOOST_CHECK_EQUAL( base2.size(), base_container.size() );
base_container = base_container;
}
template< class Cont, class Key, class T >
void test_unordered_interface()
{
Cont c;
T* t = new T;
Key key = get_next_key( key );
c.insert( key, t );
typename Cont::local_iterator i = c.begin( 0 );
typename Cont::const_local_iterator ci = i;
ci = c.cbegin( 0 );
i = c.end( 0 );
ci = c.cend( 0 );
typename Cont::size_type s = c.bucket_count();
s = c.max_bucket_count();
s = c.bucket_size( 0 );
s = c.bucket( key );
float f = c.load_factor();
f = c.max_load_factor();
c.max_load_factor(f);
c.rehash(1000);
}
#include <boost/ptr_container/ptr_unordered_map.hpp>
using namespace std;
void test_map()
{
ptr_map_test< ptr_unordered_map<int, Base>, Base, Derived_class >();
ptr_map_test< ptr_unordered_map<int, Value>, Value, Value >();
ptr_map_test< ptr_unordered_map<int, nullable<Base> >, Base, Derived_class >();
ptr_map_test< ptr_unordered_map<int, nullable<Value> >, Value, Value >();
ptr_map_test< ptr_unordered_map<int, abstract_base>, abstract_base, implementation >();
ptr_map_test< ptr_unordered_multimap<int,Base>, Base, Derived_class >();
ptr_map_test< ptr_unordered_multimap<int,Value>, Value, Value >();
ptr_map_test< ptr_unordered_multimap<int, nullable<Base> >, Base, Derived_class >();
ptr_map_test< ptr_unordered_multimap<int, nullable<Value> >, Value, Value >();
map_container_assignment_test< ptr_unordered_map<std::string,Base>,
ptr_unordered_map<std::string,Derived_class>,
Derived_class>();
map_container_assignment_test< ptr_unordered_map<std::string, nullable<Base> >,
ptr_unordered_map<std::string,Derived_class>,
Derived_class>();
map_container_assignment_test< ptr_unordered_map<std::string, nullable<Base> >,
ptr_unordered_map<std::string, nullable<Derived_class> >,
Derived_class>();
map_container_assignment_test< ptr_unordered_multimap<std::string,Base>,
ptr_unordered_multimap<std::string,Derived_class>,
Derived_class>();
map_container_assignment_test< ptr_unordered_multimap<std::string, nullable<Base> >,
ptr_unordered_multimap<std::string,Derived_class>,
Derived_class>();
map_container_assignment_test< ptr_unordered_multimap<std::string, nullable<Base> >,
ptr_unordered_multimap<std::string, nullable<Derived_class> >,
Derived_class>();
test_transfer< ptr_unordered_map<int,Derived_class>, ptr_unordered_map<int,Base>, Derived_class >();
test_transfer< ptr_unordered_multimap<int,Derived_class>, ptr_unordered_multimap<int,Base>, Derived_class >();
string joe = "joe";
string brian = "brian";
string kenny = "kenny";
ptr_unordered_map<string,int> m;
m.insert( joe, new int( 4 ) );
m.insert( brian, new int( 6 ) );
BOOST_CHECK( m[ "foo" ] == 0 );
m[ "bar" ] += 5;
BOOST_CHECK( m[ "bar" ] == 5 );
m[ joe ] += 56;
m[ brian ] += 10;
BOOST_CHECK_THROW( (m.insert(kenny, 0 )), bad_ptr_container_operation );
BOOST_CHECK_THROW( (m.replace(m.begin(), 0 )), bad_ptr_container_operation );
BOOST_CHECK_THROW( (m.at("not there")), bad_ptr_container_operation );
for( ptr_unordered_map<string,int>::iterator i = m.begin();
i != m.end(); ++i )
{
if( is_null(i) )
BOOST_CHECK( false );
const string& ref = i->first;
hide_warning(ref);
int& ref2 = *(*i).second;
ref2++;
}
typedef ptr_unordered_map<string,Derived_class> map_type;
map_type m2;
m2.insert( joe, new Derived_class );
//
// This works fine since 'm2' is not const
//
m2.begin()->second->foo();
//
// These all return an implementation-defined proxy
// with two public members: 'first' and 'second'
//
map_type::value_type a_value = *m2.begin();
a_value.second->foo();
map_type::reference a_reference = *m2.begin();
a_reference.second->foo();
map_type::const_reference a_creference = *const_begin(m2);
//
//
// These will fail as iterators propagate constness
//
//a_creference.second->foo();
//a_cpointer->second->foo();
//const_begin(m2)->second->foo();
test_unordered_interface< ptr_unordered_map<string,Base>, string, Derived_class >();
test_unordered_interface< ptr_unordered_map<string,Base>, string, Derived_class >();
}
using boost::unit_test::test_suite;
test_suite* init_unit_test_suite( int argc, char* argv[] )
{
test_suite* test = BOOST_TEST_SUITE( "Pointer Container Test Suite" );
test->add( BOOST_TEST_CASE( &test_map ) );
return test;
}