Home | History | Annotate | Download | only in test
      1 #include "test_precomp.hpp"
      2 
      3 using namespace cv;
      4 using namespace std;
      5 
      6 typedef  struct  CvTsSimpleSeq
      7 {
      8     schar* array;
      9     int   count;
     10     int   max_count;
     11     int   elem_size;
     12 } CvTsSimpleSeq;
     13 
     14 
     15 static CvTsSimpleSeq*  cvTsCreateSimpleSeq( int max_count, int elem_size )
     16 {
     17     CvTsSimpleSeq* seq = (CvTsSimpleSeq*)cvAlloc( sizeof(*seq) + max_count * elem_size );
     18     seq->elem_size = elem_size;
     19     seq->max_count = max_count;
     20     seq->count = 0;
     21     seq->array = (schar*)(seq + 1);
     22     return seq;
     23 }
     24 
     25 
     26 static void cvTsReleaseSimpleSeq( CvTsSimpleSeq** seq )
     27 {
     28     cvFree( seq );
     29 }
     30 
     31 
     32 static schar*  cvTsSimpleSeqElem( CvTsSimpleSeq* seq, int index )
     33 {
     34     assert( 0 <= index && index < seq->count );
     35     return seq->array + index * seq->elem_size;
     36 }
     37 
     38 
     39 static void  cvTsClearSimpleSeq( CvTsSimpleSeq* seq )
     40 {
     41     seq->count = 0;
     42 }
     43 
     44 
     45 static void cvTsSimpleSeqShiftAndCopy( CvTsSimpleSeq* seq, int from_idx, int to_idx, void* elem=0 )
     46 {
     47     int elem_size = seq->elem_size;
     48 
     49     if( from_idx == to_idx )
     50         return;
     51     assert( (from_idx > to_idx && !elem) || (from_idx < to_idx && elem) );
     52 
     53     if( from_idx < seq->count )
     54     {
     55         memmove( seq->array + to_idx*elem_size, seq->array + from_idx*elem_size,
     56                 (seq->count - from_idx)*elem_size );
     57     }
     58     seq->count += to_idx - from_idx;
     59     if( elem && to_idx > from_idx )
     60         memcpy( seq->array + from_idx*elem_size, elem, (to_idx - from_idx)*elem_size );
     61 }
     62 
     63 static void cvTsSimpleSeqInvert( CvTsSimpleSeq* seq )
     64 {
     65     int i, k, len = seq->count, elem_size = seq->elem_size;
     66     schar *data = seq->array, t;
     67 
     68     for( i = 0; i < len/2; i++ )
     69     {
     70         schar* a = data + i*elem_size;
     71         schar* b = data + (len - i - 1)*elem_size;
     72         for( k = 0; k < elem_size; k++ )
     73             CV_SWAP( a[k], b[k], t );
     74     }
     75 }
     76 
     77 /****************************************************************************************\
     78  *                                simple cvset implementation                               *
     79  \****************************************************************************************/
     80 
     81 typedef  struct  CvTsSimpleSet
     82 {
     83     schar* array;
     84     int   count, max_count;
     85     int   elem_size;
     86     int*  free_stack;
     87     int   free_count;
     88 } CvTsSimpleSet;
     89 
     90 
     91 static void  cvTsClearSimpleSet( CvTsSimpleSet* set_header )
     92 {
     93     int i;
     94     int elem_size = set_header->elem_size;
     95 
     96     for( i = 0; i < set_header->max_count; i++ )
     97     {
     98         set_header->array[i*elem_size] = 0;
     99         set_header->free_stack[i] = set_header->max_count - i - 1;
    100     }
    101     set_header->free_count = set_header->max_count;
    102     set_header->count = 0;
    103 }
    104 
    105 
    106 static CvTsSimpleSet*  cvTsCreateSimpleSet( int max_count, int elem_size )
    107 {
    108     CvTsSimpleSet* set_header = (CvTsSimpleSet*)cvAlloc( sizeof(*set_header) + max_count *
    109                                                         (elem_size + 1 + sizeof(int)));
    110     set_header->elem_size = elem_size + 1;
    111     set_header->max_count = max_count;
    112     set_header->free_stack = (int*)(set_header + 1);
    113     set_header->array = (schar*)(set_header->free_stack + max_count);
    114 
    115     cvTsClearSimpleSet( set_header );
    116     return set_header;
    117 }
    118 
    119 
    120 static void cvTsReleaseSimpleSet( CvTsSimpleSet** set_header )
    121 {
    122     cvFree( set_header );
    123 }
    124 
    125 
    126 static schar*  cvTsSimpleSetFind( CvTsSimpleSet* set_header, int index )
    127 {
    128     int idx = index * set_header->elem_size;
    129     assert( 0 <= index && index < set_header->max_count );
    130     return set_header->array[idx] ? set_header->array + idx + 1 : 0;
    131 }
    132 
    133 
    134 static int  cvTsSimpleSetAdd( CvTsSimpleSet* set_header, void* elem )
    135 {
    136     int idx, idx2;
    137     assert( set_header->free_count > 0 );
    138 
    139     idx = set_header->free_stack[--set_header->free_count];
    140     idx2 = idx * set_header->elem_size;
    141     assert( set_header->array[idx2] == 0 );
    142     set_header->array[idx2] = 1;
    143     if( set_header->elem_size > 1 )
    144         memcpy( set_header->array + idx2 + 1, elem, set_header->elem_size - 1 );
    145     set_header->count = MAX( set_header->count, idx + 1 );
    146 
    147     return idx;
    148 }
    149 
    150 
    151 static void  cvTsSimpleSetRemove( CvTsSimpleSet* set_header, int index )
    152 {
    153     assert( set_header->free_count < set_header->max_count &&
    154            0 <= index && index < set_header->max_count );
    155     assert( set_header->array[index * set_header->elem_size] == 1 );
    156 
    157     set_header->free_stack[set_header->free_count++] = index;
    158     set_header->array[index * set_header->elem_size] = 0;
    159 }
    160 
    161 
    162 /****************************************************************************************\
    163  *                              simple graph implementation                               *
    164  \****************************************************************************************/
    165 
    166 typedef  struct  CvTsSimpleGraph
    167 {
    168     char* matrix;
    169     int   edge_size;
    170     int   oriented;
    171     CvTsSimpleSet* vtx;
    172 } CvTsSimpleGraph;
    173 
    174 
    175 static void  cvTsClearSimpleGraph( CvTsSimpleGraph* graph )
    176 {
    177     int max_vtx_count = graph->vtx->max_count;
    178     cvTsClearSimpleSet( graph->vtx );
    179     memset( graph->matrix, 0, max_vtx_count * max_vtx_count * graph->edge_size );
    180 }
    181 
    182 
    183 static CvTsSimpleGraph*  cvTsCreateSimpleGraph( int max_vtx_count, int vtx_size,
    184                                                int edge_size, int oriented )
    185 {
    186     CvTsSimpleGraph* graph;
    187 
    188     assert( max_vtx_count > 1 && vtx_size >= 0 && edge_size >= 0 );
    189     graph = (CvTsSimpleGraph*)cvAlloc( sizeof(*graph) +
    190                                       max_vtx_count * max_vtx_count * (edge_size + 1));
    191     graph->vtx = cvTsCreateSimpleSet( max_vtx_count, vtx_size );
    192     graph->edge_size = edge_size + 1;
    193     graph->matrix = (char*)(graph + 1);
    194     graph->oriented = oriented;
    195 
    196     cvTsClearSimpleGraph( graph );
    197     return graph;
    198 }
    199 
    200 
    201 static void cvTsReleaseSimpleGraph( CvTsSimpleGraph** graph )
    202 {
    203     if( *graph )
    204     {
    205         cvTsReleaseSimpleSet( &(graph[0]->vtx) );
    206         cvFree( graph );
    207     }
    208 }
    209 
    210 
    211 static int  cvTsSimpleGraphAddVertex( CvTsSimpleGraph* graph, void* vertex )
    212 {
    213     return cvTsSimpleSetAdd( graph->vtx, vertex );
    214 }
    215 
    216 
    217 static void  cvTsSimpleGraphRemoveVertex( CvTsSimpleGraph* graph, int index )
    218 {
    219     int i, max_vtx_count = graph->vtx->max_count;
    220     int edge_size = graph->edge_size;
    221     cvTsSimpleSetRemove( graph->vtx, index );
    222 
    223     /* remove all the corresponding edges */
    224     for( i = 0; i < max_vtx_count; i++ )
    225     {
    226         graph->matrix[(i*max_vtx_count + index)*edge_size] =
    227         graph->matrix[(index*max_vtx_count + i)*edge_size] = 0;
    228     }
    229 }
    230 
    231 
    232 static void cvTsSimpleGraphAddEdge( CvTsSimpleGraph* graph, int idx1, int idx2, void* edge )
    233 {
    234     int i, t, n = graph->oriented ? 1 : 2;
    235 
    236     assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
    237            cvTsSimpleSetFind( graph->vtx, idx2 ));
    238 
    239     for( i = 0; i < n; i++ )
    240     {
    241         int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
    242         assert( graph->matrix[ofs] == 0 );
    243         graph->matrix[ofs] = 1;
    244         if( graph->edge_size > 1 )
    245             memcpy( graph->matrix + ofs + 1, edge, graph->edge_size - 1 );
    246 
    247         CV_SWAP( idx1, idx2, t );
    248     }
    249 }
    250 
    251 
    252 static void  cvTsSimpleGraphRemoveEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
    253 {
    254     int i, t, n = graph->oriented ? 1 : 2;
    255 
    256     assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
    257            cvTsSimpleSetFind( graph->vtx, idx2 ));
    258 
    259     for( i = 0; i < n; i++ )
    260     {
    261         int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
    262         assert( graph->matrix[ofs] == 1 );
    263         graph->matrix[ofs] = 0;
    264         CV_SWAP( idx1, idx2, t );
    265     }
    266 }
    267 
    268 
    269 static schar*  cvTsSimpleGraphFindVertex( CvTsSimpleGraph* graph, int index )
    270 {
    271     return cvTsSimpleSetFind( graph->vtx, index );
    272 }
    273 
    274 
    275 static char*  cvTsSimpleGraphFindEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
    276 {
    277     if( cvTsSimpleGraphFindVertex( graph, idx1 ) &&
    278        cvTsSimpleGraphFindVertex( graph, idx2 ))
    279     {
    280         char* edge = graph->matrix + (idx1 * graph->vtx->max_count + idx2)*graph->edge_size;
    281         if( edge[0] ) return edge + 1;
    282     }
    283     return 0;
    284 }
    285 
    286 
    287 static int  cvTsSimpleGraphVertexDegree( CvTsSimpleGraph* graph, int index )
    288 {
    289     int i, count = 0;
    290     int edge_size = graph->edge_size;
    291     int max_vtx_count = graph->vtx->max_count;
    292     assert( cvTsSimpleGraphFindVertex( graph, index ) != 0 );
    293 
    294     for( i = 0; i < max_vtx_count; i++ )
    295     {
    296         count += graph->matrix[(i*max_vtx_count + index)*edge_size] +
    297         graph->matrix[(index*max_vtx_count + i)*edge_size];
    298     }
    299 
    300     if( !graph->oriented )
    301     {
    302         assert( count % 2 == 0 );
    303         count /= 2;
    304     }
    305     return count;
    306 }
    307 
    308 
    309 ///////////////////////////////////// the tests //////////////////////////////////
    310 
    311 #define CV_TS_SEQ_CHECK_CONDITION( expr, err_msg )          \
    312 if( !(expr) )                                               \
    313 {                                                           \
    314 set_error_context( #expr, err_msg, __FILE__, __LINE__ );    \
    315 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );\
    316 throw -1;                                                   \
    317 }
    318 
    319 class Core_DynStructBaseTest : public cvtest::BaseTest
    320 {
    321 public:
    322     Core_DynStructBaseTest();
    323     virtual ~Core_DynStructBaseTest();
    324     bool can_do_fast_forward();
    325     void clear();
    326 
    327 protected:
    328     int read_params( CvFileStorage* fs );
    329     void run_func(void);
    330     void set_error_context( const char* condition,
    331                            const char* err_msg,
    332                            const char* file, int line );
    333     int test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total );
    334     void update_progressbar();
    335 
    336     int struct_count, max_struct_size, iterations, generations;
    337     int min_log_storage_block_size, max_log_storage_block_size;
    338     int min_log_elem_size, max_log_elem_size;
    339     int gen, struct_idx, iter;
    340     int test_progress;
    341     int64 start_time;
    342     double cpu_freq;
    343     vector<void*> cxcore_struct;
    344     vector<void*> simple_struct;
    345     Ptr<CvMemStorage> storage;
    346 };
    347 
    348 
    349 Core_DynStructBaseTest::Core_DynStructBaseTest()
    350 {
    351     struct_count = 2;
    352     max_struct_size = 2000;
    353     min_log_storage_block_size = 7;
    354     max_log_storage_block_size = 12;
    355     min_log_elem_size = 0;
    356     max_log_elem_size = 8;
    357     generations = 10;
    358     iterations = max_struct_size*2;
    359     gen = struct_idx = iter = -1;
    360     test_progress = -1;
    361 }
    362 
    363 
    364 Core_DynStructBaseTest::~Core_DynStructBaseTest()
    365 {
    366     clear();
    367 }
    368 
    369 
    370 void Core_DynStructBaseTest::run_func()
    371 {
    372 }
    373 
    374 bool Core_DynStructBaseTest::can_do_fast_forward()
    375 {
    376     return false;
    377 }
    378 
    379 
    380 void Core_DynStructBaseTest::clear()
    381 {
    382     cvtest::BaseTest::clear();
    383 }
    384 
    385 
    386 int Core_DynStructBaseTest::read_params( CvFileStorage* fs )
    387 {
    388     int code = cvtest::BaseTest::read_params( fs );
    389     double sqrt_scale = sqrt(ts->get_test_case_count_scale());
    390     if( code < 0 )
    391         return code;
    392 
    393     struct_count = cvReadInt( find_param( fs, "struct_count" ), struct_count );
    394     max_struct_size = cvReadInt( find_param( fs, "max_struct_size" ), max_struct_size );
    395     generations = cvReadInt( find_param( fs, "generations" ), generations );
    396     iterations = cvReadInt( find_param( fs, "iterations" ), iterations );
    397     generations = cvRound(generations*sqrt_scale);
    398     iterations = cvRound(iterations*sqrt_scale);
    399 
    400     min_log_storage_block_size = cvReadInt( find_param( fs, "min_log_storage_block_size" ),
    401                                            min_log_storage_block_size );
    402     max_log_storage_block_size = cvReadInt( find_param( fs, "max_log_storage_block_size" ),
    403                                            max_log_storage_block_size );
    404     min_log_elem_size = cvReadInt( find_param( fs, "min_log_elem_size" ), min_log_elem_size );
    405     max_log_elem_size = cvReadInt( find_param( fs, "max_log_elem_size" ), max_log_elem_size );
    406 
    407     struct_count = cvtest::clipInt( struct_count, 1, 100 );
    408     max_struct_size = cvtest::clipInt( max_struct_size, 1, 1<<20 );
    409     generations = cvtest::clipInt( generations, 1, 100 );
    410     iterations = cvtest::clipInt( iterations, 100, 1<<20 );
    411 
    412     min_log_storage_block_size = cvtest::clipInt( min_log_storage_block_size, 7, 20 );
    413     max_log_storage_block_size = cvtest::clipInt( max_log_storage_block_size,
    414                                              min_log_storage_block_size, 20 );
    415 
    416     min_log_elem_size = cvtest::clipInt( min_log_elem_size, 0, 8 );
    417     max_log_elem_size = cvtest::clipInt( max_log_elem_size, min_log_elem_size, 10 );
    418 
    419     return 0;
    420 }
    421 
    422 
    423 void Core_DynStructBaseTest::update_progressbar()
    424 {
    425     int64 t;
    426 
    427     if( test_progress < 0 )
    428     {
    429         test_progress = 0;
    430         cpu_freq = cv::getTickFrequency();
    431         start_time = cv::getTickCount();
    432     }
    433 
    434     t = cv::getTickCount();
    435     test_progress = update_progress( test_progress, 0, 0, (double)(t - start_time)/cpu_freq );
    436 }
    437 
    438 
    439 void Core_DynStructBaseTest::set_error_context( const char* condition,
    440                                                 const char* err_msg,
    441                                                 const char* filename, int lineno )
    442 {
    443     ts->printf( cvtest::TS::LOG, "file %s, line %d: %s\n(\"%s\" failed).\n"
    444                "generation = %d, struct_idx = %d, iter = %d\n",
    445                filename, lineno, err_msg, condition, gen, struct_idx, iter );
    446     ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
    447 }
    448 
    449 
    450 int Core_DynStructBaseTest::test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total )
    451 {
    452     int sum = 0;
    453     struct_idx = _struct_idx;
    454 
    455     CV_TS_SEQ_CHECK_CONDITION( seq != 0, "Null sequence pointer" );
    456 
    457     if( seq->first )
    458     {
    459         CvSeqBlock* block = seq->first;
    460         CvSeqBlock* prev_block = block->prev;
    461 
    462         int delta_idx = seq->first->start_index;
    463 
    464         for( ;; )
    465         {
    466             CV_TS_SEQ_CHECK_CONDITION( sum == block->start_index - delta_idx &&
    467                                       block->count > 0 && block->prev == prev_block &&
    468                                       prev_block->next == block,
    469                                       "sequence blocks are inconsistent" );
    470             sum += block->count;
    471             prev_block = block;
    472             block = block->next;
    473             if( block == seq->first ) break;
    474         }
    475 
    476         CV_TS_SEQ_CHECK_CONDITION( block->prev->count * seq->elem_size +
    477                                   block->prev->data <= seq->block_max,
    478                                   "block->data or block_max pointer are incorrect" );
    479     }
    480 
    481     CV_TS_SEQ_CHECK_CONDITION( seq->total == sum && sum == total,
    482                               "total number of elements is incorrect" );
    483 
    484     return 0;
    485 }
    486 
    487 
    488 /////////////////////////////////// sequence tests ////////////////////////////////////
    489 
    490 class Core_SeqBaseTest : public Core_DynStructBaseTest
    491 {
    492 public:
    493     Core_SeqBaseTest();
    494     void clear();
    495     void run( int );
    496 
    497 protected:
    498     int test_multi_create();
    499     int test_get_seq_elem( int _struct_idx, int iters );
    500     int test_get_seq_reading( int _struct_idx, int iters );
    501     int test_seq_ops( int iters );
    502 };
    503 
    504 
    505 Core_SeqBaseTest::Core_SeqBaseTest()
    506 {
    507 }
    508 
    509 
    510 void Core_SeqBaseTest::clear()
    511 {
    512     for( size_t i = 0; i < simple_struct.size(); i++ )
    513         cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
    514     Core_DynStructBaseTest::clear();
    515 }
    516 
    517 
    518 int Core_SeqBaseTest::test_multi_create()
    519 {
    520     vector<CvSeqWriter> writer(struct_count);
    521     vector<int> pos(struct_count);
    522     vector<int> index(struct_count);
    523     int  cur_count, elem_size;
    524     RNG& rng = ts->get_rng();
    525 
    526     for( int i = 0; i < struct_count; i++ )
    527     {
    528         double t;
    529         CvTsSimpleSeq* sseq;
    530 
    531         pos[i] = -1;
    532         index[i] = i;
    533 
    534         t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
    535         elem_size = cvRound( exp(t * CV_LOG2) );
    536         elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) -
    537                                           sizeof(CvSeqBlock) - sizeof(CvMemBlock)) );
    538 
    539         cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
    540         simple_struct[i] = sseq = cvTsCreateSimpleSeq( max_struct_size, elem_size );
    541         cxcore_struct[i] = 0;
    542         sseq->count = cvtest::randInt( rng ) % max_struct_size;
    543         Mat m( 1, MAX(sseq->count,1)*elem_size, CV_8UC1, sseq->array );
    544         cvtest::randUni( rng, m, Scalar::all(0), Scalar::all(256) );
    545     }
    546 
    547     for( cur_count = struct_count; cur_count > 0; cur_count-- )
    548     {
    549         for(;;)
    550         {
    551             int k = cvtest::randInt( rng ) % cur_count;
    552             struct_idx = index[k];
    553             CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
    554 
    555             if( pos[struct_idx] < 0 )
    556             {
    557                 int hdr_size = (cvtest::randInt(rng) % 10)*4 + sizeof(CvSeq);
    558                 hdr_size = MIN( hdr_size, (int)(storage->block_size - sizeof(CvMemBlock)) );
    559                 elem_size = sseq->elem_size;
    560 
    561                 if( cvtest::randInt(rng) % 2 )
    562                 {
    563                     cvStartWriteSeq( 0, hdr_size, elem_size, storage, &writer[struct_idx] );
    564                 }
    565                 else
    566                 {
    567                     CvSeq* s;
    568                     s = cvCreateSeq( 0, hdr_size, elem_size, storage );
    569                     cvStartAppendToSeq( s, &writer[struct_idx] );
    570                 }
    571 
    572                 cvSetSeqBlockSize( writer[struct_idx].seq, cvtest::randInt( rng ) % 10000 );
    573                 pos[struct_idx] = 0;
    574             }
    575 
    576             update_progressbar();
    577             if( pos[struct_idx] == sseq->count )
    578             {
    579                 cxcore_struct[struct_idx] = cvEndWriteSeq( &writer[struct_idx] );
    580                 /* del index */
    581                 for( ; k < cur_count-1; k++ )
    582                     index[k] = index[k+1];
    583                 break;
    584             }
    585 
    586             {
    587                 schar* el = cvTsSimpleSeqElem( sseq, pos[struct_idx] );
    588                 CV_WRITE_SEQ_ELEM_VAR( el, writer[struct_idx] );
    589             }
    590             pos[struct_idx]++;
    591         }
    592     }
    593 
    594     return 0;
    595 }
    596 
    597 
    598 int  Core_SeqBaseTest::test_get_seq_elem( int _struct_idx, int iters )
    599 {
    600     RNG& rng = ts->get_rng();
    601 
    602     CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
    603     CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
    604     struct_idx = _struct_idx;
    605 
    606     assert( seq->total == sseq->count );
    607 
    608     if( sseq->count == 0 )
    609         return 0;
    610 
    611     for( int i = 0; i < iters; i++ )
    612     {
    613         int idx = cvtest::randInt(rng) % (sseq->count*3) - sseq->count*3/2;
    614         int idx0 = (unsigned)idx < (unsigned)(sseq->count) ? idx : idx < 0 ?
    615         idx + sseq->count : idx - sseq->count;
    616         int bad_range = (unsigned)idx0 >= (unsigned)(sseq->count);
    617         schar* elem;
    618          elem = cvGetSeqElem( seq, idx );
    619 
    620         if( bad_range )
    621         {
    622             CV_TS_SEQ_CHECK_CONDITION( elem == 0,
    623                                       "cvGetSeqElem doesn't "
    624                                       "handle \"out of range\" properly" );
    625         }
    626         else
    627         {
    628             CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
    629                                       !memcmp( elem, cvTsSimpleSeqElem(sseq, idx0), sseq->elem_size ),
    630                                       "cvGetSeqElem returns wrong element" );
    631 
    632              idx = cvSeqElemIdx(seq, elem );
    633             CV_TS_SEQ_CHECK_CONDITION( idx >= 0 && idx == idx0,
    634                                       "cvSeqElemIdx is incorrect" );
    635         }
    636     }
    637 
    638     return 0;
    639 }
    640 
    641 
    642 int  Core_SeqBaseTest::test_get_seq_reading( int _struct_idx, int iters )
    643 {
    644     const int max_val = 3*5 + 2;
    645     CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
    646     CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
    647     int total = seq->total;
    648     RNG& rng = ts->get_rng();
    649     CvSeqReader reader;
    650     vector<schar> _elem(sseq->elem_size);
    651     schar* elem = &_elem[0];
    652 
    653     assert( total == sseq->count );
    654     this->struct_idx = _struct_idx;
    655 
    656     int pos = cvtest::randInt(rng) % 2;
    657     cvStartReadSeq( seq, &reader, pos );
    658 
    659     if( total == 0 )
    660     {
    661         CV_TS_SEQ_CHECK_CONDITION( reader.ptr == 0, "Empty sequence reader pointer is not NULL" );
    662         return 0;
    663     }
    664 
    665     pos = pos ? seq->total - 1 : 0;
    666 
    667     CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos(&reader),
    668                               "initial reader position is wrong" );
    669 
    670     for( iter = 0; iter < iters; iter++ )
    671     {
    672         int op = cvtest::randInt(rng) % max_val;
    673 
    674         if( op >= max_val - 2 )
    675         {
    676             int new_pos, new_pos0;
    677             int bad_range;
    678             int is_relative = op == max_val - 1;
    679 
    680             new_pos = cvtest::randInt(rng) % (total*2) - total;
    681             new_pos0 = new_pos + (is_relative ? pos : 0 );
    682 
    683             if( new_pos0 < 0 ) new_pos0 += total;
    684             if( new_pos0 >= total ) new_pos0 -= total;
    685 
    686             bad_range = (unsigned)new_pos0 >= (unsigned)total;
    687              cvSetSeqReaderPos( &reader, new_pos, is_relative );
    688 
    689             if( !bad_range )
    690             {
    691                 CV_TS_SEQ_CHECK_CONDITION( new_pos0 == cvGetSeqReaderPos( &reader ),
    692                                           "cvset reader position doesn't work" );
    693                 pos = new_pos0;
    694             }
    695             else
    696             {
    697                 CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
    698                                           "reader doesn't stay at the current position after wrong positioning" );
    699             }
    700         }
    701         else
    702         {
    703             int direction = (op % 3) - 1;
    704             memcpy( elem, reader.ptr, sseq->elem_size );
    705 
    706             if( direction > 0 )
    707             {
    708                 CV_NEXT_SEQ_ELEM( sseq->elem_size, reader );
    709             }
    710             else if( direction < 0 )
    711             {
    712                 CV_PREV_SEQ_ELEM( sseq->elem_size, reader );
    713             }
    714 
    715             CV_TS_SEQ_CHECK_CONDITION( memcmp(elem, cvTsSimpleSeqElem(sseq, pos),
    716                                               sseq->elem_size) == 0, "reading is incorrect" );
    717             pos += direction;
    718             if( -pos > 0 ) pos += total;
    719             if( pos >= total ) pos -= total;
    720 
    721             CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
    722                                       "reader doesn't move correctly after reading" );
    723         }
    724     }
    725 
    726     return 0;
    727 }
    728 
    729 
    730 int  Core_SeqBaseTest::test_seq_ops( int iters )
    731 {
    732     const int max_op = 14;
    733     int max_elem_size = 0;
    734     schar* elem2 = 0;
    735     RNG& rng = ts->get_rng();
    736 
    737     for( int i = 0; i < struct_count; i++ )
    738         max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
    739 
    740     vector<schar> elem_buf(max_struct_size*max_elem_size);
    741     schar* elem = (schar*)&elem_buf[0];
    742     Mat elem_mat;
    743 
    744     for( iter = 0; iter < iters; iter++ )
    745     {
    746         struct_idx = cvtest::randInt(rng) % struct_count;
    747         int op = cvtest::randInt(rng) % max_op;
    748         CvSeq* seq = (CvSeq*)cxcore_struct[struct_idx];
    749         CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
    750         int elem_size = sseq->elem_size;
    751         int whence = 0, pos = 0, count = 0;
    752 
    753         switch( op )
    754         {
    755             case 0:
    756             case 1:
    757             case 2:  // push/pushfront/insert
    758                 if( sseq->count == sseq->max_count )
    759                     break;
    760 
    761                 elem_mat = Mat(1, elem_size, CV_8U, elem);
    762                 cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
    763 
    764                 whence = op - 1;
    765                 if( whence < 0 )
    766                 {
    767                     pos = 0;
    768                     cvSeqPushFront( seq, elem );
    769                 }
    770                 else if( whence > 0 )
    771                 {
    772                     pos = sseq->count;
    773                     cvSeqPush( seq, elem );
    774                 }
    775                 else
    776                 {
    777                     pos = cvtest::randInt(rng) % (sseq->count + 1);
    778                     cvSeqInsert( seq, pos, elem );
    779                 }
    780 
    781                 cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + 1, elem );
    782                 elem2 = cvGetSeqElem( seq, pos );
    783                 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "The inserted element could not be retrieved" );
    784                 CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
    785                                           memcmp(elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
    786                                           "The inserted sequence element is wrong" );
    787                 break;
    788 
    789             case 3:
    790             case 4:
    791             case 5: // pop/popfront/remove
    792                 if( sseq->count == 0 )
    793                     break;
    794 
    795                 whence = op - 4;
    796                 if( whence < 0 )
    797                 {
    798                     pos = 0;
    799                      cvSeqPopFront( seq, elem );
    800                 }
    801                 else if( whence > 0 )
    802                 {
    803                     pos = sseq->count-1;
    804                      cvSeqPop( seq, elem );
    805                 }
    806                 else
    807                 {
    808                     pos = cvtest::randInt(rng) % sseq->count;
    809                      cvSeqRemove( seq, pos );
    810                 }
    811 
    812                 if( whence != 0 )
    813                     CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - 1 &&
    814                                               memcmp( elem, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
    815                                               "The popped sequence element isn't correct" );
    816 
    817                 cvTsSimpleSeqShiftAndCopy( sseq, pos + 1, pos );
    818 
    819                 if( sseq->count > 0 )
    820                 {
    821                      elem2 = cvGetSeqElem( seq, pos < sseq->count ? pos : -1 );
    822                     CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "GetSeqElem fails after removing the element" );
    823 
    824                     CV_TS_SEQ_CHECK_CONDITION( memcmp( elem2,
    825                                                       cvTsSimpleSeqElem(sseq, pos - (pos == sseq->count)), elem_size) == 0,
    826                                               "The first shifted element is not correct after removing another element" );
    827                 }
    828                 else
    829                 {
    830                     CV_TS_SEQ_CHECK_CONDITION( seq->first == 0,
    831                                               "The sequence doesn't become empty after the final remove" );
    832                 }
    833                 break;
    834 
    835             case 6:
    836             case 7:
    837             case 8: // push [front] multi/insert slice
    838                 if( sseq->count == sseq->max_count )
    839                     break;
    840 
    841                 count = cvtest::randInt( rng ) % (sseq->max_count - sseq->count + 1);
    842                 elem_mat = Mat(1, MAX(count,1) * elem_size, CV_8U, elem);
    843                 cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
    844 
    845                 whence = op - 7;
    846                 pos = whence < 0 ? 0 : whence > 0 ? sseq->count : (int)(cvtest::randInt(rng) % (sseq->count+1));
    847                 if( whence != 0 )
    848                 {
    849                      cvSeqPushMulti( seq, elem, count, whence < 0 );
    850                 }
    851                 else
    852                 {
    853                     CvSeq header;
    854                     CvSeqBlock block;
    855                     cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(CvSeq),
    856                                                      sseq->elem_size,
    857                                                      elem, count,
    858                                                      &header, &block );
    859 
    860                     cvSeqInsertSlice( seq, pos, &header );
    861                 }
    862                 cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + count, elem );
    863 
    864                 if( sseq->count > 0 )
    865                 {
    866                     // choose the random element among the added
    867                     pos = count > 0 ? (int)(cvtest::randInt(rng) % count + pos) : MAX(pos-1,0);
    868                     elem2 = cvGetSeqElem( seq, pos );
    869                     CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "multi push operation doesn't add elements" );
    870                     CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
    871                                               memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
    872                                               "One of the added elements is wrong" );
    873                 }
    874                 else
    875                 {
    876                     CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
    877                                               "Adding no elements to empty sequence fails" );
    878                 }
    879                 break;
    880 
    881             case 9:
    882             case 10:
    883             case 11: // pop [front] multi
    884                 if( sseq->count == 0 )
    885                     break;
    886 
    887                 count = cvtest::randInt(rng) % (sseq->count+1);
    888                 whence = op - 10;
    889                 pos = whence < 0 ? 0 : whence > 0 ? sseq->count - count :
    890                     (int)(cvtest::randInt(rng) % (sseq->count - count + 1));
    891 
    892                 if( whence != 0 )
    893                 {
    894                      cvSeqPopMulti( seq, elem, count, whence < 0 );
    895 
    896                     if( count > 0 )
    897                     {
    898                         CV_TS_SEQ_CHECK_CONDITION( memcmp(elem,
    899                                                           cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
    900                                                   "The first (in the sequence order) removed element is wrong after popmulti" );
    901                     }
    902                 }
    903                 else
    904                 {
    905                      cvSeqRemoveSlice( seq, cvSlice(pos, pos + count) );
    906                 }
    907 
    908                 CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - count,
    909                                           "The popmulti left a wrong number of elements in the sequence" );
    910 
    911                 cvTsSimpleSeqShiftAndCopy( sseq, pos + count, pos, 0 );
    912                 if( sseq->count > 0 )
    913                 {
    914                     pos = whence < 0 ? 0 : MIN( pos, sseq->count - 1 );
    915                     elem2 = cvGetSeqElem( seq, pos );
    916                     CV_TS_SEQ_CHECK_CONDITION( elem2 &&
    917                                               memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
    918                                               "The last sequence element is wrong after POP" );
    919                 }
    920                 else
    921                 {
    922                     CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
    923                                               "The sequence doesn't become empty after final POP" );
    924                 }
    925                 break;
    926             case 12: // seqslice
    927             {
    928                 CvMemStoragePos storage_pos;
    929                 cvSaveMemStoragePos( storage, &storage_pos );
    930 
    931                 int copy_data = cvtest::randInt(rng) % 2;
    932                 count = cvtest::randInt(rng) % (seq->total + 1);
    933                 pos = cvtest::randInt(rng) % (seq->total - count + 1);
    934                 CvSeq* seq_slice = cvSeqSlice( seq, cvSlice(pos, pos + count), storage, copy_data );
    935 
    936                 CV_TS_SEQ_CHECK_CONDITION( seq_slice && seq_slice->total == count,
    937                                           "cvSeqSlice returned incorrect slice" );
    938 
    939                 if( count > 0 )
    940                 {
    941                     int test_idx = cvtest::randInt(rng) % count;
    942                     elem2 = cvGetSeqElem( seq_slice, test_idx );
    943                     schar* elem3 = cvGetSeqElem( seq, pos + test_idx );
    944                     CV_TS_SEQ_CHECK_CONDITION( elem2 &&
    945                                               memcmp( elem2, cvTsSimpleSeqElem(sseq,pos + test_idx), elem_size) == 0,
    946                                               "The extracted slice elements are not correct" );
    947                     CV_TS_SEQ_CHECK_CONDITION( (elem2 == elem3) ^ copy_data,
    948                                               "copy_data flag is handled incorrectly" );
    949                 }
    950 
    951                 cvRestoreMemStoragePos( storage, &storage_pos );
    952             }
    953                 break;
    954             case 13: // clear
    955                 cvTsClearSimpleSeq( sseq );
    956                 cvClearSeq( seq );
    957                 CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
    958                                           "The sequence doesn't become empty after clear" );
    959                 break;
    960             default:
    961                 assert(0);
    962                 return -1;
    963         }
    964 
    965         if( test_seq_block_consistence(struct_idx, seq, sseq->count) < 0 )
    966             return -1;
    967 
    968         if( test_get_seq_elem(struct_idx, 7) < 0 )
    969             return -1;
    970 
    971         update_progressbar();
    972     }
    973 
    974     return 0;
    975 }
    976 
    977 
    978 void Core_SeqBaseTest::run( int )
    979 {
    980     try
    981     {
    982         RNG& rng = ts->get_rng();
    983         int i;
    984         double t;
    985 
    986         clear();
    987         test_progress = -1;
    988 
    989         simple_struct.resize(struct_count, 0);
    990         cxcore_struct.resize(struct_count, 0);
    991 
    992         for( gen = 0; gen < generations; gen++ )
    993         {
    994             struct_idx = iter = -1;
    995 
    996             if( !storage )
    997             {
    998                 t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
    999                 + min_log_storage_block_size;
   1000                 storage.reset(cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ));
   1001             }
   1002 
   1003             iter = struct_idx = -1;
   1004             test_multi_create();
   1005 
   1006             for( i = 0; i < struct_count; i++ )
   1007             {
   1008                 if( test_seq_block_consistence(i, (CvSeq*)cxcore_struct[i],
   1009                                                ((CvTsSimpleSeq*)simple_struct[i])->count) < 0 )
   1010                     return;
   1011 
   1012                 if( test_get_seq_elem( i, MAX(iterations/3,7) ) < 0 )
   1013                     return;
   1014 
   1015                 if( test_get_seq_reading( i, MAX(iterations/3,7) ) < 0 )
   1016                     return;
   1017                 update_progressbar();
   1018             }
   1019 
   1020             if( test_seq_ops( iterations ) < 0 )
   1021                 return;
   1022 
   1023             if( cvtest::randInt(rng) % 2 )
   1024                 storage.release();
   1025             else
   1026                 cvClearMemStorage( storage );
   1027         }
   1028     }
   1029     catch(int)
   1030     {
   1031     }
   1032 }
   1033 
   1034 
   1035 ////////////////////////////// more sequence tests //////////////////////////////////////
   1036 
   1037 class Core_SeqSortInvTest : public Core_SeqBaseTest
   1038 {
   1039 public:
   1040     Core_SeqSortInvTest();
   1041     void run( int );
   1042 
   1043 protected:
   1044 };
   1045 
   1046 
   1047 Core_SeqSortInvTest::Core_SeqSortInvTest()
   1048 {
   1049 }
   1050 
   1051 
   1052 static int icvCmpSeqElems( const void* a, const void* b, void* userdata )
   1053 {
   1054     return memcmp( a, b, ((CvSeq*)userdata)->elem_size );
   1055 }
   1056 
   1057 static int icvCmpSeqElems2_elem_size = 0;
   1058 static int icvCmpSeqElems2( const void* a, const void* b )
   1059 {
   1060     return memcmp( a, b, icvCmpSeqElems2_elem_size );
   1061 }
   1062 
   1063 
   1064 void Core_SeqSortInvTest::run( int )
   1065 {
   1066     try
   1067     {
   1068         RNG& rng = ts->get_rng();
   1069         int i, k;
   1070         double t;
   1071         schar *elem0, *elem, *elem2;
   1072         vector<uchar> buffer;
   1073 
   1074         clear();
   1075         test_progress = -1;
   1076 
   1077         simple_struct.resize(struct_count, 0);
   1078         cxcore_struct.resize(struct_count, 0);
   1079 
   1080         for( gen = 0; gen < generations; gen++ )
   1081         {
   1082             struct_idx = iter = -1;
   1083 
   1084             if( !storage )
   1085             {
   1086                 t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
   1087                 + min_log_storage_block_size;
   1088                 storage.reset(cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ));
   1089             }
   1090 
   1091             for( iter = 0; iter < iterations/10; iter++ )
   1092             {
   1093                 int max_size = 0;
   1094                 test_multi_create();
   1095 
   1096                 for( i = 0; i < struct_count; i++ )
   1097                 {
   1098                     CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
   1099                     max_size = MAX( max_size, sseq->count*sseq->elem_size );
   1100                 }
   1101 
   1102                 buffer.resize(max_size);
   1103 
   1104                 for( i = 0; i < struct_count; i++ )
   1105                 {
   1106                     CvSeq* seq = (CvSeq*)cxcore_struct[i];
   1107                     CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
   1108                     CvSlice slice = CV_WHOLE_SEQ;
   1109 
   1110                     //printf("%d. %d. %d-th size = %d\n", gen, iter, i, sseq->count );
   1111 
   1112                     cvSeqInvert( seq );
   1113                     cvTsSimpleSeqInvert( sseq );
   1114 
   1115                     if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
   1116                         return;
   1117 
   1118                     if( sseq->count > 0 && cvtest::randInt(rng) % 2 == 0 )
   1119                     {
   1120                         slice.end_index = cvtest::randInt(rng) % sseq->count + 1;
   1121                         slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1);
   1122                         slice.end_index += slice.start_index;
   1123                     }
   1124 
   1125                     cvCvtSeqToArray( seq, &buffer[0], slice );
   1126 
   1127                     slice.end_index = MIN( slice.end_index, sseq->count );
   1128                     CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0],
   1129                                                                           sseq->array + slice.start_index*sseq->elem_size,
   1130                                                                           (slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
   1131                                               "cvSeqInvert returned wrong result" );
   1132 
   1133                     for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
   1134                     {
   1135                         int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0;
   1136                         elem0 = cvTsSimpleSeqElem( sseq, idx0 );
   1137                         elem = cvGetSeqElem( seq, idx0 );
   1138                         elem2 = cvSeqSearch( seq, elem0, k % 2 ? icvCmpSeqElems : 0, 0, &idx, seq );
   1139 
   1140                         CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
   1141                                                   memcmp( elem0, elem, seq->elem_size ) == 0,
   1142                                                   "cvSeqInvert gives incorrect result" );
   1143                         CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
   1144                                                   memcmp( elem0, elem2, seq->elem_size ) == 0 &&
   1145                                                   elem2 == cvGetSeqElem( seq, idx ),
   1146                                                   "cvSeqSearch failed (linear search)" );
   1147                     }
   1148 
   1149                     cvSeqSort( seq, icvCmpSeqElems, seq );
   1150 
   1151                     if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
   1152                         return;
   1153 
   1154                     if( sseq->count > 0 )
   1155                     {
   1156                         // !!! This is not thread-safe !!!
   1157                         icvCmpSeqElems2_elem_size = sseq->elem_size;
   1158                         qsort( sseq->array, sseq->count, sseq->elem_size, icvCmpSeqElems2 );
   1159 
   1160                         if( cvtest::randInt(rng) % 2 == 0 )
   1161                         {
   1162                             slice.end_index = cvtest::randInt(rng) % sseq->count + 1;
   1163                             slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1);
   1164                             slice.end_index += slice.start_index;
   1165                         }
   1166                     }
   1167 
   1168                     cvCvtSeqToArray( seq, &buffer[0], slice );
   1169                     CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0],
   1170                                                                           sseq->array + slice.start_index*sseq->elem_size,
   1171                                                                           (slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
   1172                                               "cvSeqSort returned wrong result" );
   1173 
   1174                     for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
   1175                     {
   1176                         int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0;
   1177                         elem0 = cvTsSimpleSeqElem( sseq, idx0 );
   1178                         elem = cvGetSeqElem( seq, idx0 );
   1179                         elem2 = cvSeqSearch( seq, elem0, icvCmpSeqElems, 1, &idx, seq );
   1180 
   1181                         CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
   1182                                                   memcmp( elem0, elem, seq->elem_size ) == 0,
   1183                                                   "cvSeqSort gives incorrect result" );
   1184                         CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
   1185                                                   memcmp( elem0, elem2, seq->elem_size ) == 0 &&
   1186                                                   elem2 == cvGetSeqElem( seq, idx ),
   1187                                                   "cvSeqSearch failed (binary search)" );
   1188                     }
   1189                 }
   1190 
   1191                 cvClearMemStorage( storage );
   1192             }
   1193 
   1194             storage.release();
   1195         }
   1196     }
   1197     catch (int)
   1198     {
   1199     }
   1200 }
   1201 
   1202 
   1203 /////////////////////////////////////// set tests ///////////////////////////////////////
   1204 
   1205 class Core_SetTest : public Core_DynStructBaseTest
   1206 {
   1207 public:
   1208     Core_SetTest();
   1209     void clear();
   1210     void run( int );
   1211 
   1212 protected:
   1213     //int test_seq_block_consistence( int struct_idx );
   1214     int test_set_ops( int iters );
   1215 };
   1216 
   1217 
   1218 Core_SetTest::Core_SetTest()
   1219 {
   1220 }
   1221 
   1222 
   1223 void Core_SetTest::clear()
   1224 {
   1225     for( size_t i = 0; i < simple_struct.size(); i++ )
   1226         cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
   1227     Core_DynStructBaseTest::clear();
   1228 }
   1229 
   1230 
   1231 int  Core_SetTest::test_set_ops( int iters )
   1232 {
   1233     const int max_op = 4;
   1234     int max_elem_size = 0;
   1235     int idx, idx0;
   1236     CvSetElem *elem = 0, *elem2 = 0, *elem3 = 0;
   1237     schar* elem_data = 0;
   1238     RNG& rng = ts->get_rng();
   1239     //int max_active_count = 0, mean_active_count = 0;
   1240 
   1241     for( int i = 0; i < struct_count; i++ )
   1242         max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
   1243 
   1244     vector<schar> elem_buf(max_elem_size);
   1245     Mat elem_mat;
   1246 
   1247     for( iter = 0; iter < iters; iter++ )
   1248     {
   1249         struct_idx = cvtest::randInt(rng) % struct_count;
   1250 
   1251         CvSet* cvset = (CvSet*)cxcore_struct[struct_idx];
   1252         CvTsSimpleSet* sset = (CvTsSimpleSet*)simple_struct[struct_idx];
   1253         int pure_elem_size = sset->elem_size - 1;
   1254         int prev_total = cvset->total, prev_count = cvset->active_count;
   1255         int op = cvtest::randInt(rng) % (iter <= iters/10 ? 2 : max_op);
   1256         int by_ptr = op % 2 == 0;
   1257         CvSetElem* first_free = cvset->free_elems;
   1258         CvSetElem* next_free = first_free ? first_free->next_free : 0;
   1259         int pass_data = 0;
   1260 
   1261         if( iter > iters/10 && cvtest::randInt(rng)%200 == 0 ) // clear set
   1262         {
   1263             prev_count = cvset->total;
   1264             cvClearSet( cvset );
   1265             cvTsClearSimpleSet( sset );
   1266 
   1267             CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == 0 && cvset->total == 0 &&
   1268                                       cvset->first == 0 && cvset->free_elems == 0 &&
   1269                                       (cvset->free_blocks != 0 || prev_count == 0),
   1270                                       "cvClearSet doesn't remove all the elements" );
   1271             continue;
   1272         }
   1273         else if( op == 0 || op == 1 ) // add element
   1274         {
   1275             if( sset->free_count == 0 )
   1276                 continue;
   1277 
   1278             elem_mat = Mat(1, cvset->elem_size, CV_8U, &elem_buf[0]);
   1279             cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
   1280             elem = (CvSetElem*)&elem_buf[0];
   1281 
   1282             if( by_ptr )
   1283             {
   1284                 elem2 = cvSetNew( cvset );
   1285                 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "cvSetNew returned NULL pointer" );
   1286             }
   1287             else
   1288             {
   1289                 pass_data = cvtest::randInt(rng) % 2;
   1290                 idx = cvSetAdd( cvset, pass_data ? elem : 0, &elem2 );
   1291                 CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && elem2->flags == idx,
   1292                                           "cvSetAdd returned NULL pointer or a wrong index" );
   1293             }
   1294 
   1295             elem_data = (schar*)elem + sizeof(int);
   1296 
   1297             if( !pass_data )
   1298                 memcpy( (schar*)elem2 + sizeof(int), elem_data, pure_elem_size );
   1299 
   1300             idx = elem2->flags;
   1301             idx0 = cvTsSimpleSetAdd( sset, elem_data );
   1302             elem3 = cvGetSetElem( cvset, idx );
   1303 
   1304             CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem3) &&
   1305                                       idx == idx0 && elem3 == elem2 && (!pass_data ||
   1306                                                                         memcmp( (char*)elem3 + sizeof(int), elem_data, pure_elem_size) == 0),
   1307                                       "The added element is not correct" );
   1308 
   1309             CV_TS_SEQ_CHECK_CONDITION( (!first_free || elem3 == first_free) &&
   1310                                       (!next_free || cvset->free_elems == next_free) &&
   1311                                       cvset->active_count == prev_count + 1,
   1312                                       "The free node list is modified incorrectly" );
   1313         }
   1314         else if( op == 2 || op == 3 ) // remove element
   1315         {
   1316             idx = cvtest::randInt(rng) % sset->max_count;
   1317 
   1318             if( sset->free_count == sset->max_count || idx >= sset->count )
   1319                 continue;
   1320 
   1321             elem_data = cvTsSimpleSetFind(sset, idx);
   1322             if( elem_data == 0 )
   1323                 continue;
   1324 
   1325             elem = cvGetSetElem( cvset, idx );
   1326             CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem) && elem->flags == idx &&
   1327                                       memcmp((char*)elem + sizeof(int), elem_data, pure_elem_size) == 0,
   1328                                       "cvGetSetElem returned wrong element" );
   1329 
   1330             if( by_ptr )
   1331             {
   1332                  cvSetRemoveByPtr( cvset, elem );
   1333             }
   1334             else
   1335             {
   1336                  cvSetRemove( cvset, idx );
   1337             }
   1338 
   1339             cvTsSimpleSetRemove( sset, idx );
   1340 
   1341             CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(elem) && !cvGetSetElem(cvset, idx) &&
   1342                                       (elem->flags & CV_SET_ELEM_IDX_MASK) == idx,
   1343                                       "cvSetRemove[ByPtr] didn't release the element properly" );
   1344 
   1345             CV_TS_SEQ_CHECK_CONDITION( elem->next_free == first_free &&
   1346                                       cvset->free_elems == elem &&
   1347                                       cvset->active_count == prev_count - 1,
   1348                                       "The free node list has not been updated properly" );
   1349         }
   1350 
   1351         //max_active_count = MAX( max_active_count, cvset->active_count );
   1352         //mean_active_count += cvset->active_count;
   1353         CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == sset->max_count - sset->free_count &&
   1354                                   cvset->total >= cvset->active_count &&
   1355                                   (cvset->total == 0 || cvset->total >= prev_total),
   1356                                   "The total number of cvset elements is not correct" );
   1357 
   1358         // CvSet and simple set do not necessary have the same "total" (active & free) number,
   1359         // so pass "set->total" to skip that check
   1360         test_seq_block_consistence( struct_idx, (CvSeq*)cvset, cvset->total );
   1361         update_progressbar();
   1362     }
   1363 
   1364     return 0;
   1365 }
   1366 
   1367 
   1368 void Core_SetTest::run( int )
   1369 {
   1370     try
   1371     {
   1372         RNG& rng = ts->get_rng();
   1373         double t;
   1374 
   1375         clear();
   1376         test_progress = -1;
   1377 
   1378         simple_struct.resize(struct_count, 0);
   1379         cxcore_struct.resize(struct_count, 0);
   1380 
   1381         for( gen = 0; gen < generations; gen++ )
   1382         {
   1383             struct_idx = iter = -1;
   1384             t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
   1385             storage.reset(cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) ));
   1386 
   1387             for( int i = 0; i < struct_count; i++ )
   1388             {
   1389                 t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
   1390                 int pure_elem_size = cvRound( exp(t * CV_LOG2) );
   1391                 int elem_size = pure_elem_size + sizeof(int);
   1392                 elem_size = (elem_size + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
   1393                 elem_size = MAX( elem_size, (int)sizeof(CvSetElem) );
   1394                 elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) - sizeof(CvMemBlock) - sizeof(CvSeqBlock)) );
   1395                 pure_elem_size = MIN( pure_elem_size, elem_size-(int)sizeof(CvSetElem) );
   1396 
   1397                 cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
   1398                 simple_struct[i] = cvTsCreateSimpleSet( max_struct_size, pure_elem_size );
   1399                 cxcore_struct[i] = cvCreateSet( 0, sizeof(CvSet), elem_size, storage );
   1400             }
   1401 
   1402             if( test_set_ops( iterations*100 ) < 0 )
   1403                 return;
   1404 
   1405             storage.release();
   1406         }
   1407     }
   1408     catch(int)
   1409     {
   1410     }
   1411 }
   1412 
   1413 
   1414 /////////////////////////////////////// graph tests //////////////////////////////////
   1415 
   1416 class Core_GraphTest : public Core_DynStructBaseTest
   1417 {
   1418 public:
   1419     Core_GraphTest();
   1420     void clear();
   1421     void run( int );
   1422 
   1423 protected:
   1424     //int test_seq_block_consistence( int struct_idx );
   1425     int test_graph_ops( int iters );
   1426 };
   1427 
   1428 
   1429 Core_GraphTest::Core_GraphTest()
   1430 {
   1431 }
   1432 
   1433 
   1434 void Core_GraphTest::clear()
   1435 {
   1436     for( size_t i = 0; i < simple_struct.size(); i++ )
   1437         cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
   1438     Core_DynStructBaseTest::clear();
   1439 }
   1440 
   1441 
   1442 int  Core_GraphTest::test_graph_ops( int iters )
   1443 {
   1444     const int max_op = 4;
   1445     int i, k;
   1446     int max_elem_size = 0;
   1447     int idx, idx0;
   1448     CvGraphVtx *vtx = 0, *vtx2 = 0, *vtx3 = 0;
   1449     CvGraphEdge* edge = 0, *edge2 = 0;
   1450     RNG& rng = ts->get_rng();
   1451     //int max_active_count = 0, mean_active_count = 0;
   1452 
   1453     for( i = 0; i < struct_count; i++ )
   1454     {
   1455         CvGraph* graph = (CvGraph*)cxcore_struct[i];
   1456         max_elem_size = MAX( max_elem_size, graph->elem_size );
   1457         max_elem_size = MAX( max_elem_size, graph->edges->elem_size );
   1458     }
   1459 
   1460     vector<schar> elem_buf(max_elem_size);
   1461     Mat elem_mat;
   1462 
   1463     for( iter = 0; iter < iters; iter++ )
   1464     {
   1465         struct_idx = cvtest::randInt(rng) % struct_count;
   1466         CvGraph* graph = (CvGraph*)cxcore_struct[struct_idx];
   1467         CvTsSimpleGraph* sgraph = (CvTsSimpleGraph*)simple_struct[struct_idx];
   1468         CvSet* edges = graph->edges;
   1469         schar *vtx_data;
   1470         char *edge_data;
   1471         int pure_vtx_size = sgraph->vtx->elem_size - 1,
   1472         pure_edge_size = sgraph->edge_size - 1;
   1473         int prev_vtx_total = graph->total,
   1474         prev_edge_total = graph->edges->total,
   1475         prev_vtx_count = graph->active_count,
   1476         prev_edge_count = graph->edges->active_count;
   1477         int op = cvtest::randInt(rng) % max_op;
   1478         int pass_data = 0, vtx_degree0 = 0, vtx_degree = 0;
   1479         CvSetElem *first_free, *next_free;
   1480 
   1481         if( cvtest::randInt(rng) % 200 == 0 ) // clear graph
   1482         {
   1483             int prev_vtx_count2 = graph->total, prev_edge_count2 = graph->edges->total;
   1484 
   1485             cvClearGraph( graph );
   1486             cvTsClearSimpleGraph( sgraph );
   1487 
   1488             CV_TS_SEQ_CHECK_CONDITION( graph->active_count == 0 && graph->total == 0 &&
   1489                                       graph->first == 0 && graph->free_elems == 0 &&
   1490                                       (graph->free_blocks != 0 || prev_vtx_count2 == 0),
   1491                                       "The graph is not empty after clearing" );
   1492 
   1493             CV_TS_SEQ_CHECK_CONDITION( edges->active_count == 0 && edges->total == 0 &&
   1494                                       edges->first == 0 && edges->free_elems == 0 &&
   1495                                       (edges->free_blocks != 0 || prev_edge_count2 == 0),
   1496                                       "The graph is not empty after clearing" );
   1497         }
   1498         else if( op == 0 ) // add vertex
   1499         {
   1500             if( sgraph->vtx->free_count == 0 )
   1501                 continue;
   1502 
   1503             first_free = graph->free_elems;
   1504             next_free = first_free ? first_free->next_free : 0;
   1505 
   1506             if( pure_vtx_size )
   1507             {
   1508                 elem_mat = Mat(1, graph->elem_size, CV_8U, &elem_buf[0]);
   1509                 cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
   1510             }
   1511 
   1512             vtx = (CvGraphVtx*)&elem_buf[0];
   1513             idx0 = cvTsSimpleGraphAddVertex( sgraph, vtx + 1 );
   1514 
   1515             pass_data = cvtest::randInt(rng) % 2;
   1516             idx = cvGraphAddVtx( graph, pass_data ? vtx : 0, &vtx2 );
   1517 
   1518             if( !pass_data && pure_vtx_size > 0 )
   1519                 memcpy( vtx2 + 1, vtx + 1, pure_vtx_size );
   1520 
   1521             vtx3 = cvGetGraphVtx( graph, idx );
   1522 
   1523             CV_TS_SEQ_CHECK_CONDITION( (CV_IS_SET_ELEM(vtx3) && vtx3->flags == idx &&
   1524                                         vtx3->first == 0) || (idx == idx0 && vtx3 == vtx2 &&
   1525                                                               (!pass_data || pure_vtx_size == 0 ||
   1526                                                                memcmp(vtx3 + 1, vtx + 1, pure_vtx_size) == 0)),
   1527                                       "The added element is not correct" );
   1528 
   1529             CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)vtx3) &&
   1530                                       (!next_free || graph->free_elems == next_free) &&
   1531                                       graph->active_count == prev_vtx_count + 1,
   1532                                       "The free node list is modified incorrectly" );
   1533         }
   1534         else if( op == 1 ) // remove vertex
   1535         {
   1536             idx = cvtest::randInt(rng) % sgraph->vtx->max_count;
   1537             if( sgraph->vtx->free_count == sgraph->vtx->max_count || idx >= sgraph->vtx->count )
   1538                 continue;
   1539 
   1540             vtx_data = cvTsSimpleGraphFindVertex(sgraph, idx);
   1541             if( vtx_data == 0 )
   1542                 continue;
   1543 
   1544             vtx_degree0 = cvTsSimpleGraphVertexDegree( sgraph, idx );
   1545             first_free = graph->free_elems;
   1546 
   1547             vtx = cvGetGraphVtx( graph, idx );
   1548             CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(vtx) && vtx->flags == idx &&
   1549                                       (pure_vtx_size == 0 || memcmp( vtx + 1, vtx_data, pure_vtx_size) == 0),
   1550                                       "cvGetGraphVtx returned wrong element" );
   1551 
   1552             if( cvtest::randInt(rng) % 2 )
   1553             {
   1554                  vtx_degree = cvGraphVtxDegreeByPtr( graph, vtx );
   1555                  cvGraphRemoveVtxByPtr( graph, vtx );
   1556             }
   1557             else
   1558             {
   1559                  vtx_degree = cvGraphVtxDegree( graph, idx );
   1560                  cvGraphRemoveVtx( graph, idx );
   1561             }
   1562 
   1563             cvTsSimpleGraphRemoveVertex( sgraph, idx );
   1564 
   1565             CV_TS_SEQ_CHECK_CONDITION( vtx_degree == vtx_degree0,
   1566                                       "Number of incident edges is different in two graph representations" );
   1567 
   1568             CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(vtx) && !cvGetGraphVtx(graph, idx) &&
   1569                                       (vtx->flags & CV_SET_ELEM_IDX_MASK) == idx,
   1570                                       "cvGraphRemoveVtx[ByPtr] didn't release the vertex properly" );
   1571 
   1572             CV_TS_SEQ_CHECK_CONDITION( graph->edges->active_count == prev_edge_count - vtx_degree,
   1573                                       "cvGraphRemoveVtx[ByPtr] didn't remove all the incident edges "
   1574                                       "(or removed some extra)" );
   1575 
   1576             CV_TS_SEQ_CHECK_CONDITION( ((CvSetElem*)vtx)->next_free == first_free &&
   1577                                       graph->free_elems == (CvSetElem*)vtx &&
   1578                                       graph->active_count == prev_vtx_count - 1,
   1579                                       "The free node list has not been updated properly" );
   1580         }
   1581         else if( op == 2 ) // add edge
   1582         {
   1583             int v_idx[2] = {0,0}, res = 0;
   1584             int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
   1585 
   1586             if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
   1587                 continue;
   1588 
   1589             for( i = 0, k = 0; i < 10; i++ )
   1590             {
   1591                 int j = cvtest::randInt(rng) % sgraph->vtx->count;
   1592                 vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
   1593                 if( vtx_data )
   1594                 {
   1595                     v_idx[k] = j;
   1596                     if( k == 0 )
   1597                         k++;
   1598                     else if( v_idx[0] != v_idx[1] &&
   1599                             cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] ) == 0 )
   1600                     {
   1601                         k++;
   1602                         break;
   1603                     }
   1604                 }
   1605             }
   1606 
   1607             if( k < 2 )
   1608                 continue;
   1609 
   1610             first_free = graph->edges->free_elems;
   1611             next_free = first_free ? first_free->next_free : 0;
   1612 
   1613             edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
   1614             CV_TS_SEQ_CHECK_CONDITION( edge == 0, "Extra edge appeared in the graph" );
   1615 
   1616             if( pure_edge_size > 0 )
   1617             {
   1618                 elem_mat = Mat(1, graph->edges->elem_size, CV_8U, &elem_buf[0]);
   1619                 cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
   1620             }
   1621             edge = (CvGraphEdge*)&elem_buf[0];
   1622 
   1623             // assign some default weight that is easy to check for
   1624             // consistensy, 'cause an edge weight is not stored
   1625             // in the simple graph
   1626             edge->weight = (float)(v_idx[0] + v_idx[1]);
   1627             pass_data = cvtest::randInt(rng) % 2;
   1628 
   1629             vtx = cvGetGraphVtx( graph, v_idx[0] );
   1630             vtx2 = cvGetGraphVtx( graph, v_idx[1] );
   1631             CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
   1632                                       vtx2->flags == v_idx[1], "Some of the vertices are missing" );
   1633 
   1634             if( cvtest::randInt(rng) % 2 )
   1635             {
   1636                  v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
   1637                  v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
   1638                  res = cvGraphAddEdgeByPtr(graph, vtx, vtx2, pass_data ? edge : 0, &edge2);
   1639                  v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
   1640                  v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
   1641             }
   1642             else
   1643             {
   1644                  v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
   1645                  v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
   1646                  res = cvGraphAddEdge(graph, v_idx[0], v_idx[1], pass_data ? edge : 0, &edge2);
   1647                  v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
   1648                  v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
   1649             }
   1650 
   1651             //edge3 = (CvGraphEdge*)cvGetSetElem( graph->edges, idx );
   1652             CV_TS_SEQ_CHECK_CONDITION( res == 1 && edge2 != 0 && CV_IS_SET_ELEM(edge2) &&
   1653                                       ((edge2->vtx[0] == vtx && edge2->vtx[1] == vtx2) ||
   1654                                        (!CV_IS_GRAPH_ORIENTED(graph) && edge2->vtx[0] == vtx2 && edge2->vtx[1] == vtx)) &&
   1655                                       (!pass_data || pure_edge_size == 0 || memcmp( edge2 + 1, edge + 1, pure_edge_size ) == 0),
   1656                                       "The edge has been added incorrectly" );
   1657 
   1658             if( !pass_data )
   1659             {
   1660                 if( pure_edge_size > 0 )
   1661                     memcpy( edge2 + 1, edge + 1, pure_edge_size );
   1662                 edge2->weight = edge->weight;
   1663             }
   1664 
   1665             CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] + 1 &&
   1666                                       v_degree[1] == v_prev_degree[1] + 1,
   1667                                       "The vertices lists have not been updated properly" );
   1668 
   1669             cvTsSimpleGraphAddEdge( sgraph, v_idx[0], v_idx[1], edge + 1 );
   1670 
   1671             CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)edge2) &&
   1672                                       (!next_free || graph->edges->free_elems == next_free) &&
   1673                                       graph->edges->active_count == prev_edge_count + 1,
   1674                                       "The free node list is modified incorrectly" );
   1675         }
   1676         else if( op == 3 ) // find & remove edge
   1677         {
   1678             int v_idx[2] = {0,0}, by_ptr;
   1679             int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
   1680 
   1681             if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
   1682                 continue;
   1683 
   1684             edge_data = 0;
   1685             for( i = 0, k = 0; i < 10; i++ )
   1686             {
   1687                 int j = cvtest::randInt(rng) % sgraph->vtx->count;
   1688                 vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
   1689                 if( vtx_data )
   1690                 {
   1691                     v_idx[k] = j;
   1692                     if( k == 0 )
   1693                         k++;
   1694                     else
   1695                     {
   1696                         edge_data = cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] );
   1697                         if( edge_data )
   1698                         {
   1699                             k++;
   1700                             break;
   1701                         }
   1702                     }
   1703                 }
   1704             }
   1705 
   1706             if( k < 2 )
   1707                 continue;
   1708 
   1709             by_ptr = cvtest::randInt(rng) % 2;
   1710             first_free = graph->edges->free_elems;
   1711 
   1712             vtx = cvGetGraphVtx( graph, v_idx[0] );
   1713             vtx2 = cvGetGraphVtx( graph, v_idx[1] );
   1714             CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
   1715                                       vtx2->flags == v_idx[1], "Some of the vertices are missing" );
   1716 
   1717             if( by_ptr )
   1718             {
   1719                  edge = cvFindGraphEdgeByPtr( graph, vtx, vtx2 );
   1720                  v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
   1721                  v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
   1722             }
   1723             else
   1724             {
   1725                  edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
   1726                  v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
   1727                  v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
   1728             }
   1729 
   1730             idx = edge->flags;
   1731 
   1732             CV_TS_SEQ_CHECK_CONDITION( edge != 0 && edge->weight == v_idx[0] + v_idx[1] &&
   1733                                       ((edge->vtx[0] == vtx && edge->vtx[1] == vtx2) ||
   1734                                        (!CV_IS_GRAPH_ORIENTED(graph) && edge->vtx[1] == vtx && edge->vtx[0] == vtx2)) &&
   1735                                       (pure_edge_size == 0 || memcmp(edge + 1, edge_data, pure_edge_size) == 0),
   1736                                       "An edge is missing or incorrect" );
   1737 
   1738             if( by_ptr )
   1739             {
   1740                  cvGraphRemoveEdgeByPtr( graph, vtx, vtx2 );
   1741                  edge2 = cvFindGraphEdgeByPtr( graph, vtx, vtx2 );
   1742                  v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
   1743                  v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
   1744             }
   1745             else
   1746             {
   1747                  cvGraphRemoveEdge(graph, v_idx[0], v_idx[1] );
   1748                  edge2 = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
   1749                  v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
   1750                  v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
   1751             }
   1752 
   1753             CV_TS_SEQ_CHECK_CONDITION( !edge2 && !CV_IS_SET_ELEM(edge),
   1754                                       "The edge has not been removed from the edge set" );
   1755 
   1756             CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] - 1 &&
   1757                                       v_degree[1] == v_prev_degree[1] - 1,
   1758                                       "The vertices lists have not been updated properly" );
   1759 
   1760             cvTsSimpleGraphRemoveEdge( sgraph, v_idx[0], v_idx[1] );
   1761 
   1762             CV_TS_SEQ_CHECK_CONDITION( graph->edges->free_elems == (CvSetElem*)edge &&
   1763                                       graph->edges->free_elems->next_free == first_free &&
   1764                                       graph->edges->active_count == prev_edge_count - 1,
   1765                                       "The free edge list has not been modified properly" );
   1766         }
   1767 
   1768         //max_active_count = MAX( max_active_count, graph->active_count );
   1769         //mean_active_count += graph->active_count;
   1770 
   1771         CV_TS_SEQ_CHECK_CONDITION( graph->active_count == sgraph->vtx->max_count - sgraph->vtx->free_count &&
   1772                                   graph->total >= graph->active_count &&
   1773                                   (graph->total == 0 || graph->total >= prev_vtx_total),
   1774                                   "The total number of graph vertices is not correct" );
   1775 
   1776         CV_TS_SEQ_CHECK_CONDITION( graph->edges->total >= graph->edges->active_count &&
   1777                                   (graph->edges->total == 0 || graph->edges->total >= prev_edge_total),
   1778                                   "The total number of graph vertices is not correct" );
   1779 
   1780         // CvGraph and simple graph do not necessary have the same "total" (active & free) number,
   1781         // so pass "graph->total" (or "graph->edges->total") to skip that check
   1782         test_seq_block_consistence( struct_idx, (CvSeq*)graph, graph->total );
   1783         test_seq_block_consistence( struct_idx, (CvSeq*)graph->edges, graph->edges->total );
   1784         update_progressbar();
   1785     }
   1786 
   1787     return 0;
   1788 }
   1789 
   1790 
   1791 void Core_GraphTest::run( int )
   1792 {
   1793     try
   1794     {
   1795         RNG& rng = ts->get_rng();
   1796         int i, k;
   1797         double t;
   1798 
   1799         clear();
   1800         test_progress = -1;
   1801 
   1802         simple_struct.resize(struct_count, 0);
   1803         cxcore_struct.resize(struct_count, 0);
   1804 
   1805         for( gen = 0; gen < generations; gen++ )
   1806         {
   1807             struct_idx = iter = -1;
   1808             t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
   1809             int block_size = cvRound( exp(t * CV_LOG2) );
   1810             block_size = MAX(block_size, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
   1811 
   1812             storage.reset(cvCreateMemStorage(block_size));
   1813 
   1814             for( i = 0; i < struct_count; i++ )
   1815             {
   1816                 int pure_elem_size[2], elem_size[2];
   1817                 int is_oriented = (gen + i) % 2;
   1818                 for( k = 0; k < 2; k++ )
   1819                 {
   1820                     t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
   1821                     int pe = cvRound( exp(t * CV_LOG2) ) - 1; // pure_elem_size==0 does also make sense
   1822                     int delta = k == 0 ? sizeof(CvGraphVtx) : sizeof(CvGraphEdge);
   1823                     int e = pe + delta;
   1824                     e = (e + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
   1825                     e = MIN( e, (int)(storage->block_size - sizeof(CvMemBlock) -
   1826                                       sizeof(CvSeqBlock) - sizeof(void*)) );
   1827                     pe = MIN(pe, e - delta);
   1828                     pure_elem_size[k] = pe;
   1829                     elem_size[k] = e;
   1830                 }
   1831 
   1832                 cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
   1833                 simple_struct[i] = cvTsCreateSimpleGraph( max_struct_size/4, pure_elem_size[0],
   1834                                                          pure_elem_size[1], is_oriented );
   1835                 cxcore_struct[i] = cvCreateGraph( is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
   1836                                                           sizeof(CvGraph), elem_size[0], elem_size[1],
   1837                                                           storage );
   1838             }
   1839 
   1840             if( test_graph_ops( iterations*10 ) < 0 )
   1841                 return;
   1842 
   1843             storage.release();
   1844         }
   1845     }
   1846     catch(int)
   1847     {
   1848     }
   1849 }
   1850 
   1851 
   1852 //////////// graph scan test //////////////
   1853 
   1854 class Core_GraphScanTest : public Core_DynStructBaseTest
   1855 {
   1856 public:
   1857     Core_GraphScanTest();
   1858     void run( int );
   1859 
   1860 protected:
   1861     //int test_seq_block_consistence( int struct_idx );
   1862     int create_random_graph( int );
   1863 };
   1864 
   1865 
   1866 Core_GraphScanTest::Core_GraphScanTest()
   1867 {
   1868     iterations = 100;
   1869     struct_count = 1;
   1870 }
   1871 
   1872 
   1873 int Core_GraphScanTest::create_random_graph( int _struct_idx )
   1874 {
   1875     RNG& rng = ts->get_rng();
   1876     int is_oriented = cvtest::randInt(rng) % 2;
   1877     int i, vtx_count = cvtest::randInt(rng) % max_struct_size;
   1878     int edge_count = cvtest::randInt(rng) % MAX(vtx_count*20, 1);
   1879     CvGraph* graph;
   1880 
   1881     struct_idx = _struct_idx;
   1882     cxcore_struct[_struct_idx] = graph =
   1883         cvCreateGraph(is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
   1884                       sizeof(CvGraph), sizeof(CvGraphVtx),
   1885                       sizeof(CvGraphEdge), storage );
   1886 
   1887     for( i = 0; i < vtx_count; i++ )
   1888          cvGraphAddVtx( graph );
   1889 
   1890     assert( graph->active_count == vtx_count );
   1891 
   1892     for( i = 0; i < edge_count; i++ )
   1893     {
   1894         int j = cvtest::randInt(rng) % vtx_count;
   1895         int k = cvtest::randInt(rng) % vtx_count;
   1896 
   1897         if( j != k )
   1898              cvGraphAddEdge( graph, j, k );
   1899     }
   1900 
   1901     assert( graph->active_count == vtx_count && graph->edges->active_count <= edge_count );
   1902 
   1903     return 0;
   1904 }
   1905 
   1906 
   1907 void Core_GraphScanTest::run( int )
   1908 {
   1909     CvGraphScanner* scanner = 0;
   1910     try
   1911     {
   1912         RNG& rng = ts->get_rng();
   1913         vector<uchar> vtx_mask, edge_mask;
   1914         double t;
   1915         int i;
   1916 
   1917         clear();
   1918         test_progress = -1;
   1919 
   1920         cxcore_struct.resize(struct_count, 0);
   1921 
   1922         for( gen = 0; gen < generations; gen++ )
   1923         {
   1924             struct_idx = iter = -1;
   1925             t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
   1926             int storage_blocksize = cvRound( exp(t * CV_LOG2) );
   1927             storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
   1928             storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphEdge) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
   1929             storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphVtx) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
   1930             storage.reset(cvCreateMemStorage(storage_blocksize));
   1931 
   1932             if( gen == 0 )
   1933             {
   1934                 // special regression test for one sample graph.
   1935                 // !!! ATTENTION !!! The test relies on the particular order of the inserted edges
   1936                 // (LIFO: the edge inserted last goes first in the list of incident edges).
   1937                 // if it is changed, the test will have to be modified.
   1938 
   1939                 int vtx_count = -1, edge_count = 0, edges[][3] =
   1940                 {
   1941                     {0,4,'f'}, {0,1,'t'}, {1,4,'t'}, {1,2,'t'}, {2,3,'t'}, {4,3,'c'}, {3,1,'b'},
   1942                     {5,7,'t'}, {7,5,'b'}, {5,6,'t'}, {6,0,'c'}, {7,6,'c'}, {6,4,'c'}, {-1,-1,0}
   1943                 };
   1944 
   1945                 CvGraph* graph = cvCreateGraph( CV_ORIENTED_GRAPH, sizeof(CvGraph),
   1946                                                sizeof(CvGraphVtx), sizeof(CvGraphEdge), storage );
   1947 
   1948                 for( i = 0; edges[i][0] >= 0; i++ )
   1949                 {
   1950                     vtx_count = MAX( vtx_count, edges[i][0] );
   1951                     vtx_count = MAX( vtx_count, edges[i][1] );
   1952                 }
   1953                 vtx_count++;
   1954 
   1955                 for( i = 0; i < vtx_count; i++ )
   1956                      cvGraphAddVtx( graph );
   1957 
   1958                 for( i = 0; edges[i][0] >= 0; i++ )
   1959                 {
   1960                     CvGraphEdge* edge;
   1961                      cvGraphAddEdge( graph, edges[i][0], edges[i][1], 0, &edge );
   1962                     edge->weight = (float)edges[i][2];
   1963                 }
   1964 
   1965                 edge_count = i;
   1966                 scanner = cvCreateGraphScanner( graph, 0, CV_GRAPH_ALL_ITEMS );
   1967 
   1968                 for(;;)
   1969                 {
   1970                     int code, a = -1, b = -1;
   1971                     const char* event = "";
   1972                      code = cvNextGraphItem( scanner );
   1973 
   1974                     switch( code )
   1975                     {
   1976                         case CV_GRAPH_VERTEX:
   1977                             event = "Vertex";
   1978                             vtx_count--;
   1979                             a = cvGraphVtxIdx( graph, scanner->vtx );
   1980                             break;
   1981                         case CV_GRAPH_TREE_EDGE:
   1982                             event = "Tree Edge";
   1983                             edge_count--;
   1984                             CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'t',
   1985                                                       "Invalid edge type" );
   1986                             a = cvGraphVtxIdx( graph, scanner->vtx );
   1987                             b = cvGraphVtxIdx( graph, scanner->dst );
   1988                             break;
   1989                         case CV_GRAPH_BACK_EDGE:
   1990                             event = "Back Edge";
   1991                             edge_count--;
   1992                             CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'b',
   1993                                                       "Invalid edge type" );
   1994                             a = cvGraphVtxIdx( graph, scanner->vtx );
   1995                             b = cvGraphVtxIdx( graph, scanner->dst );
   1996                             break;
   1997                         case CV_GRAPH_CROSS_EDGE:
   1998                             event = "Cross Edge";
   1999                             edge_count--;
   2000                             CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'c',
   2001                                                       "Invalid edge type" );
   2002                             a = cvGraphVtxIdx( graph, scanner->vtx );
   2003                             b = cvGraphVtxIdx( graph, scanner->dst );
   2004                             break;
   2005                         case CV_GRAPH_FORWARD_EDGE:
   2006                             event = "Forward Edge";
   2007                             edge_count--;
   2008                             CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'f',
   2009                                                       "Invalid edge type" );
   2010                             a = cvGraphVtxIdx( graph, scanner->vtx );
   2011                             b = cvGraphVtxIdx( graph, scanner->dst );
   2012                             break;
   2013                         case CV_GRAPH_BACKTRACKING:
   2014                             event = "Backtracking";
   2015                             a = cvGraphVtxIdx( graph, scanner->vtx );
   2016                             break;
   2017                         case CV_GRAPH_NEW_TREE:
   2018                             event = "New search tree";
   2019                             break;
   2020                         case CV_GRAPH_OVER:
   2021                             event = "End of procedure";
   2022                             break;
   2023                         default:
   2024                             CV_TS_SEQ_CHECK_CONDITION( 0, "Invalid code appeared during graph scan" );
   2025                     }
   2026 
   2027                     ts->printf( cvtest::TS::LOG, "%s", event );
   2028                     if( a >= 0 )
   2029                     {
   2030                         if( b >= 0 )
   2031                             ts->printf( cvtest::TS::LOG, ": (%d,%d)", a, b );
   2032                         else
   2033                             ts->printf( cvtest::TS::LOG, ": %d", a );
   2034                     }
   2035 
   2036                     ts->printf( cvtest::TS::LOG, "\n" );
   2037 
   2038                     if( code < 0 )
   2039                         break;
   2040                 }
   2041 
   2042                 CV_TS_SEQ_CHECK_CONDITION( vtx_count == 0 && edge_count == 0,
   2043                                           "Not every vertex/edge has been visited" );
   2044                 update_progressbar();
   2045             }
   2046 
   2047             // for a random graph the test just checks that every graph vertex and
   2048             // every edge is vitisted during the scan
   2049             for( iter = 0; iter < iterations; iter++ )
   2050             {
   2051                 create_random_graph(0);
   2052                 CvGraph* graph = (CvGraph*)cxcore_struct[0];
   2053 
   2054                 // iterate twice to check that scanner doesn't damage the graph
   2055                 for( i = 0; i < 2; i++ )
   2056                 {
   2057                     CvGraphVtx* start_vtx = cvtest::randInt(rng) % 2 || graph->active_count == 0 ? 0 :
   2058                     cvGetGraphVtx( graph, cvtest::randInt(rng) % graph->active_count );
   2059 
   2060                     scanner = cvCreateGraphScanner( graph, start_vtx, CV_GRAPH_ALL_ITEMS );
   2061 
   2062                     vtx_mask.resize(0);
   2063                     vtx_mask.resize(graph->active_count, 0);
   2064                     edge_mask.resize(0);
   2065                     edge_mask.resize(graph->edges->active_count, 0);
   2066 
   2067                     for(;;)
   2068                     {
   2069                         int code = cvNextGraphItem( scanner );
   2070 
   2071                         if( code == CV_GRAPH_OVER )
   2072                             break;
   2073                         else if( code & CV_GRAPH_ANY_EDGE )
   2074                         {
   2075                             int edge_idx = scanner->edge->flags & CV_SET_ELEM_IDX_MASK;
   2076 
   2077                             CV_TS_SEQ_CHECK_CONDITION( edge_idx < graph->edges->active_count &&
   2078                                                       edge_mask[edge_idx] == 0,
   2079                                                       "The edge is not found or visited for the second time" );
   2080                             edge_mask[edge_idx] = 1;
   2081                         }
   2082                         else if( code & CV_GRAPH_VERTEX )
   2083                         {
   2084                             int vtx_idx = scanner->vtx->flags & CV_SET_ELEM_IDX_MASK;
   2085 
   2086                             CV_TS_SEQ_CHECK_CONDITION( vtx_idx < graph->active_count &&
   2087                                                       vtx_mask[vtx_idx] == 0,
   2088                                                       "The vtx is not found or visited for the second time" );
   2089                             vtx_mask[vtx_idx] = 1;
   2090                         }
   2091                     }
   2092 
   2093                     cvReleaseGraphScanner( &scanner );
   2094 
   2095                     CV_TS_SEQ_CHECK_CONDITION( cvtest::norm(Mat(vtx_mask),CV_L1) == graph->active_count &&
   2096                                               cvtest::norm(Mat(edge_mask),CV_L1) == graph->edges->active_count,
   2097                                               "Some vertices or edges have not been visited" );
   2098                     update_progressbar();
   2099                 }
   2100                 cvClearMemStorage( storage );
   2101             }
   2102 
   2103             storage.release();
   2104         }
   2105     }
   2106     catch(int)
   2107     {
   2108     }
   2109 
   2110     cvReleaseGraphScanner( &scanner );
   2111 }
   2112 
   2113 
   2114 TEST(Core_DS_Seq, basic_operations) { Core_SeqBaseTest test; test.safe_run(); }
   2115 TEST(Core_DS_Seq, sort_invert) { Core_SeqSortInvTest test; test.safe_run(); }
   2116 TEST(Core_DS_Set, basic_operations) { Core_SetTest test; test.safe_run(); }
   2117 TEST(Core_DS_Graph, basic_operations) { Core_GraphTest test; test.safe_run(); }
   2118 TEST(Core_DS_Graph, scan) { Core_GraphScanTest test; test.safe_run(); }
   2119