/*********************************************************************************** test_insert.h * Copyright (c) 1997 * Mark of the Unicorn, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Mark of the Unicorn makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. ***********************************************************************************/ #ifndef test_insert_H_ #define test_insert_H_ # include "Prefix.h" # if defined (EH_NEW_HEADERS) # include <utility> # include <vector> # include <cassert> # include <climits> # else # include <vector.h> # include <assert.h> # include <limits.h> # endif #include "random_number.h" #include "nc_alloc.h" #include "ThrowCompare.h" // A classification system for containers, for verification struct container_tag {}; struct sequence_container_tag {}; struct associative_container_tag {}; struct set_tag {}; struct multiset_tag {}; struct map_tag {}; struct multimap_tag {}; template <class C, class Iter> size_t CountNewItems( const C&, const Iter& firstNew, const Iter& lastNew, sequence_container_tag ) { size_t dist = 0; #if 0 //def __SUNPRO_CC EH_DISTANCE( firstNew, lastNew, dist ); #else EH_DISTANCE( Iter(firstNew), Iter(lastNew), dist ); #endif return dist; } template <class C, class Iter> size_t CountNewItems( const C& c, const Iter& firstNew, const Iter& lastNew, multimap_tag ) { return CountNewItems( c, firstNew, lastNew, sequence_container_tag() ); } template <class C, class Iter> size_t CountNewItems( const C& c, const Iter& firstNew, const Iter& lastNew, multiset_tag ) { return CountNewItems( c, firstNew, lastNew, sequence_container_tag() ); } template <class C, class Iter, class KeyOfValue> #ifdef __BORLANDC__ size_t CountUniqueItems_Aux( const C& original, const Iter& firstNew, #else size_t CountUniqueItems_Aux( const C& original, Iter firstNew, #endif Iter lastNew, const KeyOfValue& keyOfValue ) { typedef typename C::key_type key; typedef typename C::const_iterator const_iter; typedef EH_STD::vector<key> key_list; typedef typename key_list::iterator key_iterator; key_list keys; size_t dist = 0; #ifdef __SUNPRO_CC EH_DISTANCE( firstNew, lastNew, dist ); #else EH_DISTANCE( Iter(firstNew), Iter(lastNew), dist ); #endif keys.reserve( dist ); for ( Iter x = firstNew; x != lastNew; ++x ) keys.push_back( keyOfValue(*x) ); EH_STD::sort( keys.begin(), keys.end() ); key_iterator last = EH_STD::unique( keys.begin(), keys.end() ); size_t cnt = 0; for ( key_iterator tmp = keys.begin(); tmp != last; ++tmp ) { if ( const_iter(original.find( *tmp )) == const_iter(original.end()) ) ++cnt; } return cnt; } #if ! defined (__SGI_STL) EH_BEGIN_NAMESPACE template <class T> struct identity { const T& operator()( const T& x ) const { return x; } }; # if ! defined (__KCC) template <class _Pair> struct select1st : public unary_function<_Pair, typename _Pair::first_type> { const typename _Pair::first_type& operator()(const _Pair& __x) const { return __x.first; } }; # endif EH_END_NAMESPACE #endif template <class C, class Iter> size_t CountUniqueItems( const C& original, const Iter& firstNew, const Iter& lastNew, set_tag ) { typedef typename C::value_type value_type; return CountUniqueItems_Aux( original, firstNew, lastNew, EH_STD::identity<value_type>() ); } template <class C, class Iter> size_t CountUniqueItems( const C& original, const Iter& firstNew, const Iter& lastNew, map_tag ) { #ifdef EH_MULTI_CONST_TEMPLATE_ARG_BUG return CountUniqueItems_Aux( original, firstNew, lastNew, EH_SELECT1ST_HINT<C::value_type, C::key_type>() ); #else typedef typename C::value_type value_type; return CountUniqueItems_Aux( original, firstNew, lastNew, EH_STD::select1st<value_type>() ); #endif } template <class C, class Iter> size_t CountNewItems( const C& original, const Iter& firstNew, const Iter& lastNew, map_tag ) { return CountUniqueItems( original, firstNew, lastNew, container_category( original ) ); } template <class C, class Iter> size_t CountNewItems( const C& original, const Iter& firstNew, const Iter& lastNew, set_tag ) { return CountUniqueItems( original, firstNew, lastNew, container_category( original ) ); } template <class C, class SrcIter> inline void VerifyInsertion( const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t, associative_container_tag ) { typedef typename C::const_iterator DstIter; DstIter first1 = original.begin(); DstIter first2 = result.begin(); DstIter* from_orig = new DstIter[original.size()]; DstIter* last_from_orig = from_orig; // fbp : for hashed containers, the following is needed : while ( first2 != result.end() ) { EH_STD::pair<DstIter, DstIter> p = EH_STD::mismatch( first1, original.end(), first2 ); if ( p.second != result.end() ) { SrcIter srcItem = EH_STD::find( SrcIter(firstNew), SrcIter(lastNew), *p.second ); if (srcItem == lastNew) { // not found in input range, probably re-ordered from the orig DstIter* tmp; tmp = EH_STD::find( from_orig, last_from_orig, p.first ); // if already here, exclude if (tmp != last_from_orig) { EH_STD::copy(tmp+1, last_from_orig, tmp); last_from_orig--; } else { // register re-ordered element DstIter dstItem; dstItem = EH_STD::find( first1, original.end(), *p.first ); EH_ASSERT( dstItem != original.end() ); *last_from_orig = dstItem; last_from_orig++; ++p.first; } } ++p.second; } first1 = p.first; first2 = p.second; } delete [] from_orig; } // VC++ template <class C, class SrcIter> inline void VerifyInsertion( const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t, set_tag ) { VerifyInsertion( original, result, firstNew, lastNew, size_t(0), associative_container_tag() ); } template <class C, class SrcIter> inline void VerifyInsertion(const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t, multiset_tag ) { VerifyInsertion( original, result, firstNew, lastNew, size_t(0), associative_container_tag() ); } template <class C, class SrcIter> inline void VerifyInsertion( const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t, map_tag ) { VerifyInsertion( original, result, firstNew, lastNew, size_t(0), associative_container_tag() ); } template <class C, class SrcIter> inline void VerifyInsertion( const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t, multimap_tag ) { VerifyInsertion( original, result, firstNew, lastNew, size_t(0), associative_container_tag() ); } template <class C, class SrcIter> void VerifyInsertion( # ifdef _MSC_VER const C& original, const C& result, SrcIter firstNew, SrcIter lastNew, size_t insPos, sequence_container_tag ) # else const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t insPos, sequence_container_tag ) # endif { typename C::const_iterator p1 = original.begin(); typename C::const_iterator p2 = result.begin(); SrcIter tmp(firstNew); for ( size_t n = 0; n < insPos; n++, ++p1, ++p2) EH_ASSERT( *p1 == *p2 ); for (; tmp != lastNew; ++p2, ++tmp ) { EH_ASSERT(p2 != result.end()); EH_ASSERT(*p2 == *tmp); } for (; p2 != result.end(); ++p1, ++p2 ) EH_ASSERT( *p1 == *p2 ); EH_ASSERT( p1 == original.end() ); } template <class C, class SrcIter> inline void VerifyInsertion( const C& original, const C& result, const SrcIter& firstNew, const SrcIter& lastNew, size_t insPos ) { EH_ASSERT( result.size() == original.size() + CountNewItems( original, firstNew, lastNew, container_category(original) ) ); VerifyInsertion( original, result, firstNew, lastNew, insPos, container_category(original) ); } template <class C, class Value> void VerifyInsertN( const C& original, const C& result, size_t insCnt, const Value& val, size_t insPos ) { typename C::const_iterator p1 = original.begin(); typename C::const_iterator p2 = result.begin(); (void)val; //*TY 02/06/2000 - to suppress unused variable warning under nondebug build for ( size_t n = 0; n < insPos; n++ ) EH_ASSERT( *p1++ == *p2++ ); while ( insCnt-- > 0 ) { EH_ASSERT(p2 != result.end()); EH_ASSERT(*p2 == val ); ++p2; } while ( p2 != result.end() ) { EH_ASSERT( *p1 == *p2 ); ++p1; ++p2; } EH_ASSERT( p1 == original.end() ); } template <class C> void prepare_insert_n( C&, size_t ) {} // Metrowerks 1.8 compiler requires that specializations appear first (!!) // or it won't call them. Fixed in 1.9, though. inline void MakeRandomValue(bool& b) { b = bool(random_number(2) != 0); } template<class T> inline void MakeRandomValue(T&) {} template <class C> struct test_insert_one { test_insert_one( const C& orig, int pos =-1 ) : original( orig ), fPos( random_number( orig.size() )) { MakeRandomValue( fInsVal ); if ( pos != -1 ) { fPos = size_t(pos); if ( pos == 0 ) gTestController.SetCurrentTestName("single insertion at begin()"); else gTestController.SetCurrentTestName("single insertion at end()"); } else gTestController.SetCurrentTestName("single insertion at random position"); } void operator()( C& c ) const { prepare_insert_n( c, (size_t)1 ); typename C::iterator pos = c.begin(); EH_STD::advance( pos, size_t(fPos) ); c.insert( pos, fInsVal ); // Prevent simulated failures during verification gTestController.CancelFailureCountdown(); // Success. Check results. VerifyInsertion( original, c, &fInsVal, 1+&fInsVal, fPos ); } private: typename C::value_type fInsVal; const C& original; size_t fPos; }; template <class C> struct test_insert_n { test_insert_n( const C& orig, size_t insCnt, int pos =-1 ) : original( orig ), fPos( random_number( orig.size() )), fInsCnt(insCnt) { MakeRandomValue( fInsVal ); if (pos!=-1) { fPos=size_t(pos); if (pos==0) gTestController.SetCurrentTestName("n-ary insertion at begin()"); else gTestController.SetCurrentTestName("n-ary insertion at end()"); } else gTestController.SetCurrentTestName("n-ary insertion at random position"); } void operator()( C& c ) const { prepare_insert_n( c, fInsCnt ); typename C::iterator pos = c.begin(); EH_STD::advance( pos, fPos ); c.insert( pos, fInsCnt, fInsVal ); // Prevent simulated failures during verification gTestController.CancelFailureCountdown(); // Success. Check results. VerifyInsertN( original, c, fInsCnt, fInsVal, fPos ); } private: typename C::value_type fInsVal; const C& original; size_t fPos; size_t fInsCnt; }; template <class C> struct test_insert_value { test_insert_value( const C& orig ) : original( orig ) { MakeRandomValue( fInsVal ); gTestController.SetCurrentTestName("insertion of random value"); } void operator()( C& c ) const { c.insert( fInsVal ); // Prevent simulated failures during verification gTestController.CancelFailureCountdown(); // Success. Check results. VerifyInsertion( original, c, &fInsVal, 1+&fInsVal, size_t(0) ); } private: typename C::value_type fInsVal; const C& original; }; template <class C> struct test_insert_noresize { test_insert_noresize( const C& orig ) : original( orig ) { MakeRandomValue( fInsVal ); gTestController.SetCurrentTestName("insertion of random value without resize"); } void operator()( C& c ) const { c.insert_noresize( fInsVal ); // Prevent simulated failures during verification gTestController.CancelFailureCountdown(); // Success. Check results. VerifyInsertion( original, c, &fInsVal, 1+&fInsVal, size_t(0) ); } private: typename C::value_type fInsVal; const C& original; }; template <class C, class Position, class Iter> void do_insert_range( C& c_inst, Position offset, Iter first, Iter last, sequence_container_tag ) { typedef typename C::iterator CIter; CIter pos = c_inst.begin(); EH_STD::advance( pos, offset ); c_inst.insert( pos, first, last ); } template <class C, class Position, class Iter> void do_insert_range( C& c, Position, Iter first, Iter last, associative_container_tag ) { c.insert( first, last ); } template <class C, class Position, class Iter> void do_insert_range( C& c, Position, Iter first, Iter last, multiset_tag ) { c.insert( first, last ); } template <class C, class Position, class Iter> void do_insert_range( C& c, Position, Iter first, Iter last, multimap_tag ) { c.insert( first, last ); } template <class C, class Position, class Iter> void do_insert_range( C& c, Position, Iter first, Iter last, set_tag ) { c.insert( first, last ); } template <class C, class Position, class Iter> void do_insert_range( C& c, Position, Iter first, Iter last, map_tag ) { c.insert( first, last ); } /* template <class C, class Iter> void prepare_insert_range( C&, size_t, Iter, Iter) {} */ template <class C, class Iter> struct test_insert_range { test_insert_range( const C& orig, Iter first, Iter last, int pos=-1 ) : fFirst( first ), fLast( last ), original( orig ), fPos( random_number( orig.size() )) { gTestController.SetCurrentTestName("range insertion"); if ( pos != -1 ) { fPos = size_t(pos); if ( pos == 0 ) gTestController.SetCurrentTestName("range insertion at begin()"); else gTestController.SetCurrentTestName("range insertion at end()"); } else gTestController.SetCurrentTestName("range insertion at random position"); } void operator()( C& c ) const { // prepare_insert_range( c, fPos, fFirst, fLast ); do_insert_range( c, fPos, fFirst, fLast, container_category(c) ); // Prevent simulated failures during verification gTestController.CancelFailureCountdown(); // Success. Check results. VerifyInsertion( original, c, fFirst, fLast, fPos ); } private: Iter fFirst, fLast; const C& original; size_t fPos; }; template <class C, class Iter> test_insert_range<C, Iter> insert_range_tester( const C& orig, const Iter& first, const Iter& last ) { return test_insert_range<C, Iter>( orig, first, last ); } template <class C, class Iter> test_insert_range<C, Iter> insert_range_at_begin_tester( const C& orig, const Iter& first, const Iter& last ) { return test_insert_range<C, Iter>( orig, first, last , 0); } template <class C, class Iter> test_insert_range<C, Iter> insert_range_at_end_tester( const C& orig, const Iter& first, const Iter& last ) { return test_insert_range<C, Iter>( orig, first, last , (int)orig.size()); } #endif // test_insert_H_