1 //
2 // Boost.Pointer Container
3 //
4 //  Copyright Thorsten Ottosen 2003-2005. Use, modification and
5 //  distribution is subject to the Boost Software License, Version
6 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 //  http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // For more information, see http://www.boost.org/libs/ptr_container/
10 //
11 
12 #include "test_data.hpp"
13 #include <boost/test/unit_test.hpp>
14 #include <boost/ptr_container/exception.hpp>
15 #include <boost/ptr_container/detail/ptr_container_disable_deprecated.hpp>
16 #include <boost/range/sub_range.hpp>
17 #include <boost/cast.hpp>
18 #include <cstdlib>
19 #include <iostream>
20 #include <memory>
21 #include <string>
22 
23 //
24 // abstract base class definition
25 //
26 struct abstract_base
27 {
~abstract_baseabstract_base28     virtual ~abstract_base() {}
29     virtual void foo() = 0;
30     virtual abstract_base* clone() const = 0;
31 };
32 
33 struct implementation : abstract_base
34 {
implementationimplementation35     implementation()
36     { }
37 
implementationimplementation38     implementation( const implementation& )
39     { }
40 
implementationimplementation41     implementation( int, std::string, int, std::string )
42     { }
43 
fooimplementation44     virtual void foo() {}
cloneimplementation45     virtual abstract_base* clone() const
46     {
47         return new implementation( *this );
48     }
49 };
50 
operator <<(std::ostream & out,const abstract_base & r)51 inline std::ostream& operator<<( std::ostream& out, const abstract_base& r )
52 {
53     return out;
54 }
55 
new_clone(const abstract_base & r)56 inline abstract_base* new_clone( const abstract_base& r )
57 {
58     return r.clone();
59 }
60 
61 //
62 // ptr_map test
63 //
64 
65 template< typename C, typename B, typename T >
66 void ptr_map_test();
67 
68 template< class Key >
69 Key get_next_key( const Key& k );
70 
71 template<>
get_next_key(const int &)72 int get_next_key<int>( const int& )
73 {
74     return rand();
75 }
76 
77 template<>
get_next_key(const std::string &)78 std::string get_next_key<std::string>( const std::string& )
79 {
80     return boost::lexical_cast<std::string>( rand() );
81 }
82 
83 #if defined(BOOST_PTR_CONTAINER_DISABLE_DEPRECATED)
84 #pragma GCC diagnostic push
85 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
86 #endif
87 
88 template< typename C, typename B, typename T >
ptr_map_test()89 void ptr_map_test()
90 {
91     using namespace boost;
92 
93     BOOST_TEST_MESSAGE( "starting associative container test" );
94     enum { max_cnt = 10, size = 100 };
95     C  c;
96     BOOST_CHECK( c.size() == 0 );
97 
98     const C c2( c.begin(), c.end() );
99     BOOST_CHECK( c.size() == c2.size() );
100 
101     C c3;
102 
103     BOOST_TEST_MESSAGE( "finished construction test" );
104 
105     BOOST_DEDUCED_TYPENAME C::allocator_type alloc        = c.get_allocator();
106     BOOST_DEDUCED_TYPENAME C::iterator i                  = c.begin();
107     BOOST_DEDUCED_TYPENAME C::const_iterator ci           = c2.begin();
108     BOOST_DEDUCED_TYPENAME C::iterator i2                 = c.end();
109     hide_warning(i2);
110     BOOST_DEDUCED_TYPENAME C::const_iterator ci2          = c2.begin();
111     hide_warning(ci2);
112     BOOST_DEDUCED_TYPENAME C::reverse_iterator ri         = c.rbegin();
113     hide_warning(ri);
114     BOOST_DEDUCED_TYPENAME C::const_reverse_iterator cri  = c2.rbegin();
115     hide_warning(cri);
116     BOOST_DEDUCED_TYPENAME C::reverse_iterator rv2        = c.rend();
117     hide_warning(rv2);
118     BOOST_DEDUCED_TYPENAME C::const_reverse_iterator cvr2 = c2.rend();
119     hide_warning(cvr2);
120 
121     BOOST_DEDUCED_TYPENAME C::key_type a_key;
122 
123     BOOST_TEST_MESSAGE( "finished iterator test" );
124 
125     BOOST_DEDUCED_TYPENAME C::size_type s                 = c.size();
126     BOOST_DEDUCED_TYPENAME C::size_type s2                = c.max_size();
127     hide_warning(s2);
128     BOOST_CHECK_EQUAL( c.size(), s );
129     bool b                                                = c.empty();
130     hide_warning(b);
131     BOOST_TEST_MESSAGE( "finished accessors test" );
132 
133     a_key = get_next_key( a_key );
134     c.insert( a_key, new T );
135     a_key = get_next_key( a_key );
136     c.insert( a_key, new T );
137     c3.insert( c.begin(), c.end() );
138     c.insert( c3 );
139     c.erase( c.begin() );
140     BOOST_CHECK( c3.end() == c3.erase( boost::make_iterator_range(c3) ) );
141     c3.erase( a_key );
142 
143     BOOST_CHECK( c3.empty() );
144     c.swap( c3 );
145     swap(c,c3);
146     swap(c3,c);
147     BOOST_CHECK( !c3.empty() );
148     c3.clear();
149     BOOST_CHECK( c3.empty() );
150     BOOST_TEST_MESSAGE( "finished modifiers test" );
151 
152 
153     a_key = get_next_key( a_key );
154     c.insert( a_key, new T );
155     a_key = get_next_key( a_key );
156 #ifndef BOOST_NO_AUTO_PTR
157     c.insert( a_key, std::auto_ptr<T>( new T ) );
158 #endif
159 #ifndef BOOST_NO_CXX11_SMART_PTR
160     c.insert( a_key, std::unique_ptr<T>( new T ) );
161 #endif
162     typename C::auto_type ptr2  = c.release( c.begin() );
163 #ifndef BOOST_NO_AUTO_PTR
164     std::auto_ptr<C> ap         = c.release();
165 #else
166     std::unique_ptr<C> up       = c.release();
167 #endif
168     c                           = c2.clone();
169     BOOST_TEST_MESSAGE( "finished release/clone test" );
170 
171 
172     a_key = get_next_key( a_key );
173     c3.insert( a_key, new T );
174     a_key = get_next_key( a_key );
175     c3.insert( a_key, new T );
176 
177     c. BOOST_NESTED_TEMPLATE transfer<C>( c3.begin(), c3 );
178     c. BOOST_NESTED_TEMPLATE transfer<C>( c3.begin(), c3.end(), c3 );
179     BOOST_CHECK( c3.empty() );
180     BOOST_CHECK( !c.empty() );
181     c3. BOOST_NESTED_TEMPLATE transfer<C>( c );
182     BOOST_CHECK( !c3.empty() );
183     BOOST_CHECK( c.empty() );
184 #ifdef BOOST_NO_SFINAE
185 #else
186     c. BOOST_NESTED_TEMPLATE transfer<C>( make_iterator_range(c3), c3 );
187     BOOST_CHECK( !c.empty() );
188     BOOST_CHECK( c3.empty() );
189     c3. BOOST_NESTED_TEMPLATE transfer<C>(c);
190 #endif
191     BOOST_TEST_MESSAGE( "finished transfer test" );
192 
193     BOOST_CHECK( !c3.empty() );
194     c3.replace( c3.begin(), new T );
195 #ifndef BOOST_NO_AUTO_PTR
196     c3.replace( c3.begin(), std::auto_ptr<T>( new T ) );
197 #endif
198 #ifndef BOOST_NO_CXX11_SMART_PTR
199     c3.replace( c3.begin(), std::unique_ptr<T>( new T ) );
200 #endif
201     BOOST_TEST_MESSAGE( "finished set/map interface test" );
202 
203     // @todo: make macro with algorithms so that the right erase() is called.
204     //  c.unique();
205     //  c.unique( std::not_equal_to<T>() );
206     //  c.remove( T() );
207     //  c.remove_if( std::binder1st< std::equal_to<T> >( T() ) );
208 
209     sub_range<C>        sub;
210     sub_range<const C> csub;
211 
212     i  = c.find( get_next_key( a_key ) );
213     ci = c2.find( get_next_key( a_key ) );
214     BOOST_CHECK_EQUAL(0, c2.count( get_next_key( a_key ) ));
215     i  = c.lower_bound( get_next_key( a_key ) );
216     ci = c2.lower_bound( get_next_key( a_key ) );
217     i  = c.upper_bound( get_next_key( a_key ) );
218     ci = c2.upper_bound( get_next_key( a_key ) );
219     sub  = c.equal_range( get_next_key( a_key ) );
220     csub = c2.equal_range( get_next_key( a_key ) );
221 
222     try
223     {
224         c.at( get_next_key( a_key ) );
225     }
226     catch( const bad_ptr_container_operation& )
227     { }
228 
229     try
230     {
231         c2.at( get_next_key( a_key ) );
232     }
233     catch( const bad_ptr_container_operation& )
234     { }
235 
236     BOOST_TEST_MESSAGE( "finished algorithms interface test" );
237 
238     typename C::iterator it = c.begin(), e = c.end();
239     for( ; it != e; ++it )
240     {
241         std::cout << "\n mapped value = " << *it->second << " key = " << it->first;
242         //std::cout << "\n mapped value = " << it.value() << " key = " << it.key();
243     }
244 
245     typename C::reverse_iterator rit = c.rbegin(), re = c.rend();
246     for( ; rit != re; ++rit )
247     {
248         std::cout << "\n mapped value = " << *rit->second << " key = " << rit->first;
249         //std::cout << "\n mapped value = " << rit.value() << " key = " << rit.key();
250         //std::cout << "\n mapped value (base) = "
251         //          << rit.base().value() << " key = " << rit.base().key();
252     }
253 
254     typename C::const_reverse_iterator crit = c2.rbegin(), cre = c2.rend();
255     for( ; crit != cre; ++crit )
256     {
257         std::cout << "\n mapped value = " << *(*crit).second << " key = " << (*crit).first;
258         //std::cout << "\n mapped value = " << crit.value() << " key = " << crit.key();
259         //std::cout << "\n mapped value (base) = "
260         //          << crit.base().value() << " key = " << crit.base().key();
261     }
262 
263     BOOST_TEST_MESSAGE( "finished iterator test" );
264 
265     a_key = get_next_key( a_key );
266     c.insert( a_key, new T );
267     c.erase( a_key );
268     c.erase( a_key );
269 
270 }
271 
272 #if defined(BOOST_PTR_CONTAINER_DISABLE_DEPRECATED)
273 #pragma GCC diagnostic pop
274 #endif
275 
276 
277 
278 template< class CDerived, class CBase, class T >
test_transfer()279 void test_transfer()
280 {
281     CDerived from;
282     CBase    to;
283 
284     int key = get_next_key( key );
285     from.insert( key, new T );
286     key = get_next_key( key );
287     from.insert( key, new T );
288     transfer_test( from, to );
289 }
290 
291 
292 
293 template< class BaseContainer, class DerivedContainer, class Derived >
map_container_assignment_test()294 void map_container_assignment_test()
295 {
296     DerivedContainer derived;
297     std::string foo( "foo" );
298     std::string bar( "foo" );
299     derived.insert( foo, new Derived );
300     derived.insert( bar, new Derived );
301 
302     BaseContainer base_container( derived );
303     BOOST_CHECK_EQUAL( derived.size(), base_container.size() );
304     base_container.clear();
305     base_container = derived;
306     BOOST_CHECK_EQUAL( derived.size(), base_container.size() );
307 
308     BaseContainer base2( base_container );
309     BOOST_CHECK_EQUAL( base2.size(), base_container.size() );
310     base2 = base_container;
311     BOOST_CHECK_EQUAL( base2.size(), base_container.size() );
312     base_container = base_container;
313 }
314 
315 
316 
317 #include <boost/ptr_container/ptr_map.hpp>
318 
319 using namespace std;
320 
test_map()321 void test_map()
322 {
323     ptr_map_test< ptr_map<int, Base>, Base, Derived_class >();
324     ptr_map_test< ptr_map<int, Value>, Value, Value >();
325     ptr_map_test< ptr_map<int, nullable<Base> >, Base, Derived_class >();
326     ptr_map_test< ptr_map<int, nullable<Value> >, Value, Value >();
327     ptr_map_test< ptr_map<int, abstract_base>, abstract_base, implementation >();
328 
329     ptr_map_test< ptr_multimap<int,Base>, Base, Derived_class >();
330     ptr_map_test< ptr_multimap<int,Value>, Value, Value >();
331     ptr_map_test< ptr_multimap<int, nullable<Base> >, Base, Derived_class >();
332     ptr_map_test< ptr_multimap<int, nullable<Value> >, Value, Value >();
333 
334     map_container_assignment_test< ptr_map<std::string,Base>,
335                                    ptr_map<std::string,Derived_class>,
336                                    Derived_class>();
337     map_container_assignment_test< ptr_map<std::string, nullable<Base> >,
338                                    ptr_map<std::string,Derived_class>,
339                                    Derived_class>();
340     map_container_assignment_test< ptr_map<std::string, nullable<Base> >,
341                                    ptr_map<std::string, nullable<Derived_class> >,
342                                    Derived_class>();
343    map_container_assignment_test< ptr_multimap<std::string,Base>,
344                                    ptr_multimap<std::string,Derived_class>,
345                                    Derived_class>();
346     map_container_assignment_test< ptr_multimap<std::string, nullable<Base> >,
347                                    ptr_multimap<std::string,Derived_class>,
348                                    Derived_class>();
349     map_container_assignment_test< ptr_multimap<std::string, nullable<Base> >,
350                                    ptr_multimap<std::string, nullable<Derived_class> >,
351                                    Derived_class>();
352 
353 
354     test_transfer< ptr_map<int,Derived_class>, ptr_map<int,Base>, Derived_class >();
355     test_transfer< ptr_multimap<int,Derived_class>, ptr_multimap<int,Base>, Derived_class >();
356 
357     string joe   = "joe";
358     string brian = "brian";
359     string kenny = "kenny";
360 
361     ptr_map<string,int> m;
362     m.insert( joe, new int( 4 ) );
363     m.insert( brian, new int( 6 ) );
364     BOOST_CHECK( m[ "foo" ] == 0 );
365     m[ "bar" ] += 5;
366     BOOST_CHECK( m[ "bar" ] == 5 );
367     m[ joe ]   += 56;
368     m[ brian ] += 10;
369 
370     BOOST_CHECK_THROW( (m.insert(kenny, 0 )), bad_ptr_container_operation );
371     BOOST_CHECK_THROW( (m.replace(m.begin(), 0 )), bad_ptr_container_operation );
372     BOOST_CHECK_THROW( (m.at("not there")), bad_ptr_container_operation );
373 
374     for( ptr_map<string,int>::iterator i = m.begin();
375          i != m.end(); ++i )
376     {
377         if( is_null(i) )
378             BOOST_CHECK( false );
379         const string& ref  = i->first;
380         hide_warning(ref);
381         int&          ref2 = *(*i).second;
382         ref2++;
383     }
384 
385     typedef ptr_map<string,Derived_class> map_type;
386     map_type m2;
387     m2.insert( joe, new Derived_class );
388     //
389     // This works fine since 'm2' is not const
390     //
391     m2.begin()->second->foo();
392 
393     //
394     // These all return an implementation-defined proxy
395     // with two public members: 'first' and 'second'
396     //
397     map_type::value_type       a_value      = *m2.begin();
398     a_value.second->foo();
399     map_type::reference        a_reference  = *m2.begin();
400     a_reference.second->foo();
401     map_type::const_reference  a_creference = *const_begin(m2);
402     hide_warning(a_creference);
403 
404     //
405     //
406     // These will fail as iterators propagate constness
407     //
408     //a_creference.second->foo();
409     //a_cpointer->second->foo();
410     //const_begin(m2)->second->foo();
411 
412 }
413 
414 #include <boost/tuple/tuple.hpp>
415 #include <boost/iterator/zip_iterator.hpp>
416 #include <map>
417 #include <boost/ptr_container/ptr_map.hpp>
418 
test_map_iterators()419 void test_map_iterators()
420 {
421     using boost::zip_iterator;
422     using boost::tuple;
423     using boost::make_tuple;
424     using boost::ptr_map;
425     using std::map;
426 
427     //typedef map<int, int> theMapType;
428     /*
429     @remark: the following will not compile
430              because of the proxy (non-reference) returned by operator*()
431              of the ptr_map's iterator type.
432 
433     typedef boost::ptr_map<int, int> theMapType;
434     typedef zip_iterator
435         <tuple<theMapType::iterator, theMapType::iterator> > zipIter;
436     theMapType map1;
437     theMapType map2;
438     zipIter zip(make_tuple(map1.begin(), map2.begin()));
439     */
440 }
441 
442 
443 
444 using boost::unit_test::test_suite;
445 
init_unit_test_suite(int argc,char * argv[])446 test_suite* init_unit_test_suite( int argc, char* argv[] )
447 {
448     test_suite* test = BOOST_TEST_SUITE( "Pointer Container Test Suite" );
449 
450     test->add( BOOST_TEST_CASE( &test_map ) );
451     test->add( BOOST_TEST_CASE( &test_map_iterators ) );
452 
453     return test;
454 }
455